diff --git a/.browserslistrc b/.browserslistrc
deleted file mode 100644
index 755f8b8..0000000
--- a/.browserslistrc
+++ /dev/null
@@ -1 +0,0 @@
-IE 10
diff --git a/.claude/tasks/context_session_a9973aa3-2e87-420a-9c57-c48fd5f3a2d4.md b/.claude/tasks/context_session_a9973aa3-2e87-420a-9c57-c48fd5f3a2d4.md
new file mode 100644
index 0000000..f7bad6a
--- /dev/null
+++ b/.claude/tasks/context_session_a9973aa3-2e87-420a-9c57-c48fd5f3a2d4.md
@@ -0,0 +1,45 @@
+# Session Context: TypeScript Rewrite Plan
+
+## Session ID
+a9973aa3-2e87-420a-9c57-c48fd5f3a2d4
+
+## Goal
+Create a comprehensive implementation plan to rewrite the ABSmartly JavaScript SDK in TypeScript from scratch.
+
+## What Was Done
+1. Created git worktree `worktree-typescript-rewrite` based on `main`
+2. Thoroughly explored the entire codebase (43 source files, 34 test files, all config)
+3. Read every source file, understanding all types, APIs, and algorithms
+4. Read all 20 JsonExpr operators
+5. Read all 14 test files to understand test patterns and fixture data
+6. Wrote comprehensive 17-task implementation plan
+
+## Plan Location
+`docs/superpowers/plans/2026-03-28-typescript-rewrite.md`
+
+## Key Decisions
+- **Drop legacy support**: Node 18+ / modern browsers only (was Node 6+ / IE 10+)
+- **Drop dependencies**: node-fetch, rfdc, core-js (use native fetch, structuredClone)
+- **Drop polyfills**: fetch-shim, abort-controller-shim, platform detection wrappers
+- **Drop Babel**: Use tsup (esbuild-based) for bundling ESM + CJS + browser IIFE
+- **Test framework**: Vitest instead of Jest
+- **Keep identical**: Public API, hashing algorithms, variant assignment, client retry logic
+
+## Task Breakdown (17 tasks)
+1. Project scaffolding & build system (package.json, tsconfig, tsup, vitest)
+2. Types & errors
+3. Murmur3 hash
+4. MD5 hash
+5. Hashing utilities
+6. Core utilities (isObject, isEqualsDeep, etc.)
+7. Variant assigner
+8. JsonExpr evaluator
+9. JsonExpr operators (all 20 in one file)
+10. JsonExpr facade & AudienceMatcher
+11. HTTP client with retry
+12. Provider & publisher
+13. Context class (largest module)
+14. SDK class
+15. Config merge utility
+16. Public API & index exports
+17. Full integration & cleanup
diff --git a/.editorconfig b/.editorconfig
deleted file mode 100644
index ffd3563..0000000
--- a/.editorconfig
+++ /dev/null
@@ -1,10 +0,0 @@
-root = true
-
-[*.{json,js,sh}]
-end_of_line = lf
-insert_final_newline = true
-indent_style = tab
-indent_size = 4
-trim_trailing_whitespace = true
-charset = utf-8
-
diff --git a/.eslintignore b/.eslintignore
deleted file mode 100644
index 12289b4..0000000
--- a/.eslintignore
+++ /dev/null
@@ -1,2 +0,0 @@
-/dist/
-/src/js/
diff --git a/.eslintrc.js b/.eslintrc.js
deleted file mode 100644
index f5c917c..0000000
--- a/.eslintrc.js
+++ /dev/null
@@ -1,58 +0,0 @@
-module.exports = {
- root: true,
- parser: "@typescript-eslint/parser",
- plugins: ["@typescript-eslint"],
- env: {
- browser: true,
- node: true,
- es6: true,
- jest: true,
- },
- extends: [
- "eslint:recommended",
- "prettier",
- "plugin:@typescript-eslint/eslint-recommended",
- "plugin:@typescript-eslint/recommended",
- ],
- rules: {
- "@typescript-eslint/no-empty-function": "off",
- "no-debugger": process.env.NODE_ENV === "production" ? "error" : "off",
- "no-template-curly-in-string": "error",
- "no-promise-executor-return": "error",
- "no-useless-backreference": "error",
- // "require-atomic-updates": "error",
- "array-callback-return": "error",
- "block-scoped-var": "error",
- "class-methods-use-this": "off",
- "consistent-return": "error",
- "default-case": ["error", { commentPattern: "^skip|no\\s+default" }],
- "default-param-last": "error",
- "dot-location": ["error", "property"],
- eqeqeq: ["error", "smart"],
- "no-alert": "error",
- "no-constructor-return": "error",
- "no-else-return": "error",
- "no-extend-native": "error",
- "no-extra-label": "error",
- "no-invalid-this": "error",
- "no-loop-func": "error",
- "no-return-assign": "error",
- "no-return-await": "error",
- "no-self-compare": "error",
- "no-sequences": "error",
- "no-throw-literal": "error",
- "no-useless-concat": "error",
- "no-useless-return": "error",
- "no-void": "error",
- "wrap-iife": ["error", "inside"],
- "no-shadow": ["error", { builtinGlobals: true, hoist: "never" }],
- "no-use-before-define": "off",
- "no-var": "error",
- "prefer-numeric-literals": "error",
- "prefer-const": "warn",
- "prefer-arrow-callback": "error",
- "prefer-rest-params": "error",
- "prefer-spread": "error",
- "prefer-template": "error",
- },
-};
diff --git a/.prettierignore b/.prettierignore
deleted file mode 100644
index 785efb8..0000000
--- a/.prettierignore
+++ /dev/null
@@ -1,5 +0,0 @@
-node_modules
-coverage
-dist
-es
-lib
diff --git a/.prettierrc.json b/.prettierrc.json
deleted file mode 100644
index 627187b..0000000
--- a/.prettierrc.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "printWidth": 120,
- "useTabs": true,
- "semi": true,
- "singleQuote": false,
- "jsxSingleQuote": false
-}
diff --git a/README.md b/README.md
index be4a960..faad2de 100644
--- a/README.md
+++ b/README.md
@@ -1,17 +1,64 @@
# A/B Smartly SDK [](https://badge.fury.io/js/%40absmartly%2Fjavascript-sdk)
-A/B Smartly - JavaScript SDK
+A/B Smartly - JavaScript/TypeScript SDK
## Compatibility
-The A/B Smartly Javascript SDK is an isomorphic library for Node.js (CommonJS and ES6) and browsers (UMD).
+The A/B Smartly JavaScript SDK is an isomorphic TypeScript library for Node.js (ESM and CommonJS) and browsers (IIFE).
-It's supported on Node.js version 6.x and npm 3.x or later.
+### Modern (default, zero dependencies)
+- **Node.js 18+** - uses native `fetch` and `AbortController`
+- **All modern browsers** - Chrome, Firefox, Safari, Edge
-It's supported on IE 10+ and all the other major browsers.
+### Legacy Node.js (14-17)
+Supported via optional polyfill injection. No extra dependencies are bundled - you provide your own:
-**Note**: IE 10 does not natively support Promises.
-If you target IE 10, you must include a polyfill like [es6-promise](https://www.npmjs.com/package/es6-promise) or [rsvp](https://www.npmjs.com/package/rsvp).
+```typescript
+import fetch from "node-fetch";
+import { AbortController } from "abort-controller";
+
+const sdk = new SDK({
+ endpoint: "https://sandbox.absmartly.io/v1",
+ apiKey: process.env.ABSMARTLY_API_KEY,
+ environment: "production",
+ application: "website",
+ fetchImpl: fetch,
+ AbortControllerImpl: AbortController,
+});
+```
+
+### Legacy Browsers
+A pre-built legacy bundle transpiled to ES2015 is available at `dist/index.legacy.js`.
+
+**Important:** This is an ES2015 build, not an ES5 build. It does **not** support IE10/IE11.
+
+If you need legacy browser support, you must provide polyfills for missing APIs:
+
+| API | Polyfill |
+|---|---|
+| `Promise` | [es6-promise](https://www.npmjs.com/package/es6-promise) |
+| `fetch` | [whatwg-fetch](https://www.npmjs.com/package/whatwg-fetch) |
+| `AbortController` | [abortcontroller-polyfill](https://www.npmjs.com/package/abortcontroller-polyfill) |
+
+```html
+
+
+
+
+
+
+
+```
+
+### Build Outputs
+
+| File | Target | Use case |
+|---|---|---|
+| `dist/index.js` | ES2022 ESM | Modern bundlers (Vite, webpack, Rollup) |
+| `dist/index.cjs` | ES2022 CJS | Node.js `require()` |
+| `dist/index.global.js` | ES2022 IIFE | Modern browsers via `
+
+```
-Simply add the following code to your `head` section to include the latest published version.
+#### Directly in the browser (legacy / ES2015-capable browsers)
```html
-
+
+
+
```
## Getting Started
@@ -43,10 +99,9 @@ Please follow the [installation](#installation) instructions before trying the f
#### Initialization
This example assumes an Api Key, an Application, and an Environment have been created in the A/B Smartly web console.
-```javascript
-// somewhere in your application initialization code
-const sdk = new absmartly.SDK({
- endpoint: 'https://sandbox.absmartly.io/v1',
+```typescript
+const sdk = new SDK({
+ endpoint: "https://sandbox.absmartly.io/v1",
apiKey: process.env.ABSMARTLY_API_KEY,
environment: process.env.NODE_ENV,
application: process.env.APPLICATION_NAME,
@@ -54,54 +109,69 @@ const sdk = new absmartly.SDK({
```
The `application` option can also be an object with `name` and `version` to track which version of your application is generating events. The version can be a number or a semver string:
-```javascript
-const sdk = new absmartly.SDK({
- endpoint: 'https://sandbox.absmartly.io/v1',
+```typescript
+const sdk = new SDK({
+ endpoint: "https://sandbox.absmartly.io/v1",
apiKey: process.env.ABSMARTLY_API_KEY,
environment: process.env.NODE_ENV,
- application: { name: 'website', version: '1.2.3' },
+ application: { name: "website", version: "1.2.3" },
});
```
-#### Creating a new Context with raw promises
-```javascript
-// define a new context request
-const request = {
+#### SDK Options
+
+| Option | Type | Required | Description |
+|---|---|---|---|
+| `endpoint` | `string` | Yes | A/B Smartly API endpoint |
+| `apiKey` | `string` | Yes | API key from the web console |
+| `environment` | `string` | Yes | Environment name (e.g. `"production"`) |
+| `application` | `string \| { name, version }` | Yes | Application name or object |
+| `agent` | `string` | No | Custom agent identifier |
+| `retries` | `number` | No | Number of retries (default: `5`) |
+| `timeout` | `number` | No | Request timeout in ms (default: `3000`) |
+| `keepalive` | `boolean` | No | Enable keep-alive (default: `true`) |
+| `fetchImpl` | `typeof fetch` | No | Custom fetch implementation for legacy environments |
+| `AbortControllerImpl` | `typeof AbortController` | No | Custom AbortController for legacy environments |
+| `client` | `Client` | No | Custom HTTP client implementing the `Client` interface |
+| `eventLogger` | `EventLogger` | No | Custom event logger callback |
+| `publisher` | `ContextPublisher` | No | Custom context publisher |
+| `provider` | `ContextDataProvider` | No | Custom context data provider |
+
+#### Creating a new Context with promises
+```typescript
+const context = sdk.createContext({
units: {
- session_id: '5ebf06d8cb5d8137290c4abb64155584fbdb64d8',
+ session_id: "5ebf06d8cb5d8137290c4abb64155584fbdb64d8",
},
-};
-
-// create context with raw promises
-const context = sdk.createContext(request);
+});
-context.ready().then((response) => {
- console.log("ABSmartly Context ready!")
-}).catch((error) => {
- console.log(error);
+context.ready().then(() => {
+ if (context.isFailed()) {
+ console.error("Context failed to initialize:", context.readyError());
+ // Context is still usable — all treatments return control (variant 0)
+ }
+ console.log("ABSmartly Context ready!");
});
```
#### Creating a new Context with async/await
-```javascript
-// define a new context request
-const request = {
+```typescript
+const context = sdk.createContext({
units: {
- session_id: '5ebf06d8cb5d8137290c4abb64155584fbdb64d8',
+ session_id: "5ebf06d8cb5d8137290c4abb64155584fbdb64d8",
},
-};
+});
-// create context with raw promises
-const context = sdk.createContext(request);
+await context.ready();
-try {
- await context.ready();
- console.log("ABSmartly Context ready!")
-} catch (error) {
- console.log(error);
+if (context.isFailed()) {
+ console.error("Context failed to initialize:", context.readyError());
+ // Context is still usable — all treatments return control (variant 0)
}
```
+> **Note:** `ready()` always resolves to `true`, even when initialization fails. A failed context is still "ready" — it simply has no experiment data, so all `treatment()` calls return `0` (control). Use `isFailed()` to check if initialization failed and `readyError()` to inspect the error.
+
#### Creating a new Context with pre-fetched data
When doing full-stack experimentation with A/B Smartly, we recommend creating a context only once on the server-side.
Creating a context involves a round-trip to the A/B Smartly event collector.
@@ -109,17 +179,14 @@ We can avoid repeating the round-trip on the client-side by sending the server-s
Then we can initialize the A/B Smartly context on the client-side directly with it.
```html
-
-
-
+
+
+
```
#### Setting extra units for a context
@@ -128,8 +195,8 @@ This method may be used for example, when a user logs in to your application, an
Please note that **you cannot override an already set unit type** as that would be a change of identity, and will throw an exception. In this case, you must create a new context instead.
The `unit()` and `units()` methods can be called before the context is ready.
-```javascript
-context.unit('db_user_id', 1000013);
+```typescript
+context.unit("db_user_id", 1000013);
// or
context.units({
@@ -139,11 +206,11 @@ context.units({
#### Setting context attributes
The `attribute()` and `attributes()` methods can be called before the context is ready.
-```javascript
-context.attribute('user_agent', navigator.userAgent);
+```typescript
+context.attribute("user_agent", navigator.userAgent);
context.attributes({
- customer_age: 'new_customer',
+ customer_age: "new_customer",
});
```
@@ -151,7 +218,7 @@ context.attributes({
You can opt in to automatically include system attributes (SDK name, SDK version, application, environment, and application version) in every publish payload. These are sent as context attributes and can be useful for debugging and filtering in the Web Console.
To enable this, set the `includeSystemAttributes` option to `true` when creating the context:
-```javascript
+```typescript
const context = sdk.createContext(request, {
includeSystemAttributes: true,
});
@@ -160,9 +227,9 @@ const context = sdk.createContext(request, {
When enabled, the following attributes are automatically prepended to the publish request payload:
| Attribute | Description |
-|:--- |---|
+|:---|---|
| `sdk_name` | The SDK agent name (e.g. `"absmartly-javascript-sdk"`) |
-| `sdk_version` | The SDK version (e.g. `"1.13.4"`) |
+| `sdk_version` | The SDK version (e.g. `"2.0.0"`) |
| `application` | The application name from the SDK configuration |
| `environment` | The environment from the SDK configuration |
| `app_version` | The application version, only included if greater than `0` |
@@ -170,17 +237,29 @@ When enabled, the following attributes are automatically prepended to the publis
These system attributes are prepended before any user-defined attributes.
#### Selecting a treatment
-```javascript
-if (context.treament("exp_test_experiment") == 0) {
+```typescript
+if (context.treatment("exp_test_experiment") === 0) {
// user is in control group (variant 0)
} else {
// user is in treatment group
}
```
+#### Accessing experiment variables
+Experiment variables allow you to configure per-variant values directly from the A/B Smartly web console.
+
+```typescript
+const buttonColor = context.variableValue("button.color", "grey"); // "grey" is the default
+```
+
+Use `peekVariableValue()` to access a variable without triggering an exposure:
+```typescript
+const buttonColor = context.peekVariableValue("button.color", "grey");
+```
+
#### Tracking a goal achievement
Goals are created in the A/B Smartly web console.
-```javascript
+```typescript
context.track("payment", { item_count: 1, total_amount: 1999.99 });
```
@@ -188,44 +267,37 @@ context.track("payment", { item_count: 1, total_amount: 1999.99 });
Sometimes it is necessary to ensure all events have been published to the A/B Smartly collector, before proceeding.
One such case is when the user is about to navigate away right before being exposed to a treatment.
You can explicitly call the `publish()` method, which returns a promise, before navigating away.
-```javascript
-await context.publish().then(() => {
- window.location = "https://www.absmartly.com"
-})
+```typescript
+await context.publish();
+window.location = "https://www.absmartly.com";
```
#### Finalizing
The `finalize()` method will ensure all events have been published to the A/B Smartly collector, like `publish()`, and will also "seal" the context, throwing an error if any method that could generate an event is called.
-```javascript
-await context.finalize().then(() => {
- window.location = "https://www.absmartly.com"
-})
+```typescript
+await context.finalize();
+window.location = "https://www.absmartly.com";
```
#### Refreshing the context with fresh experiment data
For long-running single-page-applications (SPA), the context is usually created once when the application is first reached.
However, any experiments being tracked in your production code, but started after the context was created, will not be triggered.
-To mitigate this, we can use the `refreshInterval` option when creating the context.
+To mitigate this, we can use the `refreshPeriod` option when creating the context.
-```javascript
-const request = {
- units: {
- session_id: '5ebf06d8cb5d8137290c4abb64155584fbdb64d8',
- },
-};
-
-const context = sdk.createContext(request, {
- refreshInterval: 5 * 60 * 1000
-});
+```typescript
+const context = sdk.createContext(
+ { units: { session_id: "5ebf06d8cb5d8137290c4abb64155584fbdb64d8" } },
+ { refreshPeriod: 5 * 60 * 1000 },
+);
```
Alternatively, the `refresh()` method can be called manually.
The `refresh()` method pulls updated experiment data from the A/B Smartly collector and will trigger recently started experiments when `treatment()` is called again.
-```javascript
+```typescript
setTimeout(async () => {
try {
- context.refresh();
- } catch(error) {
+ await context.refresh();
+ } catch (error) {
console.error(error);
}
}, 5 * 60 * 1000);
@@ -235,14 +307,14 @@ setTimeout(async () => {
The A/B Smartly SDK can be instantiated with an event logger used for all contexts.
In addition, an event logger can be specified when creating a particular context, in the `createContext` call options.
The example below illustrates this with the implementation of the default event logger, used if none is specified.
-```javascript
-const sdk = new absmartly.SDK({
- endpoint: 'https://sandbox-api.absmartly.com/v1',
+```typescript
+const sdk = new SDK({
+ endpoint: "https://sandbox-api.absmartly.com/v1",
apiKey: process.env.ABSMARTLY_API_KEY,
environment: process.env.NODE_ENV,
application: process.env.APPLICATION_NAME,
eventLogger: (context, eventName, data) => {
- if (eventName == "error") {
+ if (eventName === "error") {
console.error(data);
}
},
@@ -253,7 +325,7 @@ The data parameter depends on the type of event.
Currently, the SDK logs the following events:
| eventName | when | data |
-|:---: |---|---|
+|:---:|---|---|
| `"error"` | `Context` receives an error | error object thrown |
| `"ready"` | `Context` turns ready | data used to initialize the context |
| `"refresh"` | `Context.refresh()` method succeeds | data used to refresh the context |
@@ -262,13 +334,14 @@ Currently, the SDK logs the following events:
| `"goal"` | `Context.track()` method succeeds | goal data enqueued for publishing |
| `"finalize"` | `Context.finalize()` method succeeds the first time | undefined |
+> **Note:** The event logger is wrapped in a try/catch by the SDK. A broken logger will not crash SDK operations.
#### Peek at treatment variants
Although generally not recommended, it is sometimes necessary to peek at a treatment without triggering an exposure.
The A/B Smartly SDK provides a `peek()` method for that.
-```javascript
-if (context.peek("exp_test_experiment") == 0) {
+```typescript
+if (context.peek("exp_test_experiment") === 0) {
// user is in control group (variant 0)
} else {
// user is in treatment group
@@ -278,38 +351,89 @@ if (context.peek("exp_test_experiment") == 0) {
#### Overriding treatment variants
During development, for example, it is useful to force a treatment for an experiment. This can be achieved with the `override()` and/or `overrides()` methods.
The `override()` and `overrides()` methods can be called before the context is ready.
-```javascript
- context.override("exp_test_experiment", 1); // force variant 1 of treatment
- context.overrides({
- exp_test_experiment: 1,
- exp_another_experiment: 0,
- });
+```typescript
+context.override("exp_test_experiment", 1); // force variant 1 of treatment
+context.overrides({
+ exp_test_experiment: 1,
+ exp_another_experiment: 0,
+});
+```
+
+#### Custom fields
+Experiments can have custom field values configured in the A/B Smartly web console.
+```typescript
+const keys = context.customFieldKeys();
+const value = context.customFieldValue("exp_test_experiment", "country");
+const type = context.customFieldValueType("exp_test_experiment", "country");
+```
+
+#### Error handling
+The SDK provides typed error classes for programmatic error handling:
+
+```typescript
+import {
+ ABSmartlyError,
+ ContextNotReadyError,
+ ContextFinalizedError,
+ TimeoutError,
+ RetryError,
+} from "@absmartly/javascript-sdk";
+
+try {
+ context.treatment("exp_test");
+} catch (error) {
+ if (error instanceof ContextNotReadyError) {
+ // Context not ready yet — await context.ready() first
+ } else if (error instanceof ContextFinalizedError) {
+ // Context has been finalized — create a new one
+ }
+}
+```
+
+#### Custom Client (Dependency Injection)
+You can provide your own HTTP client implementation by implementing the `Client` interface:
+
+```typescript
+import type { Client } from "@absmartly/javascript-sdk";
+
+class MyCustomClient implements Client {
+ async getContext(options?) { /* ... */ }
+ async publish(params, options?) { /* ... */ }
+ getAgent() { return "my-custom-client"; }
+ getApplication() { return { name: "my-app", version: "1.0.0" }; }
+ getEnvironment() { return "production"; }
+}
+
+const sdk = new SDK({
+ client: new MyCustomClient(),
+ // No need for endpoint, apiKey, etc. when providing your own client
+});
```
+Similarly, `ContextDataProvider` and `ContextPublisher` interfaces can be implemented for custom data fetching and publishing strategies.
+
#### HTTP request timeout
It is possible to set a timeout per individual HTTP request, overriding the global timeout set for all request when instantiating the SDK object.
Here is an example of setting a timeout only for the createContext request.
-```javascript
+```typescript
const context = sdk.createContext(request, {
- refreshInterval: 5 * 60 * 1000
+ refreshPeriod: 5 * 60 * 1000,
}, {
- timeout: 1500
+ timeout: 1500,
});
```
#### HTTP Request cancellation
-Sometimes it is useful to cancel an inflight HTTP request, for example, when the user is navigating away. The A/B Smartly SDK also supports a cancellation via an `AbortSignal`. An implementation of AbortController is provided for older platforms, but will use the native implementation where available.
-
-Here is an example of a cancellation scenario.
+Sometimes it is useful to cancel an inflight HTTP request, for example, when the user is navigating away. The A/B Smartly SDK supports cancellation via an `AbortSignal`.
-```javascript
-const controller = new absmartly.AbortController();
+```typescript
+const controller = new AbortController();
const context = sdk.createContext(request, {
- refreshInterval: 5 * 60 * 1000
+ refreshPeriod: 5 * 60 * 1000,
}, {
- signal: controller.signal
+ signal: controller.signal,
});
// abort request if not ready after 1500ms
@@ -320,6 +444,33 @@ await context.ready();
clearTimeout(timeoutId);
```
+## Migration from v1
+
+### Breaking changes
+- **Named exports** instead of default export: `import { SDK } from "@absmartly/javascript-sdk"` instead of `import absmartly from "@absmartly/javascript-sdk"`
+- **Provider/Publisher classes renamed**: `ContextDataProvider` → `DefaultContextDataProvider`, `ContextPublisher` → `DefaultContextPublisher`. The old names are now interfaces.
+- **`Goal` type renamed** to `GoalAchievement` for clarity
+- **Node.js 14+** minimum (was Node.js 6+)
+- **IE10 and IE11 are not supported by the shipped bundles** - `index.legacy.js` is ES2015, not ES5. Supporting IE10/IE11 would require an additional ES5 build plus polyfills.
+- **No bundled polyfills** - `core-js`, `node-fetch`, and `rfdc` are no longer bundled. Legacy environments must provide polyfills explicitly.
+- **Browser bundle renamed** - `dist/absmartly.min.js` is now `dist/index.global.js` (modern) or `dist/index.legacy.js` (ES2015 legacy build)
+
+### New features
+- Full TypeScript support with type declarations
+- Zero runtime dependencies
+- Optional polyfill injection (`fetchImpl`, `AbortControllerImpl`)
+- ESM, CJS, and IIFE builds from a single source
+- Smaller bundle size
+- Interface-based dependency injection (`Client`, `ContextDataProvider`, `ContextPublisher`)
+- Domain error classes (`ABSmartlyError`, `ContextNotReadyError`, `ContextFinalizedError`)
+- `readyError()` method to inspect initialization failures
+- Input validation on all public methods
+
+### Removed exports
+- `AbortController` is no longer exported by the SDK package.
+- Use the platform/global `AbortController` instead.
+- In legacy environments, provide your own polyfill and pass it via `AbortControllerImpl`.
+- `NormalizedClientOptions` is no longer exported (internal type).
## About A/B Smartly
**A/B Smartly** is the leading provider of state-of-the-art, on-premises, full-stack experimentation platforms for engineering and product teams that want to confidently deploy features as fast as they can develop them.
diff --git a/babel.config.js b/babel.config.js
deleted file mode 100644
index 815eb05..0000000
--- a/babel.config.js
+++ /dev/null
@@ -1,100 +0,0 @@
-module.exports = function (api) {
- api.cache.never();
-
- const target = process.env.TARGET || "cjs";
-
- const presets = [];
- const plugins = [
- "@babel/plugin-syntax-dynamic-import",
- "@babel/plugin-syntax-import-meta",
- "@babel/plugin-proposal-class-properties",
- "@babel/plugin-proposal-export-namespace-from",
- "@babel/plugin-proposal-numeric-separator",
- "@babel/plugin-proposal-throw-expressions",
- "@babel/plugin-proposal-export-default-from",
- "@babel/plugin-proposal-logical-assignment-operators",
- "@babel/plugin-proposal-optional-chaining",
- "@babel/plugin-proposal-nullish-coalescing-operator",
- ];
-
- const preset = [
- "@babel/preset-env",
- {
- modules: "commonjs", // transpile modules into common-js syntax by default
- targets: {},
- },
- ];
-
- const runtime = [
- "@babel/plugin-transform-runtime",
- {
- absoluteRuntime: true,
- regenerator: false,
- useESModules: false, // don't output es-modules by default
- corejs: false,
- helpers: true,
- },
- ];
-
- switch (target) {
- case "browser":
- Object.assign(preset[1], {
- targets: {
- ie: "10",
- },
- useBuiltIns: "usage",
- corejs: 3,
- exclude: [
- /es\.array\.(?!(find$)).*/,
- "es.array-buffer.*",
- "es.function.*",
- "es.json.*",
- /es\.math\.(?!(imul$)).*/,
- "es.map.*",
- /es\.object\.(?!(assign$|entries$)).*/,
- "es.promise.*",
- "es.regexp.*",
- "es.reflect.*",
- "es.set.*",
- "es.string.*",
- "es.symbol.*",
- /es\.typed-array\.(?!(from$|of)).*/,
- "es.weak-map.*",
- "web.*",
- ],
- });
- break;
-
- case "cjs":
- Object.assign(preset[1], {
- targets: {
- node: "6",
- },
- useBuiltIns: "usage",
- corejs: 3,
- });
- break;
-
- case "es":
- Object.assign(runtime[1], {
- useESModules: true,
- });
- Object.assign(preset[1], {
- modules: false,
- targets: {
- node: "13.20",
- },
- });
- break;
- default:
- throw new Error(`Unsupported target '${target}'`);
- }
-
- presets.push(preset);
- plugins.push(runtime);
-
- return {
- presets,
- plugins,
- };
-};
diff --git a/docs/superpowers/plans/2026-03-28-typescript-rewrite.md b/docs/superpowers/plans/2026-03-28-typescript-rewrite.md
new file mode 100644
index 0000000..762f759
--- /dev/null
+++ b/docs/superpowers/plans/2026-03-28-typescript-rewrite.md
@@ -0,0 +1,3763 @@
+# ABSmartly JavaScript SDK - TypeScript Rewrite
+
+> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
+
+**Goal:** Rewrite the ABSmartly JavaScript SDK from scratch in strict TypeScript, modernizing the build system and dropping legacy polyfills while maintaining identical public API and hashing behavior.
+
+**Architecture:** Clean TypeScript with strict types throughout. All shared types in a central `types.ts` file. Hashing algorithms (murmur3, md5) ported verbatim to ensure byte-level compatibility. JsonExpr engine uses a clean operator interface. Client uses native `fetch` with retry/backoff. Build outputs ESM, CJS, and browser UMD via tsup.
+
+**Tech Stack:** TypeScript 5.x, Vitest, tsup (esbuild-based bundler), native fetch/AbortController (Node 18+, modern browsers)
+
+---
+
+## Scope & Key Decisions
+
+**Dropping legacy support:**
+- Node.js 6+ / IE 10+ -> Node.js 18+ / modern browsers (last 2 versions)
+- Remove `core-js` polyfills
+- Remove `node-fetch` dependency (native fetch in Node 18+)
+- Remove `fetch-shim.ts` (XMLHttpRequest-based fetch polyfill)
+- Remove `abort-controller-shim.ts` (native AbortController everywhere)
+- Remove `abort.ts` and `fetch.ts` platform-detection wrappers
+- Remove `rfdc` dependency (use `structuredClone`)
+- Remove `browser.ts` (UMD entry point handled by bundler)
+
+**Dropping Babel entirely:**
+- No more babel.config.js, no @babel/* devDependencies
+- TypeScript compiler for type checking, tsup for bundling (ESM + CJS + browser)
+
+**Keeping identical:**
+- Public API surface: `SDK`, `Context`, `ContextDataProvider`, `ContextPublisher`, `mergeConfig`
+- Hashing algorithms: murmur3_32, md5 (byte-level identical output)
+- JsonExpr evaluation engine and all 20 operators
+- Variant assignment algorithm
+- Client retry/backoff logic
+- Context lifecycle (ready, publish, refresh, finalize)
+
+**Test framework:**
+- Vitest instead of Jest (faster, native TypeScript, ESM-first)
+- Same test coverage, modernized with async/await
+
+---
+
+## File Structure
+
+```
+src/
+ types.ts # All shared type definitions
+ errors.ts # Custom error classes (TimeoutError, RetryError, AbortError)
+ algorithm.ts # insertUniqueSorted utility
+ murmur3.ts # Murmur3 32-bit hash
+ md5.ts # MD5 hash
+ hashing.ts # hashUnit, base64UrlNoPadding, stringToUint8Array
+ utils.ts # isObject, isPromise, isEqualsDeep, arrayEqualsShallow, chooseVariant
+ assigner.ts # VariantAssigner
+ jsonexpr/
+ evaluator.ts # Expression evaluation engine with type conversion
+ operators.ts # All 20 operators in one file (they are small)
+ jsonexpr.ts # JsonExpr class wiring operators to evaluator
+ matcher.ts # AudienceMatcher
+ client.ts # HTTP client with retry logic
+ provider.ts # ContextDataProvider
+ publisher.ts # ContextPublisher
+ context.ts # Context class
+ sdk.ts # SDK class
+ config.ts # mergeConfig utility
+ index.ts # Public API exports
+ version.ts # Generated SDK version
+
+src/__tests__/
+ errors.test.ts
+ algorithm.test.ts
+ murmur3.test.ts
+ md5.test.ts
+ hashing.test.ts
+ utils.test.ts
+ assigner.test.ts
+ jsonexpr/
+ evaluator.test.ts
+ operators.test.ts
+ jsonexpr.test.ts
+ matcher.test.ts
+ client.test.ts
+ provider.test.ts
+ publisher.test.ts
+ context.test.ts
+ sdk.test.ts
+ config.test.ts
+
+tsconfig.json
+tsup.config.ts
+vitest.config.ts
+package.json
+scripts/
+ generate-version.ts
+```
+
+**Key structural changes from original:**
+- `types.ts`: Centralized types instead of scattered across files
+- `hashing.ts`: Extracted from `utils.ts` — hashing/encoding utilities are a distinct concern
+- `jsonexpr/operators.ts`: All 20 operators consolidated into one file (each is 5-15 lines)
+- Removed: `fetch.ts`, `fetch-shim.ts`, `abort.ts`, `abort-controller-shim.ts`, `browser.ts`
+
+---
+
+## Task 1: Project Scaffolding & Build System
+
+**Files:**
+- Create: `package.json`
+- Create: `tsconfig.json`
+- Create: `tsup.config.ts`
+- Create: `vitest.config.ts`
+- Create: `scripts/generate-version.ts`
+- Create: `src/version.ts`
+- Create: `.gitignore`
+
+- [ ] **Step 1: Delete all existing source files**
+
+Remove the old codebase to start fresh:
+
+```bash
+rm -rf src/ js/ lib/ es/ dist/ types/ scripts/
+rm -f babel.config.js webpack.config.js jest.config.js .eslintrc.js .prettierrc.json .browserslistrc .editorconfig
+```
+
+- [ ] **Step 2: Write package.json**
+
+```json
+{
+ "name": "@absmartly/javascript-sdk",
+ "version": "2.0.0",
+ "description": "A/B Smartly Javascript SDK",
+ "homepage": "https://github.com/absmartly/javascript-sdk#README.md",
+ "bugs": "https://github.com/absmartly/javascript-sdk/issues",
+ "keywords": [
+ "absmartly",
+ "ab-smartly",
+ "a/b-smartly",
+ "ab-testing",
+ "a/b-testing",
+ "split-testing",
+ "ab",
+ "a/b",
+ "cro"
+ ],
+ "license": "Apache-2.0",
+ "type": "module",
+ "main": "dist/index.cjs",
+ "module": "dist/index.js",
+ "browser": "dist/index.global.js",
+ "types": "dist/index.d.ts",
+ "exports": {
+ ".": {
+ "import": {
+ "types": "./dist/index.d.ts",
+ "default": "./dist/index.js"
+ },
+ "require": {
+ "types": "./dist/index.d.cts",
+ "default": "./dist/index.cjs"
+ }
+ }
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "scripts": {
+ "build": "npm run generate-version && tsup",
+ "test": "vitest run",
+ "test:watch": "vitest",
+ "test:coverage": "vitest run --coverage",
+ "typecheck": "tsc --noEmit",
+ "lint": "tsc --noEmit",
+ "generate-version": "tsx scripts/generate-version.ts",
+ "prepack": "npm run build"
+ },
+ "devDependencies": {
+ "tsup": "^8.0.0",
+ "typescript": "^5.4.0",
+ "vitest": "^3.0.0",
+ "tsx": "^4.0.0",
+ "@vitest/coverage-v8": "^3.0.0"
+ },
+ "publishConfig": {
+ "access": "public"
+ },
+ "files": [
+ "README.md",
+ "LICENSE",
+ "package.json",
+ "dist/"
+ ]
+}
+```
+
+- [ ] **Step 3: Write tsconfig.json**
+
+```json
+{
+ "compilerOptions": {
+ "target": "ES2022",
+ "module": "ESNext",
+ "moduleResolution": "bundler",
+ "lib": ["ES2022", "DOM"],
+ "strict": true,
+ "skipLibCheck": true,
+ "sourceMap": true,
+ "declaration": true,
+ "declarationMap": true,
+ "outDir": "./dist",
+ "rootDir": "./src",
+ "isolatedModules": true,
+ "esModuleInterop": true,
+ "resolveJsonModule": true,
+ "noUncheckedIndexedAccess": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noImplicitReturns": true,
+ "forceConsistentCasingInFileNames": true
+ },
+ "include": ["src/**/*.ts"],
+ "exclude": ["src/**/*.test.ts", "node_modules"]
+}
+```
+
+- [ ] **Step 4: Write tsup.config.ts**
+
+```typescript
+import { defineConfig } from "tsup";
+
+export default defineConfig({
+ entry: ["src/index.ts"],
+ format: ["esm", "cjs", "iife"],
+ globalName: "absmartly",
+ dts: true,
+ sourcemap: true,
+ clean: true,
+ minify: true,
+ target: "es2022",
+ outExtension({ format }) {
+ if (format === "iife") return { js: ".global.js" };
+ return {};
+ },
+});
+```
+
+- [ ] **Step 5: Write vitest.config.ts**
+
+```typescript
+import { defineConfig } from "vitest/config";
+
+export default defineConfig({
+ test: {
+ globals: true,
+ environment: "node",
+ coverage: {
+ provider: "v8",
+ include: ["src/**/*.ts"],
+ exclude: ["src/**/*.test.ts", "src/version.ts"],
+ },
+ },
+});
+```
+
+- [ ] **Step 6: Write scripts/generate-version.ts**
+
+```typescript
+import { readFileSync, writeFileSync } from "node:fs";
+
+const pkg = JSON.parse(readFileSync("package.json", "utf-8"));
+writeFileSync("src/version.ts", `export const SDK_VERSION = "${pkg.version}";\n`);
+```
+
+- [ ] **Step 7: Write src/version.ts**
+
+```typescript
+export const SDK_VERSION = "2.0.0";
+```
+
+- [ ] **Step 8: Write .gitignore**
+
+```
+node_modules/
+dist/
+coverage/
+*.tsbuildinfo
+```
+
+- [ ] **Step 9: Install dependencies**
+
+```bash
+npm ci
+```
+
+- [ ] **Step 10: Verify build system works**
+
+Create a minimal `src/index.ts`:
+
+```typescript
+export const placeholder = true;
+```
+
+Run:
+
+```bash
+npx tsc --noEmit && npx tsup
+```
+
+Expected: Build succeeds, `dist/` contains `index.js`, `index.cjs`, `index.global.js`, `index.d.ts`
+
+- [ ] **Step 11: Verify test system works**
+
+Create `src/__tests__/placeholder.test.ts`:
+
+```typescript
+import { expect, test } from "vitest";
+
+test("placeholder", () => {
+ expect(true).toBe(true);
+});
+```
+
+Run: `npx vitest run`
+
+Expected: 1 test passes
+
+- [ ] **Step 12: Commit**
+
+```bash
+git add -A
+git commit -m "feat: scaffold TypeScript project with tsup, vitest, and modern config"
+```
+
+---
+
+## Task 2: Types & Errors
+
+**Files:**
+- Create: `src/types.ts`
+- Create: `src/errors.ts`
+- Create: `src/__tests__/errors.test.ts`
+
+- [ ] **Step 1: Write the failing tests for errors**
+
+```typescript
+import { describe, expect, test } from "vitest";
+import { AbortError, RetryError, TimeoutError } from "../errors";
+
+describe("TimeoutError", () => {
+ test("has correct name, message, and timeout", () => {
+ const error = new TimeoutError(3000);
+ expect(error).toBeInstanceOf(Error);
+ expect(error).toBeInstanceOf(TimeoutError);
+ expect(error.name).toBe("TimeoutError");
+ expect(error.message).toBe("Timeout exceeded.");
+ expect(error.timeout).toBe(3000);
+ });
+});
+
+describe("RetryError", () => {
+ test("has correct name, message, retries, and exception", () => {
+ const cause = new Error("connection refused");
+ const error = new RetryError(5, cause, "https://example.com/api");
+ expect(error).toBeInstanceOf(Error);
+ expect(error).toBeInstanceOf(RetryError);
+ expect(error.name).toBe("RetryError");
+ expect(error.message).toBe("Retries exhausted. URL: https://example.com/api - Last Error: connection refused");
+ expect(error.retries).toBe(5);
+ expect(error.exception).toBe(cause);
+ });
+});
+
+describe("AbortError", () => {
+ test("has correct name and default message", () => {
+ const error = new AbortError();
+ expect(error).toBeInstanceOf(Error);
+ expect(error).toBeInstanceOf(AbortError);
+ expect(error.name).toBe("AbortError");
+ });
+
+ test("accepts custom message", () => {
+ const error = new AbortError("user cancelled");
+ expect(error.message).toBe("user cancelled");
+ });
+});
+```
+
+- [ ] **Step 2: Run tests to verify they fail**
+
+Run: `npx vitest run src/__tests__/errors.test.ts`
+
+Expected: FAIL - modules not found
+
+- [ ] **Step 3: Write src/types.ts**
+
+```typescript
+export type JSONPrimitive = string | number | boolean | null;
+export type JSONObject = { [key: string]: JSONValue };
+export type JSONArray = JSONValue[];
+export type JSONValue = JSONPrimitive | JSONObject | JSONArray;
+
+export type CustomFieldValueType = "text" | "string" | "number" | "json" | "boolean";
+
+export type CustomFieldValue = {
+ name: string;
+ value: string;
+ type: CustomFieldValueType;
+};
+
+export type ExperimentData = {
+ id: number;
+ name: string;
+ unitType: string | null;
+ iteration: number;
+ fullOnVariant: number;
+ trafficSplit: number[];
+ trafficSeedHi: number;
+ trafficSeedLo: number;
+ audience: string;
+ audienceStrict: boolean;
+ split: number[];
+ seedHi: number;
+ seedLo: number;
+ variants: { config: null | string }[];
+ variables: Record;
+ variant: number;
+ overridden: boolean;
+ assigned: boolean;
+ exposed: boolean;
+ eligible: boolean;
+ fullOn: boolean;
+ custom: boolean;
+ audienceMismatch: boolean;
+ customFieldValues: CustomFieldValue[] | null;
+};
+
+export type Assignment = {
+ id: number;
+ iteration: number;
+ fullOnVariant: number;
+ unitType: string | null;
+ variant: number;
+ overridden: boolean;
+ assigned: boolean;
+ exposed: boolean;
+ eligible: boolean;
+ fullOn: boolean;
+ custom: boolean;
+ audienceMismatch: boolean;
+ trafficSplit?: number[];
+ variables?: Record;
+ attrsSeq?: number;
+};
+
+export type Experiment = {
+ data: ExperimentData;
+ variables: Record[];
+};
+
+export type Unit = {
+ type: string;
+ uid: string | null;
+};
+
+export type Exposure = {
+ id: number;
+ name: string;
+ exposedAt: number;
+ unit: string | null;
+ variant: number;
+ assigned: boolean;
+ eligible: boolean;
+ overridden: boolean;
+ fullOn: boolean;
+ custom: boolean;
+ audienceMismatch: boolean;
+};
+
+export type Attribute = {
+ name: string;
+ value: unknown;
+ setAt: number;
+};
+
+export type Units = Record;
+
+export type Goal = {
+ name: string;
+ properties: Record | null;
+ achievedAt: number;
+};
+
+export type ContextParams = {
+ units: Record;
+};
+
+export type ContextData = {
+ experiments?: ExperimentData[];
+};
+
+export type FetchResponse = {
+ status: number;
+ ok: boolean;
+ text: () => Promise;
+ statusText: string;
+ json: () => Promise;
+};
+
+export type ApplicationObject = { name: string; version: number | string };
+
+export type ClientRequestOptions = {
+ query?: Record;
+ path: string;
+ method?: "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "HEAD" | "OPTIONS";
+ body?: Record;
+ auth?: boolean;
+ signal?: AbortSignal;
+ timeout?: number;
+};
+
+export type ClientOptions = {
+ agent?: string;
+ apiKey: string;
+ application: string | ApplicationObject;
+ endpoint: string;
+ environment: string;
+ retries?: number;
+ timeout?: number;
+ keepalive?: boolean;
+};
+
+export type NormalizedClientOptions = Omit, "application"> & {
+ application: ApplicationObject;
+};
+
+export type PublishParams = {
+ units: Unit[];
+ publishedAt: number;
+ hashed: boolean;
+ sdkVersion: string;
+ attributes?: Attribute[];
+ goals?: Goal[];
+ exposures?: Exposure[];
+};
+
+export type EventName = "error" | "ready" | "refresh" | "publish" | "exposure" | "goal" | "finalize";
+
+export type EventLoggerData = Error | Exposure | Goal | ContextData | PublishParams;
+
+export type EventLogger = (context: unknown, eventName: EventName, data?: EventLoggerData) => void;
+
+export type ContextOptions = {
+ publisher?: { publish: (request: PublishParams, sdk: unknown, context: unknown, requestOptions?: ClientRequestOptions) => Promise };
+ dataProvider?: { getContextData: (sdk: unknown, requestOptions?: Partial) => Promise };
+ eventLogger?: EventLogger;
+ refreshPeriod: number;
+ publishDelay: number;
+ includeSystemAttributes?: boolean;
+};
+
+export type SDKOptions = {
+ client?: unknown;
+ eventLogger?: EventLogger;
+ publisher?: unknown;
+ provider?: unknown;
+};
+```
+
+- [ ] **Step 4: Write src/errors.ts**
+
+```typescript
+export class TimeoutError extends Error {
+ readonly timeout: number;
+ constructor(timeout: number) {
+ super("Timeout exceeded.");
+ this.name = "TimeoutError";
+ this.timeout = timeout;
+ }
+}
+
+export class RetryError extends Error {
+ readonly retries: number;
+ readonly exception: Error;
+ constructor(retries: number, reason: Error, url: string) {
+ super(`Retries exhausted. URL: ${url} - Last Error: ${reason.message}`);
+ this.name = "RetryError";
+ this.retries = retries;
+ this.exception = reason;
+ }
+}
+
+export class AbortError extends Error {
+ constructor(message?: string) {
+ super(message);
+ this.name = "AbortError";
+ }
+}
+```
+
+- [ ] **Step 5: Run tests to verify they pass**
+
+Run: `npx vitest run src/__tests__/errors.test.ts`
+
+Expected: 3 tests pass
+
+- [ ] **Step 6: Verify types compile**
+
+Run: `npx tsc --noEmit`
+
+Expected: No errors
+
+- [ ] **Step 7: Commit**
+
+```bash
+git add src/types.ts src/errors.ts src/__tests__/errors.test.ts
+git commit -m "feat: add shared type definitions and custom error classes"
+```
+
+---
+
+## Task 3: Murmur3 Hash
+
+**Files:**
+- Create: `src/murmur3.ts`
+- Create: `src/__tests__/murmur3.test.ts`
+
+- [ ] **Step 1: Write the failing tests**
+
+```typescript
+import { describe, expect, test } from "vitest";
+import { murmur3_32 } from "../murmur3";
+
+function stringToBuffer(value: string): ArrayBuffer {
+ const n = value.length;
+ const array: number[] = [];
+ let k = 0;
+ for (let i = 0; i < n; ++i) {
+ const c = value.charCodeAt(i);
+ if (c < 0x80) {
+ array[k++] = c;
+ } else if (c < 0x800) {
+ array[k++] = (c >> 6) | 192;
+ array[k++] = (c & 63) | 128;
+ } else {
+ array[k++] = (c >> 12) | 224;
+ array[k++] = ((c >> 6) & 63) | 128;
+ array[k++] = (c & 63) | 128;
+ }
+ }
+ return Uint8Array.from(array).buffer;
+}
+
+describe("murmur3_32", () => {
+ const testCases: [string, number, number][] = [
+ ["", 0x00000000, 0x00000000],
+ [" ", 0x00000000, 0x7ef49b98],
+ ["t", 0x00000000, 0xca87df4d],
+ ["te", 0x00000000, 0xedb8ee1b],
+ ["tes", 0x00000000, 0x0bb90e5a],
+ ["test", 0x00000000, 0xba6bd213],
+ ["testy", 0x00000000, 0x44af8342],
+ ["testy1", 0x00000000, 0x8a1a243a],
+ ["testy12", 0x00000000, 0x845461b9],
+ ["testy123", 0x00000000, 0xee0abfbc],
+ ["special-characters-testing-!@#$%^&*()_+-=[]{}|;':\",./<>?", 0x00000000, 0xe1b16274],
+ ["", 0x00000001, 0x514e28b7],
+ [" ", 0x00000001, 0x4f0f7132],
+ ["t", 0x00000001, 0x5db1831e],
+ ["te", 0x00000001, 0xd248bb2e],
+ ["tes", 0x00000001, 0xd432eb74],
+ ["test", 0x00000001, 0x99c02ae2],
+ ["testy", 0x00000001, 0xc5b2dc1e],
+ ["testy1", 0x00000001, 0x33925ceb],
+ ["testy12", 0x00000001, 0xd92c9f23],
+ ["testy123", 0x00000001, 0x3bc1712d],
+ ["special-characters-testing-!@#$%^&*()_+-=[]{}|;':\",./<>?", 0x00000001, 0x6d1d2105],
+ ];
+
+ for (const [input, seed, expected] of testCases) {
+ test(`murmur3_32("${input}", ${seed}) == 0x${expected.toString(16).padStart(8, "0")}`, () => {
+ expect(murmur3_32(stringToBuffer(input), seed)).toBe(expected);
+ });
+ }
+});
+```
+
+- [ ] **Step 2: Run tests to verify they fail**
+
+Run: `npx vitest run src/__tests__/murmur3.test.ts`
+
+Expected: FAIL - module not found
+
+- [ ] **Step 3: Write src/murmur3.ts**
+
+```typescript
+const C1 = 0xcc9e2d51;
+const C2 = 0x1b873593;
+const C3 = 0xe6546b64;
+
+const imul32 = Math.imul;
+
+function fmix32(h: number): number {
+ h ^= h >>> 16;
+ h = imul32(h, 0x85ebca6b);
+ h ^= h >>> 13;
+ h = imul32(h, 0xc2b2ae35);
+ h ^= h >>> 16;
+ return h >>> 0;
+}
+
+function rotl32(a: number, b: number): number {
+ return (a << b) | (a >>> (32 - b));
+}
+
+function scramble32(block: number): number {
+ return imul32(rotl32(imul32(block, C1), 15), C2);
+}
+
+export function murmur3_32(key: ArrayBufferLike, hash?: number): number {
+ hash = (hash || 0) >>> 0;
+ const dataView = new DataView(key);
+
+ let i: number;
+ const n = dataView.byteLength & ~3;
+ for (i = 0; i < n; i += 4) {
+ const chunk = dataView.getUint32(i, true);
+ hash ^= scramble32(chunk);
+ hash = rotl32(hash, 13);
+ hash = imul32(hash, 5) + C3;
+ }
+
+ let remaining = 0;
+ switch (dataView.byteLength & 3) {
+ case 3:
+ remaining ^= dataView.getUint8(i + 2) << 16;
+ // fallthrough
+ case 2:
+ remaining ^= dataView.getUint8(i + 1) << 8;
+ // fallthrough
+ case 1:
+ remaining ^= dataView.getUint8(i);
+ hash ^= scramble32(remaining);
+ // fallthrough
+ default:
+ break;
+ }
+
+ hash ^= dataView.byteLength;
+ hash = fmix32(hash);
+ return hash >>> 0;
+}
+```
+
+- [ ] **Step 4: Run tests to verify they pass**
+
+Run: `npx vitest run src/__tests__/murmur3.test.ts`
+
+Expected: All 22 tests pass
+
+- [ ] **Step 5: Commit**
+
+```bash
+git add src/murmur3.ts src/__tests__/murmur3.test.ts
+git commit -m "feat: add murmur3_32 hash implementation"
+```
+
+---
+
+## Task 4: MD5 Hash
+
+**Files:**
+- Create: `src/md5.ts`
+- Create: `src/__tests__/md5.test.ts`
+
+- [ ] **Step 1: Write the failing tests**
+
+```typescript
+import { describe, expect, test } from "vitest";
+import { md5 } from "../md5";
+
+function stringToBuffer(value: string): ArrayBuffer {
+ const n = value.length;
+ const array: number[] = [];
+ let k = 0;
+ for (let i = 0; i < n; ++i) {
+ const c = value.charCodeAt(i);
+ if (c < 0x80) {
+ array[k++] = c;
+ } else if (c < 0x800) {
+ array[k++] = (c >> 6) | 192;
+ array[k++] = (c & 63) | 128;
+ } else {
+ array[k++] = (c >> 12) | 224;
+ array[k++] = ((c >> 6) & 63) | 128;
+ array[k++] = (c & 63) | 128;
+ }
+ }
+ return Uint8Array.from(array).buffer;
+}
+
+function toHex(bytes: Uint8Array): string {
+ return Array.from(bytes)
+ .map((b) => b.toString(16).padStart(2, "0"))
+ .join("");
+}
+
+describe("md5", () => {
+ const testCases: [string, string][] = [
+ ["", "d41d8cd98f00b204e9800998ecf8427e"],
+ ["a", "0cc175b9c0f1b6a831c399e269772661"],
+ ["abc", "900150983cd24fb0d6963f7d28e17f72"],
+ ["message digest", "f96b697d7cb7938d525a2f31aaf161d0"],
+ ["abcdefghijklmnopqrstuvwxyz", "c3fcd3d76192e4007dfb496cca67e13b"],
+ ];
+
+ for (const [input, expectedHex] of testCases) {
+ test(`md5("${input}") == ${expectedHex}`, () => {
+ const result = md5(stringToBuffer(input));
+ expect(toHex(result)).toBe(expectedHex);
+ });
+ }
+});
+```
+
+- [ ] **Step 2: Run tests to verify they fail**
+
+Run: `npx vitest run src/__tests__/md5.test.ts`
+
+Expected: FAIL - module not found
+
+- [ ] **Step 3: Write src/md5.ts**
+
+```typescript
+function cmn(q: number, a: number, b: number, x: number, s: number, t: number): number {
+ a = a + q + (x >>> 0) + t;
+ return ((a << s) | (a >>> (32 - s))) + b;
+}
+
+function ff(a: number, b: number, c: number, d: number, x: number, s: number, t: number): number {
+ return cmn((b & c) | (~b & d), a, b, x, s, t);
+}
+
+function gg(a: number, b: number, c: number, d: number, x: number, s: number, t: number): number {
+ return cmn((b & d) | (c & ~d), a, b, x, s, t);
+}
+
+function hh(a: number, b: number, c: number, d: number, x: number, s: number, t: number): number {
+ return cmn(b ^ c ^ d, a, b, x, s, t);
+}
+
+function ii(a: number, b: number, c: number, d: number, x: number, s: number, t: number): number {
+ return cmn(c ^ (b | ~d), a, b, x, s, t);
+}
+
+function md5cycle(x: Uint32Array, k: Uint32Array): void {
+ let a = x[0]!;
+ let b = x[1]!;
+ let c = x[2]!;
+ let d = x[3]!;
+
+ a = ff(a, b, c, d, k[0]!, 7, -680876936);
+ d = ff(d, a, b, c, k[1]!, 12, -389564586);
+ c = ff(c, d, a, b, k[2]!, 17, 606105819);
+ b = ff(b, c, d, a, k[3]!, 22, -1044525330);
+ a = ff(a, b, c, d, k[4]!, 7, -176418897);
+ d = ff(d, a, b, c, k[5]!, 12, 1200080426);
+ c = ff(c, d, a, b, k[6]!, 17, -1473231341);
+ b = ff(b, c, d, a, k[7]!, 22, -45705983);
+ a = ff(a, b, c, d, k[8]!, 7, 1770035416);
+ d = ff(d, a, b, c, k[9]!, 12, -1958414417);
+ c = ff(c, d, a, b, k[10]!, 17, -42063);
+ b = ff(b, c, d, a, k[11]!, 22, -1990404162);
+ a = ff(a, b, c, d, k[12]!, 7, 1804603682);
+ d = ff(d, a, b, c, k[13]!, 12, -40341101);
+ c = ff(c, d, a, b, k[14]!, 17, -1502002290);
+ b = ff(b, c, d, a, k[15]!, 22, 1236535329);
+
+ a = gg(a, b, c, d, k[1]!, 5, -165796510);
+ d = gg(d, a, b, c, k[6]!, 9, -1069501632);
+ c = gg(c, d, a, b, k[11]!, 14, 643717713);
+ b = gg(b, c, d, a, k[0]!, 20, -373897302);
+ a = gg(a, b, c, d, k[5]!, 5, -701558691);
+ d = gg(d, a, b, c, k[10]!, 9, 38016083);
+ c = gg(c, d, a, b, k[15]!, 14, -660478335);
+ b = gg(b, c, d, a, k[4]!, 20, -405537848);
+ a = gg(a, b, c, d, k[9]!, 5, 568446438);
+ d = gg(d, a, b, c, k[14]!, 9, -1019803690);
+ c = gg(c, d, a, b, k[3]!, 14, -187363961);
+ b = gg(b, c, d, a, k[8]!, 20, 1163531501);
+ a = gg(a, b, c, d, k[13]!, 5, -1444681467);
+ d = gg(d, a, b, c, k[2]!, 9, -51403784);
+ c = gg(c, d, a, b, k[7]!, 14, 1735328473);
+ b = gg(b, c, d, a, k[12]!, 20, -1926607734);
+
+ a = hh(a, b, c, d, k[5]!, 4, -378558);
+ d = hh(d, a, b, c, k[8]!, 11, -2022574463);
+ c = hh(c, d, a, b, k[11]!, 16, 1839030562);
+ b = hh(b, c, d, a, k[14]!, 23, -35309556);
+ a = hh(a, b, c, d, k[1]!, 4, -1530992060);
+ d = hh(d, a, b, c, k[4]!, 11, 1272893353);
+ c = hh(c, d, a, b, k[7]!, 16, -155497632);
+ b = hh(b, c, d, a, k[10]!, 23, -1094730640);
+ a = hh(a, b, c, d, k[13]!, 4, 681279174);
+ d = hh(d, a, b, c, k[0]!, 11, -358537222);
+ c = hh(c, d, a, b, k[3]!, 16, -722521979);
+ b = hh(b, c, d, a, k[6]!, 23, 76029189);
+ a = hh(a, b, c, d, k[9]!, 4, -640364487);
+ d = hh(d, a, b, c, k[12]!, 11, -421815835);
+ c = hh(c, d, a, b, k[15]!, 16, 530742520);
+ b = hh(b, c, d, a, k[2]!, 23, -995338651);
+
+ a = ii(a, b, c, d, k[0]!, 6, -198630844);
+ d = ii(d, a, b, c, k[7]!, 10, 1126891415);
+ c = ii(c, d, a, b, k[14]!, 15, -1416354905);
+ b = ii(b, c, d, a, k[5]!, 21, -57434055);
+ a = ii(a, b, c, d, k[12]!, 6, 1700485571);
+ d = ii(d, a, b, c, k[3]!, 10, -1894986606);
+ c = ii(c, d, a, b, k[10]!, 15, -1051523);
+ b = ii(b, c, d, a, k[1]!, 21, -2054922799);
+ a = ii(a, b, c, d, k[8]!, 6, 1873313359);
+ d = ii(d, a, b, c, k[15]!, 10, -30611744);
+ c = ii(c, d, a, b, k[6]!, 15, -1560198380);
+ b = ii(b, c, d, a, k[13]!, 21, 1309151649);
+ a = ii(a, b, c, d, k[4]!, 6, -145523070);
+ d = ii(d, a, b, c, k[11]!, 10, -1120210379);
+ c = ii(c, d, a, b, k[2]!, 15, 718787259);
+ b = ii(b, c, d, a, k[9]!, 21, -343485551);
+
+ x[0] = (a + x[0]!) >>> 0;
+ x[1] = (b + x[1]!) >>> 0;
+ x[2] = (c + x[2]!) >>> 0;
+ x[3] = (d + x[3]!) >>> 0;
+}
+
+export function md5(key: ArrayBufferLike): Uint8Array {
+ const dataView = new DataView(key);
+
+ let i: number;
+ const l = dataView.byteLength;
+ const n = l & ~63;
+ const block = new Uint32Array(16);
+ const state = Uint32Array.of(1732584193, -271733879, -1732584194, 271733878);
+ for (i = 0; i < n; i += 64) {
+ for (let w = 0; w < 16; ++w) {
+ block[w] = dataView.getUint32(i + (w << 2), true);
+ }
+ md5cycle(state, block);
+ }
+
+ let w = 0;
+ const m = l & ~3;
+ for (; i < m; i += 4) {
+ block[w++] = dataView.getUint32(i, true);
+ }
+
+ const p = l & 3;
+ switch (p) {
+ case 3:
+ block[w++] =
+ 0x80000000 | dataView.getUint8(i) | (dataView.getUint8(i + 1) << 8) | (dataView.getUint8(i + 2) << 16);
+ break;
+ case 2:
+ block[w++] = 0x800000 | dataView.getUint8(i) | (dataView.getUint8(i + 1) << 8);
+ break;
+ case 1:
+ block[w++] = 0x8000 | dataView.getUint8(i);
+ break;
+ default:
+ block[w++] = 0x80;
+ break;
+ }
+
+ if (w > 14) {
+ for (; w < 16; ++w) {
+ block[w] = 0;
+ }
+ md5cycle(state, block);
+ w = 0;
+ }
+
+ for (; w < 16; ++w) {
+ block[w] = 0;
+ }
+
+ block[14] = l << 3;
+ md5cycle(state, block);
+ return new Uint8Array(state.buffer);
+}
+```
+
+- [ ] **Step 4: Run tests to verify they pass**
+
+Run: `npx vitest run src/__tests__/md5.test.ts`
+
+Expected: All 5 tests pass
+
+- [ ] **Step 5: Commit**
+
+```bash
+git add src/md5.ts src/__tests__/md5.test.ts
+git commit -m "feat: add MD5 hash implementation"
+```
+
+---
+
+## Task 5: Hashing Utilities
+
+**Files:**
+- Create: `src/hashing.ts`
+- Create: `src/__tests__/hashing.test.ts`
+
+- [ ] **Step 1: Write the failing tests**
+
+```typescript
+import { describe, expect, test } from "vitest";
+import { base64UrlNoPadding, hashUnit, stringToUint8Array } from "../hashing";
+
+describe("stringToUint8Array", () => {
+ test("encodes ASCII", () => {
+ const result = stringToUint8Array("abc");
+ expect(Array.from(result)).toEqual([97, 98, 99]);
+ });
+
+ test("encodes multi-byte characters", () => {
+ const result = stringToUint8Array("\u00e9");
+ expect(Array.from(result)).toEqual([0xc3, 0xa9]);
+ });
+
+ test("encodes empty string", () => {
+ const result = stringToUint8Array("");
+ expect(result.length).toBe(0);
+ });
+});
+
+describe("base64UrlNoPadding", () => {
+ test("encodes empty", () => {
+ expect(base64UrlNoPadding(new Uint8Array([]))).toBe("");
+ });
+
+ test("encodes 1 byte", () => {
+ expect(base64UrlNoPadding(new Uint8Array([0]))).toBe("AA");
+ });
+
+ test("encodes 2 bytes", () => {
+ expect(base64UrlNoPadding(new Uint8Array([0, 0]))).toBe("AAA");
+ });
+
+ test("encodes 3 bytes", () => {
+ expect(base64UrlNoPadding(new Uint8Array([0, 0, 0]))).toBe("AAAA");
+ });
+});
+
+describe("hashUnit", () => {
+ test("hashes string unit", () => {
+ const result = hashUnit("test_unit");
+ expect(typeof result).toBe("string");
+ expect(result.length).toBeGreaterThan(0);
+ });
+
+ test("hashes numeric unit", () => {
+ const result = hashUnit(12345);
+ expect(typeof result).toBe("string");
+ expect(result.length).toBeGreaterThan(0);
+ });
+
+ test("produces consistent results", () => {
+ expect(hashUnit("abc")).toBe(hashUnit("abc"));
+ expect(hashUnit(123)).toBe(hashUnit(123));
+ });
+
+ test("produces different results for different inputs", () => {
+ expect(hashUnit("abc")).not.toBe(hashUnit("def"));
+ });
+});
+```
+
+- [ ] **Step 2: Run tests to verify they fail**
+
+Run: `npx vitest run src/__tests__/hashing.test.ts`
+
+Expected: FAIL - module not found
+
+- [ ] **Step 3: Write src/hashing.ts**
+
+```typescript
+import { md5 } from "./md5";
+
+export function stringToUint8Array(value: string): Uint8Array {
+ const n = value.length;
+ const array: number[] = [];
+ let k = 0;
+ for (let i = 0; i < n; ++i) {
+ const c = value.charCodeAt(i);
+ if (c < 0x80) {
+ array[k++] = c;
+ } else if (c < 0x800) {
+ array[k++] = (c >> 6) | 192;
+ array[k++] = (c & 63) | 128;
+ } else {
+ array[k++] = (c >> 12) | 224;
+ array[k++] = ((c >> 6) & 63) | 128;
+ array[k++] = (c & 63) | 128;
+ }
+ }
+ return Uint8Array.from(array);
+}
+
+const BASE64_URL_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+
+export function base64UrlNoPadding(value: Uint8Array): string {
+ const chars = BASE64_URL_CHARS;
+ const remaining = value.byteLength % 3;
+ const encodeLen = ((value.byteLength / 3) | 0) * 4 + (remaining === 0 ? 0 : remaining === 1 ? 2 : 3);
+ const result = new Array(encodeLen);
+
+ let i: number;
+ let out = 0;
+ const len = value.byteLength - remaining;
+ for (i = 0; i < len; i += 3) {
+ const bytes = (value[i]! << 16) | (value[i + 1]! << 8) | value[i + 2]!;
+ result[out] = chars[(bytes >> 18) & 63]!;
+ result[out + 1] = chars[(bytes >> 12) & 63]!;
+ result[out + 2] = chars[(bytes >> 6) & 63]!;
+ result[out + 3] = chars[bytes & 63]!;
+ out += 4;
+ }
+
+ switch (remaining) {
+ case 2: {
+ const bytes = (value[i]! << 16) | (value[i + 1]! << 8);
+ result[out] = chars[(bytes >> 18) & 63]!;
+ result[out + 1] = chars[(bytes >> 12) & 63]!;
+ result[out + 2] = chars[(bytes >> 6) & 63]!;
+ break;
+ }
+ case 1: {
+ const bytes = value[i]! << 16;
+ result[out] = chars[(bytes >> 18) & 63]!;
+ result[out + 1] = chars[(bytes >> 12) & 63]!;
+ break;
+ }
+ default:
+ break;
+ }
+
+ return result.join("");
+}
+
+export function hashUnit(value: string | number): string {
+ const unit = typeof value === "string" ? value : value.toFixed(0);
+ return base64UrlNoPadding(md5(stringToUint8Array(unit).buffer));
+}
+```
+
+- [ ] **Step 4: Run tests to verify they pass**
+
+Run: `npx vitest run src/__tests__/hashing.test.ts`
+
+Expected: All tests pass
+
+- [ ] **Step 5: Commit**
+
+```bash
+git add src/hashing.ts src/__tests__/hashing.test.ts
+git commit -m "feat: add hashing utilities (stringToUint8Array, base64UrlNoPadding, hashUnit)"
+```
+
+---
+
+## Task 6: Core Utilities
+
+**Files:**
+- Create: `src/utils.ts`
+- Create: `src/algorithm.ts`
+- Create: `src/__tests__/utils.test.ts`
+- Create: `src/__tests__/algorithm.test.ts`
+
+- [ ] **Step 1: Write the failing tests for utils**
+
+```typescript
+import { describe, expect, test } from "vitest";
+import { arrayEqualsShallow, chooseVariant, isEqualsDeep, isObject, isPromise } from "../utils";
+
+describe("isObject", () => {
+ test("returns true for plain objects", () => {
+ expect(isObject({})).toBe(true);
+ expect(isObject({ a: 1 })).toBe(true);
+ });
+
+ test("returns false for non-objects", () => {
+ expect(isObject(null)).toBe(false);
+ expect(isObject(undefined)).toBe(false);
+ expect(isObject(42)).toBe(false);
+ expect(isObject("str")).toBe(false);
+ expect(isObject([])).toBe(false);
+ expect(isObject(new Date())).toBe(false);
+ });
+});
+
+describe("isPromise", () => {
+ test("returns true for promises", () => {
+ expect(isPromise(Promise.resolve())).toBe(true);
+ expect(isPromise({ then: () => {} })).toBe(true);
+ });
+
+ test("returns false for non-promises", () => {
+ expect(isPromise(null)).toBe(false);
+ expect(isPromise(undefined)).toBe(false);
+ expect(isPromise({})).toBe(false);
+ expect(isPromise(42)).toBe(false);
+ });
+});
+
+describe("isEqualsDeep", () => {
+ test("primitives", () => {
+ expect(isEqualsDeep(1, 1)).toBe(true);
+ expect(isEqualsDeep(1, 2)).toBe(false);
+ expect(isEqualsDeep("a", "a")).toBe(true);
+ expect(isEqualsDeep("a", "b")).toBe(false);
+ expect(isEqualsDeep(true, true)).toBe(true);
+ expect(isEqualsDeep(true, false)).toBe(false);
+ });
+
+ test("NaN", () => {
+ expect(isEqualsDeep(NaN, NaN)).toBe(true);
+ });
+
+ test("arrays", () => {
+ expect(isEqualsDeep([1, 2, 3], [1, 2, 3])).toBe(true);
+ expect(isEqualsDeep([1, 2, 3], [1, 2, 4])).toBe(false);
+ expect(isEqualsDeep([1, 2], [1, 2, 3])).toBe(false);
+ });
+
+ test("objects", () => {
+ expect(isEqualsDeep({ a: 1, b: 2 }, { a: 1, b: 2 })).toBe(true);
+ expect(isEqualsDeep({ a: 1 }, { a: 2 })).toBe(false);
+ expect(isEqualsDeep({ a: 1 }, { a: 1, b: 2 })).toBe(false);
+ });
+
+ test("nested structures", () => {
+ expect(isEqualsDeep({ a: [1, { b: 2 }] }, { a: [1, { b: 2 }] })).toBe(true);
+ expect(isEqualsDeep({ a: [1, { b: 2 }] }, { a: [1, { b: 3 }] })).toBe(false);
+ });
+
+ test("different types", () => {
+ expect(isEqualsDeep(1, "1")).toBe(false);
+ expect(isEqualsDeep([], {})).toBe(false);
+ });
+});
+
+describe("arrayEqualsShallow", () => {
+ test("same reference", () => {
+ const arr = [1, 2, 3];
+ expect(arrayEqualsShallow(arr, arr)).toBe(true);
+ });
+
+ test("equal arrays", () => {
+ expect(arrayEqualsShallow([1, 2, 3], [1, 2, 3])).toBe(true);
+ });
+
+ test("different arrays", () => {
+ expect(arrayEqualsShallow([1, 2, 3], [1, 2, 4])).toBe(false);
+ });
+
+ test("different lengths", () => {
+ expect(arrayEqualsShallow([1, 2], [1, 2, 3])).toBe(false);
+ });
+
+ test("both undefined", () => {
+ expect(arrayEqualsShallow(undefined, undefined)).toBe(true);
+ });
+});
+
+describe("chooseVariant", () => {
+ test("selects correct variant based on probability", () => {
+ expect(chooseVariant([0.5, 0.5], 0.0)).toBe(0);
+ expect(chooseVariant([0.5, 0.5], 0.4)).toBe(0);
+ expect(chooseVariant([0.5, 0.5], 0.5)).toBe(1);
+ expect(chooseVariant([0.5, 0.5], 0.9)).toBe(1);
+ });
+
+ test("three-way split", () => {
+ expect(chooseVariant([0.33, 0.33, 0.34], 0.0)).toBe(0);
+ expect(chooseVariant([0.33, 0.33, 0.34], 0.3)).toBe(0);
+ expect(chooseVariant([0.33, 0.33, 0.34], 0.33)).toBe(1);
+ expect(chooseVariant([0.33, 0.33, 0.34], 0.65)).toBe(1);
+ expect(chooseVariant([0.33, 0.33, 0.34], 0.66)).toBe(2);
+ });
+
+ test("returns last variant for probability >= 1", () => {
+ expect(chooseVariant([0.5, 0.5], 1.0)).toBe(1);
+ });
+});
+```
+
+- [ ] **Step 2: Write the failing tests for algorithm**
+
+```typescript
+import { describe, expect, test } from "vitest";
+import { insertUniqueSorted } from "../algorithm";
+
+describe("insertUniqueSorted", () => {
+ test("inserts into empty array", () => {
+ const arr: number[] = [];
+ insertUniqueSorted(arr, 5, (a, b) => a < b);
+ expect(arr).toEqual([5]);
+ });
+
+ test("inserts in sorted order", () => {
+ const arr = [1, 3, 5];
+ insertUniqueSorted(arr, 2, (a, b) => a < b);
+ expect(arr).toEqual([1, 2, 3, 5]);
+ });
+
+ test("inserts at beginning", () => {
+ const arr = [2, 3, 4];
+ insertUniqueSorted(arr, 1, (a, b) => a < b);
+ expect(arr).toEqual([1, 2, 3, 4]);
+ });
+
+ test("inserts at end", () => {
+ const arr = [1, 2, 3];
+ insertUniqueSorted(arr, 4, (a, b) => a < b);
+ expect(arr).toEqual([1, 2, 3, 4]);
+ });
+
+ test("does not insert duplicate", () => {
+ const arr = [1, 2, 3];
+ insertUniqueSorted(arr, 2, (a, b) => a < b);
+ expect(arr).toEqual([1, 2, 3]);
+ });
+});
+```
+
+- [ ] **Step 3: Run tests to verify they fail**
+
+Run: `npx vitest run src/__tests__/utils.test.ts src/__tests__/algorithm.test.ts`
+
+Expected: FAIL - modules not found
+
+- [ ] **Step 4: Write src/utils.ts**
+
+```typescript
+export function isObject(value: unknown): value is Record {
+ if (!(value instanceof Object)) return false;
+ const proto = Object.getPrototypeOf(value);
+ return proto == null || proto === Object.prototype;
+}
+
+export function isPromise(value: unknown): value is Promise {
+ return value !== null && typeof value === "object" && typeof (value as Promise).then === "function";
+}
+
+function arrayEqualsDeep(a: unknown[], b: unknown[], astack: unknown[] = [], bstack: unknown[] = []): boolean {
+ let len = astack.length;
+ while (len--) {
+ if (astack[len] === a) return bstack[len] === b;
+ }
+
+ astack.push(a);
+ bstack.push(b);
+
+ len = a.length;
+ while (len--) {
+ if (!isEqualsDeep(a[len], b[len], astack, bstack)) return false;
+ }
+
+ bstack.pop();
+ astack.pop();
+
+ return true;
+}
+
+function objectEqualsDeep(
+ a: Record,
+ b: Record,
+ keys: string[],
+ astack?: unknown[],
+ bstack?: unknown[],
+): boolean {
+ let len = astack?.length ?? 0;
+ while (len--) {
+ if (astack && astack[len] === a) return bstack !== undefined && bstack[len] === b;
+ }
+
+ astack = astack ?? [];
+ bstack = bstack ?? [];
+
+ astack.push(a);
+ bstack.push(b);
+
+ len = keys.length;
+ while (len--) {
+ const key = keys[len]!;
+ if (!Object.prototype.hasOwnProperty.call(b, key)) return false;
+ if (!isEqualsDeep(a[key], b[key], astack, bstack)) return false;
+ }
+
+ bstack.pop();
+ astack.pop();
+
+ return true;
+}
+
+export function isEqualsDeep(a: unknown, b: unknown, astack?: unknown[], bstack?: unknown[]): boolean {
+ if (a === b) return true;
+ if (typeof a !== typeof b) return false;
+
+ switch (typeof a) {
+ case "boolean":
+ return a === b;
+ case "number":
+ if (Number.isNaN(a)) return Number.isNaN(b as number);
+ return a === b;
+ case "string":
+ return a === b;
+ case "object": {
+ const arrays = Array.isArray(a);
+ if (arrays && !Array.isArray(b)) return false;
+
+ const objects = isObject(a);
+ if (objects && !isObject(b)) return false;
+
+ if (!arrays && !objects) return false;
+
+ if (arrays && Array.isArray(b)) {
+ if (a.length === b.length) {
+ return arrayEqualsDeep(a, b, astack, bstack);
+ }
+ } else if (a && b) {
+ const keys = Object.keys(a);
+ if (keys.length === Object.keys(b as Record).length) {
+ return objectEqualsDeep(
+ a as Record,
+ b as Record,
+ keys,
+ astack,
+ bstack,
+ );
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ return false;
+}
+
+export function arrayEqualsShallow(a?: unknown[], b?: unknown[]): boolean {
+ return a === b || (a?.length === b?.length && !a?.some((va, vi) => b && va !== b[vi]));
+}
+
+export function chooseVariant(split: number[], prob: number): number {
+ let cumSum = 0.0;
+ for (let i = 0; i < split.length; ++i) {
+ cumSum += split[i]!;
+ if (prob < cumSum) return i;
+ }
+ return split.length - 1;
+}
+```
+
+- [ ] **Step 5: Write src/algorithm.ts**
+
+```typescript
+export function insertUniqueSorted(
+ arr: TData[],
+ value: TData,
+ isSorted: (a: TData, b: TData) => boolean,
+): void {
+ let left = 0;
+ let right = arr.length - 1;
+
+ while (left <= right) {
+ const mid = Math.floor(left + (right - left) / 2);
+ if (isSorted(arr[mid]!, value)) {
+ left = mid + 1;
+ } else if (isSorted(value, arr[mid]!)) {
+ right = mid - 1;
+ } else {
+ return;
+ }
+ }
+
+ arr.splice(left, 0, value);
+}
+```
+
+- [ ] **Step 6: Run tests to verify they pass**
+
+Run: `npx vitest run src/__tests__/utils.test.ts src/__tests__/algorithm.test.ts`
+
+Expected: All tests pass
+
+- [ ] **Step 7: Commit**
+
+```bash
+git add src/utils.ts src/algorithm.ts src/__tests__/utils.test.ts src/__tests__/algorithm.test.ts
+git commit -m "feat: add core utilities (isObject, isEqualsDeep, chooseVariant, insertUniqueSorted)"
+```
+
+---
+
+## Task 7: Variant Assigner
+
+**Files:**
+- Create: `src/assigner.ts`
+- Create: `src/__tests__/assigner.test.ts`
+
+- [ ] **Step 1: Write the failing tests**
+
+```typescript
+import { describe, expect, test } from "vitest";
+import { VariantAssigner } from "../assigner";
+import { hashUnit } from "../hashing";
+
+describe("VariantAssigner", () => {
+ const testCases: Record = {
+ "bleh@absmartly.com": [
+ [[0.5, 0.5], 0x00000000, 0x00000000, 0],
+ [[0.5, 0.5], 0x00000000, 0x00000001, 1],
+ [[0.5, 0.5], 0x8015406f, 0x7ef49b98, 0],
+ [[0.5, 0.5], 0x3b2e7571, 0xca87df4d, 0],
+ [[0.33, 0.33, 0.34], 0x00000000, 0x00000000, 0],
+ [[0.33, 0.33, 0.34], 0x00000000, 0x00000001, 2],
+ [[0.33, 0.33, 0.34], 0x8015406f, 0x7ef49b98, 0],
+ [[0.33, 0.33, 0.34], 0x3b2e7571, 0xca87df4d, 0],
+ ],
+ "123456789": [
+ [[0.5, 0.5], 0x00000000, 0x00000000, 1],
+ [[0.5, 0.5], 0x00000000, 0x00000001, 0],
+ [[0.5, 0.5], 0x8015406f, 0x7ef49b98, 1],
+ [[0.5, 0.5], 0x3b2e7571, 0xca87df4d, 1],
+ [[0.33, 0.33, 0.34], 0x00000000, 0x00000000, 2],
+ [[0.33, 0.33, 0.34], 0x00000000, 0x00000001, 0],
+ [[0.33, 0.33, 0.34], 0x8015406f, 0x7ef49b98, 2],
+ [[0.33, 0.33, 0.34], 0x3b2e7571, 0xca87df4d, 1],
+ ],
+ };
+
+ for (const [unit, cases] of Object.entries(testCases)) {
+ describe(`unit: "${unit}"`, () => {
+ const assigner = new VariantAssigner(hashUnit(unit));
+ for (const [split, seedHi, seedLo, expected] of cases) {
+ test(`assign([${split}], 0x${seedHi.toString(16)}, 0x${seedLo.toString(16)}) == ${expected}`, () => {
+ expect(assigner.assign(split, seedHi, seedLo)).toBe(expected);
+ });
+ }
+ });
+ }
+});
+```
+
+- [ ] **Step 2: Run tests to verify they fail**
+
+Run: `npx vitest run src/__tests__/assigner.test.ts`
+
+Expected: FAIL - module not found
+
+- [ ] **Step 3: Write src/assigner.ts**
+
+```typescript
+import { chooseVariant } from "./utils";
+import { stringToUint8Array } from "./hashing";
+import { murmur3_32 } from "./murmur3";
+
+export class VariantAssigner {
+ private readonly _unitHash: number;
+
+ constructor(unit: string) {
+ this._unitHash = murmur3_32(stringToUint8Array(unit).buffer);
+ }
+
+ assign(split: number[], seedHi: number, seedLo: number): number {
+ const prob = this._probability(seedHi, seedLo);
+ return chooseVariant(split, prob);
+ }
+
+ private _probability(seedHi: number, seedLo: number): number {
+ const key = this._unitHash;
+ const buffer = new ArrayBuffer(12);
+ const view = new DataView(buffer);
+ view.setUint32(0, seedLo, true);
+ view.setUint32(4, seedHi, true);
+ view.setUint32(8, key, true);
+ return murmur3_32(buffer) * (1.0 / 0xffffffff);
+ }
+}
+```
+
+- [ ] **Step 4: Run tests to verify they pass**
+
+Run: `npx vitest run src/__tests__/assigner.test.ts`
+
+Expected: All 16 tests pass
+
+- [ ] **Step 5: Commit**
+
+```bash
+git add src/assigner.ts src/__tests__/assigner.test.ts
+git commit -m "feat: add VariantAssigner with murmur3-based probability"
+```
+
+---
+
+## Task 8: JsonExpr Evaluator
+
+**Files:**
+- Create: `src/jsonexpr/evaluator.ts`
+- Create: `src/__tests__/jsonexpr/evaluator.test.ts`
+
+- [ ] **Step 1: Write the failing tests**
+
+```typescript
+import { describe, expect, test } from "vitest";
+import { Evaluator } from "../../jsonexpr/evaluator";
+
+function createEvaluator(vars: Record = {}) {
+ return new Evaluator({}, vars);
+}
+
+describe("Evaluator", () => {
+ describe("booleanConvert", () => {
+ const evaluator = createEvaluator();
+
+ test("boolean values", () => {
+ expect(evaluator.booleanConvert(true)).toBe(true);
+ expect(evaluator.booleanConvert(false)).toBe(false);
+ });
+
+ test("number values", () => {
+ expect(evaluator.booleanConvert(1)).toBe(true);
+ expect(evaluator.booleanConvert(0)).toBe(false);
+ expect(evaluator.booleanConvert(-1)).toBe(true);
+ });
+
+ test("string values", () => {
+ expect(evaluator.booleanConvert("true")).toBe(true);
+ expect(evaluator.booleanConvert("false")).toBe(false);
+ expect(evaluator.booleanConvert("0")).toBe(false);
+ expect(evaluator.booleanConvert("")).toBe(false);
+ expect(evaluator.booleanConvert("abc")).toBe(true);
+ });
+
+ test("null/undefined", () => {
+ expect(evaluator.booleanConvert(null)).toBe(false);
+ expect(evaluator.booleanConvert(undefined)).toBe(false);
+ });
+ });
+
+ describe("numberConvert", () => {
+ const evaluator = createEvaluator();
+
+ test("number values", () => {
+ expect(evaluator.numberConvert(42)).toBe(42);
+ expect(evaluator.numberConvert(0)).toBe(0);
+ expect(evaluator.numberConvert(-1.5)).toBe(-1.5);
+ });
+
+ test("boolean values", () => {
+ expect(evaluator.numberConvert(true)).toBe(1);
+ expect(evaluator.numberConvert(false)).toBe(0);
+ });
+
+ test("string values", () => {
+ expect(evaluator.numberConvert("42")).toBe(42);
+ expect(evaluator.numberConvert("3.14")).toBe(3.14);
+ expect(evaluator.numberConvert("abc")).toBe(null);
+ });
+
+ test("other types", () => {
+ expect(evaluator.numberConvert(null)).toBe(null);
+ expect(evaluator.numberConvert({})).toBe(null);
+ });
+ });
+
+ describe("stringConvert", () => {
+ const evaluator = createEvaluator();
+
+ test("string values", () => {
+ expect(evaluator.stringConvert("hello")).toBe("hello");
+ });
+
+ test("boolean values", () => {
+ expect(evaluator.stringConvert(true)).toBe("true");
+ expect(evaluator.stringConvert(false)).toBe("false");
+ });
+
+ test("number values", () => {
+ expect(evaluator.stringConvert(42)).toBe("42");
+ expect(evaluator.stringConvert(0)).toBe("0");
+ });
+
+ test("other types", () => {
+ expect(evaluator.stringConvert(null)).toBe(null);
+ expect(evaluator.stringConvert({})).toBe(null);
+ });
+ });
+
+ describe("extractVar", () => {
+ test("extracts top-level variable", () => {
+ const evaluator = createEvaluator({ name: "John" });
+ expect(evaluator.extractVar("name")).toBe("John");
+ });
+
+ test("extracts nested variable", () => {
+ const evaluator = createEvaluator({ user: { name: "John" } });
+ expect(evaluator.extractVar("user/name")).toBe("John");
+ });
+
+ test("returns null for missing path", () => {
+ const evaluator = createEvaluator({ name: "John" });
+ expect(evaluator.extractVar("missing")).toBe(null);
+ });
+ });
+
+ describe("compare", () => {
+ const evaluator = createEvaluator();
+
+ test("numbers", () => {
+ expect(evaluator.compare(1, 2)).toBe(-1);
+ expect(evaluator.compare(2, 1)).toBe(1);
+ expect(evaluator.compare(1, 1)).toBe(0);
+ });
+
+ test("strings", () => {
+ expect(evaluator.compare("a", "b")).toBe(-1);
+ expect(evaluator.compare("b", "a")).toBe(1);
+ expect(evaluator.compare("a", "a")).toBe(0);
+ });
+
+ test("booleans", () => {
+ expect(evaluator.compare(true, true)).toBe(0);
+ expect(evaluator.compare(false, false)).toBe(0);
+ });
+
+ test("null handling", () => {
+ expect(evaluator.compare(null, null)).toBe(0);
+ expect(evaluator.compare(null, 1)).toBe(null);
+ expect(evaluator.compare(1, null)).toBe(null);
+ });
+ });
+
+ describe("versionCompare", () => {
+ const evaluator = createEvaluator();
+
+ test("equal versions", () => {
+ expect(evaluator.versionCompare("1.0.0", "1.0.0")).toBe(0);
+ });
+
+ test("greater version", () => {
+ expect(evaluator.versionCompare("2.0.0", "1.0.0")).toBe(1);
+ });
+
+ test("lesser version", () => {
+ expect(evaluator.versionCompare("1.0.0", "2.0.0")).toBe(-1);
+ });
+
+ test("prerelease is less than release", () => {
+ expect(evaluator.versionCompare("1.0.0-alpha", "1.0.0")).toBe(-1);
+ });
+
+ test("v prefix", () => {
+ expect(evaluator.versionCompare("v1.0.0", "1.0.0")).toBe(0);
+ });
+
+ test("build metadata ignored", () => {
+ expect(evaluator.versionCompare("1.0.0+build1", "1.0.0+build2")).toBe(0);
+ });
+
+ test("null inputs", () => {
+ expect(evaluator.versionCompare(null, "1.0.0")).toBe(null);
+ expect(evaluator.versionCompare("1.0.0", null)).toBe(null);
+ });
+
+ test("empty inputs", () => {
+ expect(evaluator.versionCompare("", "1.0.0")).toBe(null);
+ expect(evaluator.versionCompare("1.0.0", "")).toBe(null);
+ });
+ });
+});
+```
+
+- [ ] **Step 2: Run tests to verify they fail**
+
+Run: `npx vitest run src/__tests__/jsonexpr/evaluator.test.ts`
+
+Expected: FAIL - module not found
+
+- [ ] **Step 3: Write src/jsonexpr/evaluator.ts**
+
+Port the evaluator verbatim from the original. The implementation is in the code read earlier (`src/jsonexpr/evaluator.ts` from original codebase). Copy it with proper strict TypeScript typing:
+
+```typescript
+import { isEqualsDeep, isObject } from "../utils";
+
+export interface Operator {
+ evaluate(evaluator: Evaluator, args: unknown): unknown;
+}
+
+function parseSemver(version: string) {
+ let v = version;
+ if (v.startsWith("v") || v.startsWith("V")) {
+ v = v.substring(1);
+ }
+
+ const plusIndex = v.indexOf("+");
+ if (plusIndex >= 0) {
+ v = v.substring(0, plusIndex);
+ }
+
+ if (v === "") return null;
+
+ const [core, ...preReleaseParts] = v.split("-");
+ const preRelease = preReleaseParts.join("-");
+
+ if (core === "") return null;
+
+ const parts = core!.split(".");
+ return { parts, preRelease };
+}
+
+const NUMERIC_IDENTIFIER = /^\d+$/;
+
+function stripLeadingZeros(s: string): string {
+ const stripped = s.replace(/^0+/, "");
+ return stripped === "" ? "0" : stripped;
+}
+
+function compareIdentifiers(a: string, b: string): number {
+ const aIsNum = NUMERIC_IDENTIFIER.test(a);
+ const bIsNum = NUMERIC_IDENTIFIER.test(b);
+
+ if (aIsNum && bIsNum) {
+ const aNorm = stripLeadingZeros(a);
+ const bNorm = stripLeadingZeros(b);
+ if (aNorm.length !== bNorm.length) return aNorm.length > bNorm.length ? 1 : -1;
+ return aNorm === bNorm ? 0 : aNorm > bNorm ? 1 : -1;
+ }
+ if (aIsNum) return -1;
+ if (bIsNum) return 1;
+ return a === b ? 0 : a > b ? 1 : -1;
+}
+
+export class Evaluator {
+ private readonly operators: Record;
+ private readonly vars: Record;
+
+ constructor(operators: Record, vars: Record) {
+ this.operators = operators;
+ this.vars = vars;
+ }
+
+ evaluate(expr: unknown): unknown {
+ if (Array.isArray(expr)) {
+ return this.operators["and"]?.evaluate(this, expr) ?? null;
+ } else if (isObject(expr)) {
+ for (const [key, value] of Object.entries(expr)) {
+ const op = this.operators[key];
+ if (op !== undefined) {
+ return op.evaluate(this, value);
+ }
+ break;
+ }
+ }
+ return null;
+ }
+
+ booleanConvert(x: unknown): boolean {
+ const type = typeof x;
+ switch (type) {
+ case "boolean":
+ return x as boolean;
+ case "number":
+ return x !== 0;
+ case "string":
+ return x !== "false" && x !== "0" && x !== "";
+ default:
+ return x !== null && x !== undefined;
+ }
+ }
+
+ numberConvert(x: unknown): number | null {
+ switch (typeof x) {
+ case "number":
+ return x;
+ case "boolean":
+ return x ? 1 : 0;
+ case "string": {
+ const y = parseFloat(x);
+ return Number.isFinite(y) ? y : null;
+ }
+ default:
+ return null;
+ }
+ }
+
+ stringConvert(x: unknown): string | null {
+ switch (typeof x) {
+ case "string":
+ return x;
+ case "boolean":
+ return x.toString();
+ case "number":
+ return x.toFixed(15).replace(/\.?0{0,15}$/, "");
+ default:
+ return null;
+ }
+ }
+
+ extractVar(path: string): unknown {
+ const frags = path.split("/");
+ let target: unknown = this.vars ?? {};
+ for (const frag of frags) {
+ if (target !== null && typeof target === "object" && frag in (target as Record)) {
+ target = (target as Record)[frag];
+ continue;
+ }
+ return null;
+ }
+ return target;
+ }
+
+ versionCompare(lhs: unknown, rhs: unknown): number | null {
+ const lhsStr = this.stringConvert(lhs);
+ const rhsStr = this.stringConvert(rhs);
+ if (lhsStr === null || rhsStr === null || lhsStr === "" || rhsStr === "") return null;
+
+ const l = parseSemver(lhsStr);
+ const r = parseSemver(rhsStr);
+ if (l === null || r === null) return null;
+
+ const maxLen = Math.max(l.parts.length, r.parts.length);
+ for (let i = 0; i < maxLen; i++) {
+ const lPart = l.parts[i] ?? "0";
+ const rPart = r.parts[i] ?? "0";
+ const result = compareIdentifiers(lPart, rPart);
+ if (result !== 0) return result;
+ }
+
+ if (!l.preRelease && !r.preRelease) return 0;
+ if (!l.preRelease) return 1;
+ if (!r.preRelease) return -1;
+
+ const lPreParts = l.preRelease.split(".");
+ const rPreParts = r.preRelease.split(".");
+ const preLen = Math.max(lPreParts.length, rPreParts.length);
+ for (let i = 0; i < preLen; i++) {
+ if (i >= lPreParts.length) return -1;
+ if (i >= rPreParts.length) return 1;
+ const result = compareIdentifiers(lPreParts[i]!, rPreParts[i]!);
+ if (result !== 0) return result;
+ }
+
+ return 0;
+ }
+
+ compare(lhs: unknown, rhs: unknown): number | null {
+ if (lhs === null) return rhs === null ? 0 : null;
+ if (rhs === null) return null;
+
+ switch (typeof lhs) {
+ case "number": {
+ const rvalue = this.numberConvert(rhs);
+ if (rvalue !== null) return lhs === rvalue ? 0 : lhs > rvalue ? 1 : -1;
+ break;
+ }
+ case "string": {
+ const rvalue = this.stringConvert(rhs);
+ if (rvalue !== null) return lhs === rvalue ? 0 : lhs > rvalue ? 1 : -1;
+ break;
+ }
+ case "boolean": {
+ const rvalue = this.booleanConvert(rhs);
+ if (rvalue != null) return lhs === rvalue ? 0 : lhs > rvalue ? 1 : -1;
+ break;
+ }
+ default: {
+ if (isEqualsDeep(lhs, rhs)) return 0;
+ break;
+ }
+ }
+
+ return null;
+ }
+}
+```
+
+- [ ] **Step 4: Run tests to verify they pass**
+
+Run: `npx vitest run src/__tests__/jsonexpr/evaluator.test.ts`
+
+Expected: All tests pass
+
+- [ ] **Step 5: Commit**
+
+```bash
+git add src/jsonexpr/evaluator.ts src/__tests__/jsonexpr/evaluator.test.ts
+git commit -m "feat: add JsonExpr evaluator with type conversion and comparison"
+```
+
+---
+
+## Task 9: JsonExpr Operators
+
+**Files:**
+- Create: `src/jsonexpr/operators.ts`
+- Create: `src/__tests__/jsonexpr/operators.test.ts`
+
+- [ ] **Step 1: Write the failing tests**
+
+```typescript
+import { describe, expect, test } from "vitest";
+import { Evaluator } from "../../jsonexpr/evaluator";
+import {
+ AndCombinator,
+ EqualsOperator,
+ GreaterThanOperator,
+ GreaterThanOrEqualOperator,
+ InOperator,
+ LessThanOperator,
+ LessThanOrEqualOperator,
+ MatchOperator,
+ NotOperator,
+ NullOperator,
+ OrCombinator,
+ SemverEqualsOperator,
+ SemverGreaterThanOperator,
+ SemverGreaterThanOrEqualOperator,
+ SemverLessThanOperator,
+ SemverLessThanOrEqualOperator,
+ ValueOperator,
+ VarOperator,
+} from "../../jsonexpr/operators";
+
+function makeEvaluator(vars: Record = {}): Evaluator {
+ const operators = {
+ and: new AndCombinator(),
+ or: new OrCombinator(),
+ value: new ValueOperator(),
+ var: new VarOperator(),
+ null: new NullOperator(),
+ not: new NotOperator(),
+ in: new InOperator(),
+ match: new MatchOperator(),
+ eq: new EqualsOperator(),
+ gt: new GreaterThanOperator(),
+ gte: new GreaterThanOrEqualOperator(),
+ lt: new LessThanOperator(),
+ lte: new LessThanOrEqualOperator(),
+ semver_eq: new SemverEqualsOperator(),
+ semver_gt: new SemverGreaterThanOperator(),
+ semver_gte: new SemverGreaterThanOrEqualOperator(),
+ semver_lt: new SemverLessThanOperator(),
+ semver_lte: new SemverLessThanOrEqualOperator(),
+ };
+ return new Evaluator(operators, vars);
+}
+
+describe("ValueOperator", () => {
+ test("returns the value as-is", () => {
+ const evaluator = makeEvaluator();
+ const op = new ValueOperator();
+ expect(op.evaluate(evaluator, 42)).toBe(42);
+ expect(op.evaluate(evaluator, "hello")).toBe("hello");
+ expect(op.evaluate(evaluator, null)).toBe(null);
+ });
+});
+
+describe("VarOperator", () => {
+ test("extracts variable by path string", () => {
+ const evaluator = makeEvaluator({ name: "John", nested: { key: "val" } });
+ const op = new VarOperator();
+ expect(op.evaluate(evaluator, "name")).toBe("John");
+ expect(op.evaluate(evaluator, "nested/key")).toBe("val");
+ });
+
+ test("extracts variable by path object", () => {
+ const evaluator = makeEvaluator({ name: "John" });
+ const op = new VarOperator();
+ expect(op.evaluate(evaluator, { path: "name" })).toBe("John");
+ });
+
+ test("returns null for non-string path", () => {
+ const evaluator = makeEvaluator();
+ const op = new VarOperator();
+ expect(op.evaluate(evaluator, 42)).toBe(null);
+ });
+});
+
+describe("AndCombinator", () => {
+ test("returns true when all truthy", () => {
+ const evaluator = makeEvaluator();
+ const op = new AndCombinator();
+ expect(op.evaluate(evaluator, [{ value: true }, { value: 1 }])).toBe(true);
+ });
+
+ test("returns false when any falsy", () => {
+ const evaluator = makeEvaluator();
+ const op = new AndCombinator();
+ expect(op.evaluate(evaluator, [{ value: true }, { value: false }])).toBe(false);
+ });
+
+ test("returns true for empty array", () => {
+ const evaluator = makeEvaluator();
+ const op = new AndCombinator();
+ expect(op.evaluate(evaluator, [])).toBe(true);
+ });
+});
+
+describe("OrCombinator", () => {
+ test("returns true when any truthy", () => {
+ const evaluator = makeEvaluator();
+ const op = new OrCombinator();
+ expect(op.evaluate(evaluator, [{ value: false }, { value: true }])).toBe(true);
+ });
+
+ test("returns false when all falsy", () => {
+ const evaluator = makeEvaluator();
+ const op = new OrCombinator();
+ expect(op.evaluate(evaluator, [{ value: false }, { value: 0 }])).toBe(false);
+ });
+
+ test("returns true for empty array (vacuous truth)", () => {
+ const evaluator = makeEvaluator();
+ const op = new OrCombinator();
+ expect(op.evaluate(evaluator, [])).toBe(true);
+ });
+});
+
+describe("NotOperator", () => {
+ test("negates boolean", () => {
+ const evaluator = makeEvaluator();
+ const op = new NotOperator();
+ expect(op.evaluate(evaluator, { value: true })).toBe(false);
+ expect(op.evaluate(evaluator, { value: false })).toBe(true);
+ });
+});
+
+describe("NullOperator", () => {
+ test("checks if value is null", () => {
+ const evaluator = makeEvaluator();
+ const op = new NullOperator();
+ expect(op.evaluate(evaluator, { value: null })).toBe(true);
+ expect(op.evaluate(evaluator, { value: 0 })).toBe(false);
+ });
+});
+
+describe("EqualsOperator", () => {
+ test("compares values for equality", () => {
+ const evaluator = makeEvaluator();
+ const op = new EqualsOperator();
+ expect(op.evaluate(evaluator, [{ value: 1 }, { value: 1 }])).toBe(true);
+ expect(op.evaluate(evaluator, [{ value: 1 }, { value: 2 }])).toBe(false);
+ expect(op.evaluate(evaluator, [{ value: "a" }, { value: "a" }])).toBe(true);
+ });
+});
+
+describe("Comparison operators", () => {
+ const evaluator = makeEvaluator();
+
+ test("GreaterThan", () => {
+ const op = new GreaterThanOperator();
+ expect(op.evaluate(evaluator, [{ value: 2 }, { value: 1 }])).toBe(true);
+ expect(op.evaluate(evaluator, [{ value: 1 }, { value: 2 }])).toBe(false);
+ expect(op.evaluate(evaluator, [{ value: 1 }, { value: 1 }])).toBe(false);
+ });
+
+ test("GreaterThanOrEqual", () => {
+ const op = new GreaterThanOrEqualOperator();
+ expect(op.evaluate(evaluator, [{ value: 2 }, { value: 1 }])).toBe(true);
+ expect(op.evaluate(evaluator, [{ value: 1 }, { value: 1 }])).toBe(true);
+ expect(op.evaluate(evaluator, [{ value: 1 }, { value: 2 }])).toBe(false);
+ });
+
+ test("LessThan", () => {
+ const op = new LessThanOperator();
+ expect(op.evaluate(evaluator, [{ value: 1 }, { value: 2 }])).toBe(true);
+ expect(op.evaluate(evaluator, [{ value: 2 }, { value: 1 }])).toBe(false);
+ });
+
+ test("LessThanOrEqual", () => {
+ const op = new LessThanOrEqualOperator();
+ expect(op.evaluate(evaluator, [{ value: 1 }, { value: 2 }])).toBe(true);
+ expect(op.evaluate(evaluator, [{ value: 1 }, { value: 1 }])).toBe(true);
+ });
+});
+
+describe("InOperator", () => {
+ const evaluator = makeEvaluator();
+ const op = new InOperator();
+
+ test("array membership", () => {
+ expect(op.evaluate(evaluator, [{ value: [1, 2, 3] }, { value: 2 }])).toBe(true);
+ expect(op.evaluate(evaluator, [{ value: [1, 2, 3] }, { value: 4 }])).toBe(false);
+ });
+
+ test("string containment", () => {
+ expect(op.evaluate(evaluator, [{ value: "hello world" }, { value: "world" }])).toBe(true);
+ expect(op.evaluate(evaluator, [{ value: "hello" }, { value: "world" }])).toBe(false);
+ });
+
+ test("object key check", () => {
+ expect(op.evaluate(evaluator, [{ value: { a: 1 } }, { value: "a" }])).toBe(true);
+ expect(op.evaluate(evaluator, [{ value: { a: 1 } }, { value: "b" }])).toBe(false);
+ });
+});
+
+describe("MatchOperator", () => {
+ const evaluator = makeEvaluator();
+ const op = new MatchOperator();
+
+ test("matches regex", () => {
+ expect(op.evaluate(evaluator, [{ value: "hello123" }, { value: "\\d+" }])).toBe(true);
+ expect(op.evaluate(evaluator, [{ value: "hello" }, { value: "\\d+" }])).toBe(false);
+ });
+});
+
+describe("Semver operators", () => {
+ const evaluator = makeEvaluator();
+
+ test("semver_eq", () => {
+ const op = new SemverEqualsOperator();
+ expect(op.evaluate(evaluator, [{ value: "1.0.0" }, { value: "1.0.0" }])).toBe(true);
+ expect(op.evaluate(evaluator, [{ value: "1.0.0" }, { value: "1.0.1" }])).toBe(false);
+ });
+
+ test("semver_gt", () => {
+ const op = new SemverGreaterThanOperator();
+ expect(op.evaluate(evaluator, [{ value: "2.0.0" }, { value: "1.0.0" }])).toBe(true);
+ expect(op.evaluate(evaluator, [{ value: "1.0.0" }, { value: "2.0.0" }])).toBe(false);
+ });
+
+ test("semver_gte", () => {
+ const op = new SemverGreaterThanOrEqualOperator();
+ expect(op.evaluate(evaluator, [{ value: "1.0.0" }, { value: "1.0.0" }])).toBe(true);
+ });
+
+ test("semver_lt", () => {
+ const op = new SemverLessThanOperator();
+ expect(op.evaluate(evaluator, [{ value: "1.0.0" }, { value: "2.0.0" }])).toBe(true);
+ });
+
+ test("semver_lte", () => {
+ const op = new SemverLessThanOrEqualOperator();
+ expect(op.evaluate(evaluator, [{ value: "1.0.0" }, { value: "1.0.0" }])).toBe(true);
+ });
+});
+```
+
+- [ ] **Step 2: Run tests to verify they fail**
+
+Run: `npx vitest run src/__tests__/jsonexpr/operators.test.ts`
+
+Expected: FAIL - module not found
+
+- [ ] **Step 3: Write src/jsonexpr/operators.ts**
+
+All 20 operators consolidated in one file:
+
+```typescript
+import { Evaluator } from "./evaluator";
+import { isObject } from "../utils";
+
+export class ValueOperator {
+ evaluate(_: Evaluator, value: unknown): unknown {
+ return value;
+ }
+}
+
+export class VarOperator {
+ evaluate(evaluator: Evaluator, path: unknown): unknown {
+ if (isObject(path)) {
+ path = (path as { path: string }).path;
+ }
+ return typeof path === "string" ? evaluator.extractVar(path) : null;
+ }
+}
+
+export class AndCombinator {
+ evaluate(evaluator: Evaluator, args: unknown): boolean | null {
+ if (Array.isArray(args)) {
+ for (const expr of args) {
+ if (!evaluator.booleanConvert(evaluator.evaluate(expr))) return false;
+ }
+ return true;
+ }
+ return null;
+ }
+}
+
+export class OrCombinator {
+ evaluate(evaluator: Evaluator, args: unknown): boolean | null {
+ if (Array.isArray(args)) {
+ for (const expr of args) {
+ if (evaluator.booleanConvert(evaluator.evaluate(expr))) return true;
+ }
+ return args.length === 0;
+ }
+ return null;
+ }
+}
+
+abstract class UnaryOperator {
+ abstract unary(evaluator: Evaluator, arg: unknown): boolean;
+ evaluate(evaluator: Evaluator, arg: unknown): boolean {
+ arg = evaluator.evaluate(arg);
+ return this.unary(evaluator, arg);
+ }
+}
+
+export class NotOperator extends UnaryOperator {
+ unary(evaluator: Evaluator, arg: unknown): boolean {
+ return !evaluator.booleanConvert(arg);
+ }
+}
+
+export class NullOperator extends UnaryOperator {
+ unary(_: Evaluator, value: unknown): boolean {
+ return value === null;
+ }
+}
+
+abstract class BinaryOperator {
+ abstract binary(evaluator: Evaluator, lhs: unknown, rhs: unknown): boolean | null;
+ evaluate(evaluator: Evaluator, args: unknown): boolean | null {
+ if (Array.isArray(args)) {
+ const lhs = args.length > 0 ? evaluator.evaluate(args[0]) : null;
+ if (lhs !== null) {
+ const rhs = args.length > 1 ? evaluator.evaluate(args[1]) : null;
+ if (rhs !== null) {
+ return this.binary(evaluator, lhs, rhs);
+ }
+ }
+ }
+ return null;
+ }
+}
+
+export class EqualsOperator extends BinaryOperator {
+ binary(evaluator: Evaluator, lhs: unknown, rhs: unknown): boolean | null {
+ const result = evaluator.compare(lhs, rhs);
+ return result !== null ? result === 0 : null;
+ }
+}
+
+export class GreaterThanOperator extends BinaryOperator {
+ binary(evaluator: Evaluator, lhs: unknown, rhs: unknown): boolean | null {
+ const result = evaluator.compare(lhs, rhs);
+ return result !== null ? result > 0 : null;
+ }
+}
+
+export class GreaterThanOrEqualOperator extends BinaryOperator {
+ binary(evaluator: Evaluator, lhs: unknown, rhs: unknown): boolean | null {
+ const result = evaluator.compare(lhs, rhs);
+ return result !== null ? result >= 0 : null;
+ }
+}
+
+export class LessThanOperator extends BinaryOperator {
+ binary(evaluator: Evaluator, lhs: unknown, rhs: unknown): boolean | null {
+ const result = evaluator.compare(lhs, rhs);
+ return result !== null ? result < 0 : null;
+ }
+}
+
+export class LessThanOrEqualOperator extends BinaryOperator {
+ binary(evaluator: Evaluator, lhs: unknown, rhs: unknown): boolean | null {
+ const result = evaluator.compare(lhs, rhs);
+ return result !== null ? result <= 0 : null;
+ }
+}
+
+export class InOperator extends BinaryOperator {
+ binary(evaluator: Evaluator, haystack: unknown, needle: unknown): boolean | null {
+ if (Array.isArray(haystack)) {
+ for (const item of haystack) {
+ if (evaluator.compare(item, needle) === 0) return true;
+ }
+ return false;
+ } else if (typeof haystack === "string") {
+ const needleString = evaluator.stringConvert(needle);
+ return needleString !== null && haystack.includes(needleString);
+ } else if (isObject(haystack)) {
+ const needleString = evaluator.stringConvert(needle);
+ return needleString != null && Object.prototype.hasOwnProperty.call(haystack, needleString);
+ }
+ return null;
+ }
+}
+
+export class MatchOperator extends BinaryOperator {
+ binary(evaluator: Evaluator, text: unknown, pattern: unknown): boolean | null {
+ const textStr = evaluator.stringConvert(text);
+ if (textStr !== null) {
+ const patternStr = evaluator.stringConvert(pattern);
+ if (patternStr !== null) {
+ try {
+ return new RegExp(patternStr).test(textStr);
+ } catch {
+ return null;
+ }
+ }
+ }
+ return null;
+ }
+}
+
+export class SemverEqualsOperator extends BinaryOperator {
+ binary(evaluator: Evaluator, lhs: unknown, rhs: unknown): boolean | null {
+ const result = evaluator.versionCompare(lhs, rhs);
+ return result !== null ? result === 0 : null;
+ }
+}
+
+export class SemverGreaterThanOperator extends BinaryOperator {
+ binary(evaluator: Evaluator, lhs: unknown, rhs: unknown): boolean | null {
+ const result = evaluator.versionCompare(lhs, rhs);
+ return result !== null ? result > 0 : null;
+ }
+}
+
+export class SemverGreaterThanOrEqualOperator extends BinaryOperator {
+ binary(evaluator: Evaluator, lhs: unknown, rhs: unknown): boolean | null {
+ const result = evaluator.versionCompare(lhs, rhs);
+ return result !== null ? result >= 0 : null;
+ }
+}
+
+export class SemverLessThanOperator extends BinaryOperator {
+ binary(evaluator: Evaluator, lhs: unknown, rhs: unknown): boolean | null {
+ const result = evaluator.versionCompare(lhs, rhs);
+ return result !== null ? result < 0 : null;
+ }
+}
+
+export class SemverLessThanOrEqualOperator extends BinaryOperator {
+ binary(evaluator: Evaluator, lhs: unknown, rhs: unknown): boolean | null {
+ const result = evaluator.versionCompare(lhs, rhs);
+ return result !== null ? result <= 0 : null;
+ }
+}
+```
+
+- [ ] **Step 4: Run tests to verify they pass**
+
+Run: `npx vitest run src/__tests__/jsonexpr/operators.test.ts`
+
+Expected: All tests pass
+
+- [ ] **Step 5: Commit**
+
+```bash
+git add src/jsonexpr/operators.ts src/__tests__/jsonexpr/operators.test.ts
+git commit -m "feat: add all 20 JsonExpr operators"
+```
+
+---
+
+## Task 10: JsonExpr Facade & AudienceMatcher
+
+**Files:**
+- Create: `src/jsonexpr/jsonexpr.ts`
+- Create: `src/matcher.ts`
+- Create: `src/__tests__/jsonexpr/jsonexpr.test.ts`
+- Create: `src/__tests__/matcher.test.ts`
+
+- [ ] **Step 1: Write the failing tests for JsonExpr**
+
+```typescript
+import { describe, expect, test } from "vitest";
+import { JsonExpr } from "../../jsonexpr/jsonexpr";
+
+describe("JsonExpr", () => {
+ const jsonExpr = new JsonExpr();
+
+ test("evaluateBooleanExpr with and-array", () => {
+ expect(jsonExpr.evaluateBooleanExpr([{ value: true }, { value: 1 }], {})).toBe(true);
+ expect(jsonExpr.evaluateBooleanExpr([{ value: true }, { value: false }], {})).toBe(false);
+ });
+
+ test("evaluateBooleanExpr with object expr", () => {
+ expect(jsonExpr.evaluateBooleanExpr({ value: true }, {})).toBe(true);
+ expect(jsonExpr.evaluateBooleanExpr({ value: false }, {})).toBe(false);
+ });
+
+ test("evaluateExpr returns raw value", () => {
+ expect(jsonExpr.evaluateExpr({ value: 42 }, {})).toBe(42);
+ expect(jsonExpr.evaluateExpr({ value: "hello" }, {})).toBe("hello");
+ });
+
+ test("var operator extracts from vars", () => {
+ expect(jsonExpr.evaluateExpr({ var: "name" }, { name: "Alice" })).toBe("Alice");
+ });
+
+ test("complex expression with eq and var", () => {
+ const expr = { eq: [{ var: "age" }, { value: 25 }] };
+ expect(jsonExpr.evaluateBooleanExpr(expr, { age: 25 })).toBe(true);
+ expect(jsonExpr.evaluateBooleanExpr(expr, { age: 30 })).toBe(false);
+ });
+});
+```
+
+- [ ] **Step 2: Write the failing tests for AudienceMatcher**
+
+```typescript
+import { describe, expect, test } from "vitest";
+import { AudienceMatcher } from "../matcher";
+
+describe("AudienceMatcher", () => {
+ const matcher = new AudienceMatcher();
+
+ test("evaluates matching audience", () => {
+ const audience = JSON.stringify({ filter: [{ value: true }] });
+ expect(matcher.evaluate(audience, {})).toBe(true);
+ });
+
+ test("evaluates non-matching audience", () => {
+ const audience = JSON.stringify({ filter: [{ value: false }] });
+ expect(matcher.evaluate(audience, {})).toBe(false);
+ });
+
+ test("evaluates with not operator", () => {
+ const audience = JSON.stringify({ filter: [{ not: { value: false } }] });
+ expect(matcher.evaluate(audience, {})).toBe(true);
+ });
+
+ test("returns null for invalid JSON", () => {
+ expect(matcher.evaluate("invalid json", {})).toBe(null);
+ });
+
+ test("returns null for missing filter", () => {
+ expect(matcher.evaluate(JSON.stringify({}), {})).toBe(null);
+ });
+
+ test("returns null for null filter", () => {
+ expect(matcher.evaluate(JSON.stringify({ filter: null }), {})).toBe(null);
+ });
+});
+```
+
+- [ ] **Step 3: Run tests to verify they fail**
+
+Run: `npx vitest run src/__tests__/jsonexpr/jsonexpr.test.ts src/__tests__/matcher.test.ts`
+
+Expected: FAIL - modules not found
+
+- [ ] **Step 4: Write src/jsonexpr/jsonexpr.ts**
+
+```typescript
+import { Evaluator } from "./evaluator";
+import {
+ AndCombinator,
+ EqualsOperator,
+ GreaterThanOperator,
+ GreaterThanOrEqualOperator,
+ InOperator,
+ LessThanOperator,
+ LessThanOrEqualOperator,
+ MatchOperator,
+ NotOperator,
+ NullOperator,
+ OrCombinator,
+ SemverEqualsOperator,
+ SemverGreaterThanOperator,
+ SemverGreaterThanOrEqualOperator,
+ SemverLessThanOperator,
+ SemverLessThanOrEqualOperator,
+ ValueOperator,
+ VarOperator,
+} from "./operators";
+
+const operators = {
+ and: new AndCombinator(),
+ or: new OrCombinator(),
+ value: new ValueOperator(),
+ var: new VarOperator(),
+ null: new NullOperator(),
+ not: new NotOperator(),
+ in: new InOperator(),
+ match: new MatchOperator(),
+ eq: new EqualsOperator(),
+ gt: new GreaterThanOperator(),
+ gte: new GreaterThanOrEqualOperator(),
+ lt: new LessThanOperator(),
+ lte: new LessThanOrEqualOperator(),
+ semver_eq: new SemverEqualsOperator(),
+ semver_gt: new SemverGreaterThanOperator(),
+ semver_gte: new SemverGreaterThanOrEqualOperator(),
+ semver_lt: new SemverLessThanOperator(),
+ semver_lte: new SemverLessThanOrEqualOperator(),
+};
+
+export class JsonExpr {
+ evaluateBooleanExpr(expr: unknown, vars: Record): boolean {
+ const evaluator = new Evaluator(operators, vars);
+ return evaluator.booleanConvert(evaluator.evaluate(expr));
+ }
+
+ evaluateExpr(expr: unknown, vars: Record): unknown {
+ const evaluator = new Evaluator(operators, vars);
+ return evaluator.evaluate(expr);
+ }
+}
+```
+
+- [ ] **Step 5: Write src/matcher.ts**
+
+```typescript
+import { isObject } from "./utils";
+import { JsonExpr } from "./jsonexpr/jsonexpr";
+
+export class AudienceMatcher {
+ private readonly _jsonExpr = new JsonExpr();
+
+ evaluate(audienceString: string, vars: Record): boolean | null {
+ try {
+ const audience = JSON.parse(audienceString);
+ if (audience && audience.filter) {
+ if (Array.isArray(audience.filter) || isObject(audience.filter)) {
+ return this._jsonExpr.evaluateBooleanExpr(audience.filter, vars);
+ }
+ }
+ } catch {
+ // invalid JSON
+ }
+ return null;
+ }
+}
+```
+
+- [ ] **Step 6: Run tests to verify they pass**
+
+Run: `npx vitest run src/__tests__/jsonexpr/jsonexpr.test.ts src/__tests__/matcher.test.ts`
+
+Expected: All tests pass
+
+- [ ] **Step 7: Commit**
+
+```bash
+git add src/jsonexpr/jsonexpr.ts src/matcher.ts src/__tests__/jsonexpr/jsonexpr.test.ts src/__tests__/matcher.test.ts
+git commit -m "feat: add JsonExpr facade and AudienceMatcher"
+```
+
+---
+
+## Task 11: HTTP Client
+
+**Files:**
+- Create: `src/client.ts`
+- Create: `src/__tests__/client.test.ts`
+
+- [ ] **Step 1: Write the failing tests**
+
+```typescript
+import { describe, expect, test, vi, beforeEach, afterEach } from "vitest";
+import { Client } from "../client";
+import type { ClientOptions } from "../types";
+
+const defaultOpts: ClientOptions = {
+ agent: "test-agent",
+ apiKey: "test-api-key",
+ application: "test-app",
+ endpoint: "https://test.absmartly.io/v1",
+ environment: "test",
+};
+
+describe("Client", () => {
+ describe("constructor validation", () => {
+ test("throws for missing apiKey", () => {
+ const opts = { ...defaultOpts, apiKey: undefined } as unknown as ClientOptions;
+ expect(() => new Client(opts)).toThrow("Missing 'apiKey' in options argument");
+ });
+
+ test("throws for missing endpoint", () => {
+ const opts = { ...defaultOpts, endpoint: undefined } as unknown as ClientOptions;
+ expect(() => new Client(opts)).toThrow("Missing 'endpoint' in options argument");
+ });
+
+ test("throws for missing environment", () => {
+ const opts = { ...defaultOpts, environment: undefined } as unknown as ClientOptions;
+ expect(() => new Client(opts)).toThrow("Missing 'environment' in options argument");
+ });
+
+ test("throws for missing application", () => {
+ const opts = { ...defaultOpts, application: undefined } as unknown as ClientOptions;
+ expect(() => new Client(opts)).toThrow("Missing 'application' in options argument");
+ });
+
+ test("throws for empty apiKey", () => {
+ const opts = { ...defaultOpts, apiKey: "" };
+ expect(() => new Client(opts)).toThrow("Invalid 'apiKey' in options argument");
+ });
+
+ test("accepts ApplicationObject", () => {
+ const opts = { ...defaultOpts, application: { name: "my-app", version: "1.0.0" } };
+ const client = new Client(opts);
+ expect(client.getApplication()).toEqual({ name: "my-app", version: "1.0.0" });
+ });
+
+ test("converts string application to ApplicationObject", () => {
+ const client = new Client(defaultOpts);
+ expect(client.getApplication()).toEqual({ name: "test-app", version: 0 });
+ });
+ });
+
+ describe("accessors", () => {
+ test("getAgent", () => {
+ const client = new Client(defaultOpts);
+ expect(client.getAgent()).toBe("test-agent");
+ });
+
+ test("getEnvironment", () => {
+ const client = new Client(defaultOpts);
+ expect(client.getEnvironment()).toBe("test");
+ });
+ });
+
+ describe("getContext", () => {
+ beforeEach(() => {
+ vi.stubGlobal("fetch", vi.fn());
+ });
+
+ afterEach(() => {
+ vi.restoreAllMocks();
+ });
+
+ test("makes GET request to /context", async () => {
+ const mockResponse = { ok: true, json: () => Promise.resolve({ experiments: [] }) };
+ (globalThis.fetch as ReturnType).mockResolvedValue(mockResponse);
+
+ const client = new Client({ ...defaultOpts, retries: 0, timeout: 1000 });
+ await client.getContext();
+
+ expect(globalThis.fetch).toHaveBeenCalledTimes(1);
+ const [url] = (globalThis.fetch as ReturnType).mock.calls[0]!;
+ expect(url).toContain("/context");
+ expect(url).toContain("application=test-app");
+ expect(url).toContain("environment=test");
+ });
+ });
+
+ describe("publish", () => {
+ beforeEach(() => {
+ vi.stubGlobal("fetch", vi.fn());
+ });
+
+ afterEach(() => {
+ vi.restoreAllMocks();
+ });
+
+ test("makes PUT request to /context with auth headers", async () => {
+ const mockResponse = { ok: true, json: () => Promise.resolve({}) };
+ (globalThis.fetch as ReturnType).mockResolvedValue(mockResponse);
+
+ const client = new Client({ ...defaultOpts, retries: 0, timeout: 1000 });
+ await client.publish({
+ units: [{ type: "session_id", uid: "abc" }],
+ publishedAt: 1000,
+ hashed: true,
+ sdkVersion: "2.0.0",
+ });
+
+ const [, opts] = (globalThis.fetch as ReturnType).mock.calls[0]!;
+ expect(opts.method).toBe("PUT");
+ expect(opts.headers["X-API-Key"]).toBe("test-api-key");
+ expect(opts.headers["X-Agent"]).toBe("test-agent");
+ expect(opts.headers["X-Environment"]).toBe("test");
+ });
+
+ test("omits empty goals and exposures arrays", async () => {
+ const mockResponse = { ok: true, json: () => Promise.resolve({}) };
+ (globalThis.fetch as ReturnType).mockResolvedValue(mockResponse);
+
+ const client = new Client({ ...defaultOpts, retries: 0, timeout: 1000 });
+ await client.publish({
+ units: [{ type: "session_id", uid: "abc" }],
+ publishedAt: 1000,
+ hashed: true,
+ sdkVersion: "2.0.0",
+ goals: [],
+ exposures: [],
+ });
+
+ const [, opts] = (globalThis.fetch as ReturnType).mock.calls[0]!;
+ const body = JSON.parse(opts.body);
+ expect(body.goals).toBeUndefined();
+ expect(body.exposures).toBeUndefined();
+ });
+ });
+
+ describe("retry logic", () => {
+ beforeEach(() => {
+ vi.useFakeTimers();
+ vi.stubGlobal("fetch", vi.fn());
+ });
+
+ afterEach(() => {
+ vi.useRealTimers();
+ vi.restoreAllMocks();
+ });
+
+ test("retries on server error", async () => {
+ const failResponse = { ok: false, status: 500, statusText: "Server Error", text: () => Promise.resolve("") };
+ const successResponse = { ok: true, json: () => Promise.resolve({ data: "ok" }) };
+
+ (globalThis.fetch as ReturnType)
+ .mockResolvedValueOnce(failResponse)
+ .mockResolvedValueOnce(successResponse);
+
+ const client = new Client({ ...defaultOpts, retries: 3, timeout: 10000 });
+ const promise = client.getContext();
+
+ await vi.runAllTimersAsync();
+ const result = await promise;
+
+ expect(result).toEqual({ data: "ok" });
+ expect(globalThis.fetch).toHaveBeenCalledTimes(2);
+ });
+
+ test("does not retry on 4xx error", async () => {
+ const failResponse = {
+ ok: false,
+ status: 400,
+ statusText: "Bad Request",
+ text: () => Promise.resolve("bad request"),
+ };
+
+ (globalThis.fetch as ReturnType).mockResolvedValue(failResponse);
+
+ const client = new Client({ ...defaultOpts, retries: 3, timeout: 10000 });
+ const promise = client.getContext();
+
+ await vi.runAllTimersAsync();
+ await expect(promise).rejects.toThrow("bad request");
+ expect(globalThis.fetch).toHaveBeenCalledTimes(1);
+ });
+ });
+});
+```
+
+- [ ] **Step 2: Run tests to verify they fail**
+
+Run: `npx vitest run src/__tests__/client.test.ts`
+
+Expected: FAIL - module not found
+
+- [ ] **Step 3: Write src/client.ts**
+
+```typescript
+import { AbortError, RetryError, TimeoutError } from "./errors";
+import type {
+ ApplicationObject,
+ ClientOptions,
+ ClientRequestOptions,
+ ContextOptions,
+ ContextParams,
+ FetchResponse,
+ NormalizedClientOptions,
+ PublishParams,
+} from "./types";
+
+export class Client {
+ private readonly _opts: NormalizedClientOptions;
+ private readonly _delay: number;
+
+ constructor(opts: ClientOptions) {
+ const merged: Record = Object.assign(
+ { agent: "javascript-client", retries: 5, timeout: 3000, keepalive: true },
+ opts,
+ );
+
+ for (const key of ["agent", "application", "apiKey", "endpoint", "environment"]) {
+ if (key in merged && merged[key] !== undefined) {
+ const value = merged[key];
+ if (typeof value !== "string" || (value as string).length === 0) {
+ if (key === "application") {
+ if (value !== null && typeof value === "object" && "name" in (value as object)) continue;
+ }
+ throw new Error(`Invalid '${key}' in options argument`);
+ }
+ } else {
+ throw new Error(`Missing '${key}' in options argument`);
+ }
+ }
+
+ if (typeof merged.application === "string") {
+ merged.application = { name: merged.application, version: 0 };
+ }
+
+ this._opts = merged as unknown as NormalizedClientOptions;
+ this._delay = 50;
+ }
+
+ getContext(options?: Partial): Promise {
+ return this.getUnauthed({
+ ...options,
+ path: "/context",
+ query: {
+ application: this._opts.application.name,
+ environment: this._opts.environment,
+ },
+ });
+ }
+
+ createContext(params: ContextParams, options: ContextOptions): Promise {
+ return this.post({ ...options, path: "/context", body: { units: params.units } });
+ }
+
+ publish(params: PublishParams, options?: ClientRequestOptions): Promise {
+ const body: Record = {
+ units: params.units,
+ hashed: params.hashed,
+ publishedAt: params.publishedAt || Date.now(),
+ sdkVersion: params.sdkVersion,
+ };
+
+ if (Array.isArray(params.goals) && params.goals.length > 0) {
+ body.goals = params.goals;
+ }
+ if (Array.isArray(params.exposures) && params.exposures.length > 0) {
+ body.exposures = params.exposures;
+ }
+ if (Array.isArray(params.attributes) && params.attributes.length > 0) {
+ body.attributes = params.attributes;
+ }
+
+ return this.put({ ...options, path: "/context", body });
+ }
+
+ request(options: ClientRequestOptions): Promise {
+ let url = `${this._opts.endpoint}${options.path}`;
+ if (options.query) {
+ const keys = Object.keys(options.query);
+ if (keys.length > 0) {
+ const encoded = keys
+ .map((k) => (options.query ? `${k}=${encodeURIComponent(options.query[k]!)}` : null))
+ .join("&");
+ url = `${url}?${encoded}`;
+ }
+ }
+
+ const controller = new AbortController();
+
+ const tryOnce = (): Promise => {
+ const opts: RequestInit = {
+ method: options.method,
+ body: options.body !== undefined ? JSON.stringify(options.body, null, 0) : undefined,
+ signal: controller.signal,
+ keepalive: this._opts.keepalive,
+ };
+
+ if (options.auth) {
+ opts.headers = {
+ "Content-Type": "application/json",
+ "X-API-Key": this._opts.apiKey,
+ "X-Agent": this._opts.agent,
+ "X-Environment": this._opts.environment,
+ "X-Application": this._opts.application.name,
+ "X-Application-Version": String(this._opts.application.version),
+ };
+ }
+
+ return fetch(url, opts).then((response: Response) => {
+ if (!response.ok) {
+ const bail = response.status >= 400 && response.status < 500;
+ return response.text().then((text: string) => {
+ const error: Error & { _bail?: boolean } = new Error(
+ text !== null && text.length > 0 ? text : response.statusText,
+ );
+ error._bail = bail;
+ return Promise.reject(error);
+ });
+ }
+ return response.json();
+ });
+ };
+
+ type WaitFn = ((ms: number) => Promise) & { reject?: (reason: AbortError) => void };
+ type TryWithFn = ((retries: number, timeout: number, tries?: number, waited?: number) => Promise) & {
+ timedout?: boolean;
+ };
+
+ const wait: WaitFn = (ms) =>
+ new Promise((resolve, reject) => {
+ const timeoutId = setTimeout(() => {
+ delete wait.reject;
+ resolve();
+ }, ms);
+
+ wait.reject = (reason) => {
+ clearTimeout(timeoutId);
+ reject(reason);
+ };
+ });
+
+ const tryWith: TryWithFn = (retries, timeout, tries = 0, waited = 0) => {
+ delete tryWith.timedout;
+
+ return tryOnce().catch((reason: Error & { _bail?: boolean }) => {
+ if (reason._bail || retries <= 0) throw new Error(reason.message);
+ if (tries >= retries) throw new RetryError(tries, reason, url);
+ if (waited >= timeout || reason.name === "AbortError") {
+ if (tryWith.timedout) throw new TimeoutError(timeout);
+ throw reason;
+ }
+
+ let delay = (1 << tries) * this._delay + 0.5 * Math.random() * this._delay;
+ if (waited + delay > timeout) delay = timeout - waited;
+
+ return wait(delay).then(() => tryWith(retries, timeout, tries + 1, waited + delay));
+ });
+ };
+
+ const abort = () => {
+ if (wait.reject) {
+ wait.reject(new AbortError());
+ } else {
+ controller.abort();
+ }
+ };
+
+ if (options.signal) {
+ options.signal.addEventListener("abort", abort);
+ }
+
+ const timeout = options.timeout || this._opts.timeout || 0;
+ const timeoutId =
+ timeout > 0
+ ? setTimeout(() => {
+ tryWith.timedout = true;
+ abort();
+ }, timeout)
+ : 0;
+
+ const finalCleanUp = () => {
+ clearTimeout(timeoutId);
+ if (options.signal) {
+ options.signal.removeEventListener("abort", abort);
+ }
+ };
+
+ return tryWith(this._opts.retries ?? 5, this._opts.timeout ?? 3000)
+ .then((value) => {
+ finalCleanUp();
+ return value;
+ })
+ .catch((error: Error) => {
+ finalCleanUp();
+ throw error;
+ });
+ }
+
+ post(options: ClientRequestOptions): Promise {
+ return this.request({ ...options, auth: true, method: "POST" });
+ }
+
+ put(options: ClientRequestOptions): Promise {
+ return this.request({ ...options, auth: true, method: "PUT" });
+ }
+
+ getAgent(): string {
+ return this._opts.agent;
+ }
+
+ getApplication(): ApplicationObject {
+ return this._opts.application;
+ }
+
+ getEnvironment(): string {
+ return this._opts.environment;
+ }
+
+ getUnauthed(options: ClientRequestOptions): Promise {
+ return this.request({ ...options, method: "GET" });
+ }
+}
+```
+
+- [ ] **Step 4: Run tests to verify they pass**
+
+Run: `npx vitest run src/__tests__/client.test.ts`
+
+Expected: All tests pass
+
+- [ ] **Step 5: Commit**
+
+```bash
+git add src/client.ts src/__tests__/client.test.ts
+git commit -m "feat: add HTTP client with retry logic and exponential backoff"
+```
+
+---
+
+## Task 12: Provider & Publisher
+
+**Files:**
+- Create: `src/provider.ts`
+- Create: `src/publisher.ts`
+- Create: `src/__tests__/provider.test.ts`
+- Create: `src/__tests__/publisher.test.ts`
+
+- [ ] **Step 1: Write the failing tests for provider**
+
+```typescript
+import { describe, expect, test, vi } from "vitest";
+import { ContextDataProvider } from "../provider";
+
+describe("ContextDataProvider", () => {
+ test("delegates to sdk.getClient().getContext()", async () => {
+ const mockGetContext = vi.fn().mockResolvedValue({ experiments: [] });
+ const mockSdk = { getClient: () => ({ getContext: mockGetContext }) };
+
+ const provider = new ContextDataProvider();
+ const result = await provider.getContextData(mockSdk, { path: "/test" });
+
+ expect(mockGetContext).toHaveBeenCalledWith({ path: "/test" });
+ expect(result).toEqual({ experiments: [] });
+ });
+});
+```
+
+- [ ] **Step 2: Write the failing tests for publisher**
+
+```typescript
+import { describe, expect, test, vi } from "vitest";
+import { ContextPublisher } from "../publisher";
+
+describe("ContextPublisher", () => {
+ test("delegates to sdk.getClient().publish()", async () => {
+ const mockPublish = vi.fn().mockResolvedValue({});
+ const mockSdk = { getClient: () => ({ publish: mockPublish }) };
+ const request = {
+ units: [{ type: "session_id", uid: "abc" }],
+ publishedAt: 1000,
+ hashed: true,
+ sdkVersion: "2.0.0",
+ };
+
+ const publisher = new ContextPublisher();
+ await publisher.publish(request, mockSdk, {}, { path: "/test" });
+
+ expect(mockPublish).toHaveBeenCalledWith(request, { path: "/test" });
+ });
+});
+```
+
+- [ ] **Step 3: Run tests to verify they fail**
+
+Run: `npx vitest run src/__tests__/provider.test.ts src/__tests__/publisher.test.ts`
+
+Expected: FAIL - modules not found
+
+- [ ] **Step 4: Write src/provider.ts**
+
+```typescript
+import type { ClientRequestOptions, ContextData } from "./types";
+
+interface SDKLike {
+ getClient(): { getContext(options?: Partial): Promise };
+}
+
+export class ContextDataProvider {
+ getContextData(sdk: SDKLike, requestOptions?: Partial): Promise {
+ return sdk.getClient().getContext(requestOptions) as Promise;
+ }
+}
+```
+
+- [ ] **Step 5: Write src/publisher.ts**
+
+```typescript
+import type { ClientRequestOptions, PublishParams } from "./types";
+
+interface SDKLike {
+ getClient(): { publish(request: PublishParams, options?: ClientRequestOptions): Promise };
+}
+
+export class ContextPublisher {
+ publish(request: PublishParams, sdk: SDKLike, _context: unknown, requestOptions?: ClientRequestOptions): Promise {
+ return sdk.getClient().publish(request, requestOptions);
+ }
+}
+```
+
+- [ ] **Step 6: Run tests to verify they pass**
+
+Run: `npx vitest run src/__tests__/provider.test.ts src/__tests__/publisher.test.ts`
+
+Expected: All tests pass
+
+- [ ] **Step 7: Commit**
+
+```bash
+git add src/provider.ts src/publisher.ts src/__tests__/provider.test.ts src/__tests__/publisher.test.ts
+git commit -m "feat: add ContextDataProvider and ContextPublisher"
+```
+
+---
+
+## Task 13: Context Class
+
+This is the largest and most complex module. The `Context` class manages experiment assignments, exposure tracking, goal tracking, attribute management, and publish/refresh lifecycle.
+
+**Files:**
+- Create: `src/context.ts`
+- Create: `src/__tests__/context.test.ts`
+
+- [ ] **Step 1: Write the failing tests**
+
+Write comprehensive tests covering all Context functionality. Due to the size of this module, the tests are extensive. The test should cover:
+
+1. Constructor with immediate data vs promise data
+2. `isReady()`, `isFailed()`, `isFinalized()`, `isFinalizing()` state checks
+3. `ready()` promise resolution
+4. `unit()` / `units()` - setting and validating unit identifiers
+5. `attribute()` / `attributes()` - setting user attributes
+6. `treatment()` - variant assignment with exposure tracking
+7. `peek()` - variant assignment without exposure
+8. `track()` - goal tracking
+9. `publish()` - flushing pending events
+10. `refresh()` - fetching updated experiment data
+11. `finalize()` - cleanup and final publish
+12. `variableValue()` / `peekVariableValue()` - experiment variable access
+13. `override()` / `overrides()` - forced variant assignment
+14. `customAssignment()` / `customAssignments()` - custom assignment logic
+15. `customFieldValue()` / `customFieldKeys()` - custom field access
+16. Auto-publish timeout behavior
+17. Refresh interval behavior
+18. Error handling and failed state
+19. System attributes inclusion
+
+The test file should use the same experiment fixture data from the original test suite to ensure byte-level compatibility. Create the file with the complete test content from the original `context.test.js` adapted to Vitest syntax (replace `jest.fn()` with `vi.fn()`, `jest.spyOn` with `vi.spyOn`, etc.).
+
+Run: `npx vitest run src/__tests__/context.test.ts`
+
+Expected: FAIL - module not found
+
+- [ ] **Step 2: Write src/context.ts**
+
+Port the Context class from the original codebase with strict TypeScript types. The implementation must:
+
+- Import types from `./types` instead of declaring locally
+- Import `hashUnit` from `./hashing` instead of `./utils`
+- Import `VariantAssigner` from `./assigner`
+- Import `AudienceMatcher` from `./matcher`
+- Import `insertUniqueSorted` from `./algorithm`
+- Import `arrayEqualsShallow`, `isObject`, `isPromise` from `./utils`
+- Import `SDK_VERSION` from `./version`
+- Use native `setTimeout`/`setInterval`/`clearTimeout`/`clearInterval`
+- Use `structuredClone` in `_buildAttributes` if cloning is needed
+- Maintain identical API: all public methods have the same signatures
+- All private methods prefixed with `_` as in original
+
+The logic must be identical to the original `context.ts` to maintain backward compatibility.
+
+- [ ] **Step 3: Run tests to verify they pass**
+
+Run: `npx vitest run src/__tests__/context.test.ts`
+
+Expected: All tests pass
+
+- [ ] **Step 4: Commit**
+
+```bash
+git add src/context.ts src/__tests__/context.test.ts
+git commit -m "feat: add Context class with experiment assignment and lifecycle management"
+```
+
+---
+
+## Task 14: SDK Class
+
+**Files:**
+- Create: `src/sdk.ts`
+- Create: `src/__tests__/sdk.test.ts`
+
+- [ ] **Step 1: Write the failing tests**
+
+```typescript
+import { describe, expect, test, vi } from "vitest";
+import { SDK } from "../sdk";
+import type { ClientOptions, ContextParams } from "../types";
+
+const defaultOpts: ClientOptions = {
+ agent: "test-agent",
+ apiKey: "test-api-key",
+ application: "test-app",
+ endpoint: "https://test.absmartly.io/v1",
+ environment: "test",
+};
+
+describe("SDK", () => {
+ test("creates SDK instance", () => {
+ const sdk = new SDK(defaultOpts);
+ expect(sdk).toBeInstanceOf(SDK);
+ });
+
+ test("getClient returns client", () => {
+ const sdk = new SDK(defaultOpts);
+ expect(sdk.getClient()).toBeDefined();
+ });
+
+ test("get/set event logger", () => {
+ const sdk = new SDK(defaultOpts);
+ const logger = vi.fn();
+ sdk.setEventLogger(logger);
+ expect(sdk.getEventLogger()).toBe(logger);
+ });
+
+ test("default event logger logs errors", () => {
+ const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => {});
+ const error = new Error("test");
+ SDK.defaultEventLogger({} as never, "error", error);
+ expect(consoleSpy).toHaveBeenCalledWith(error);
+ consoleSpy.mockRestore();
+ });
+
+ test("createContext validates unit types", () => {
+ const sdk = new SDK(defaultOpts);
+ expect(() => sdk.createContext({ units: { session_id: true as unknown as string } })).toThrow(
+ "Unit 'session_id' UID is of unsupported type 'boolean'. UID must be one of ['string', 'number']",
+ );
+ });
+
+ test("createContext validates empty string units", () => {
+ const sdk = new SDK(defaultOpts);
+ expect(() => sdk.createContext({ units: { session_id: "" } })).toThrow(
+ "Unit 'session_id' UID length must be >= 1",
+ );
+ });
+
+ test("createContext returns Context instance", () => {
+ vi.stubGlobal("fetch", vi.fn().mockResolvedValue({ ok: true, json: () => Promise.resolve({ experiments: [] }) }));
+ const sdk = new SDK(defaultOpts);
+ const context = sdk.createContext({ units: { session_id: "abc" } });
+ expect(context).toBeDefined();
+ vi.restoreAllMocks();
+ });
+
+ test("createContextWith accepts pre-fetched data", () => {
+ const sdk = new SDK(defaultOpts);
+ const context = sdk.createContextWith({ units: { session_id: "abc" } }, { experiments: [] });
+ expect(context).toBeDefined();
+ expect(context.isReady()).toBe(true);
+ });
+
+ test("get/set context publisher", () => {
+ const sdk = new SDK(defaultOpts);
+ const publisher = { publish: vi.fn() };
+ sdk.setContextPublisher(publisher as never);
+ expect(sdk.getContextPublisher()).toBe(publisher);
+ });
+
+ test("get/set context data provider", () => {
+ const sdk = new SDK(defaultOpts);
+ const provider = { getContextData: vi.fn() };
+ sdk.setContextDataProvider(provider as never);
+ expect(sdk.getContextDataProvider()).toBe(provider);
+ });
+});
+```
+
+- [ ] **Step 2: Run tests to verify they fail**
+
+Run: `npx vitest run src/__tests__/sdk.test.ts`
+
+Expected: FAIL - module not found
+
+- [ ] **Step 3: Write src/sdk.ts**
+
+```typescript
+import { Client } from "./client";
+import { Context } from "./context";
+import { ContextPublisher } from "./publisher";
+import { ContextDataProvider } from "./provider";
+import type {
+ ClientOptions,
+ ClientRequestOptions,
+ ContextData,
+ ContextOptions,
+ ContextParams,
+ EventLogger,
+ EventLoggerData,
+ EventName,
+ Exposure,
+ Goal,
+ PublishParams,
+ SDKOptions,
+} from "./types";
+
+function isLongLivedApp(): boolean {
+ return (typeof window !== "undefined" && typeof window.document !== "undefined") ||
+ (typeof navigator !== "undefined" && navigator.product === "ReactNative");
+}
+
+const CLIENT_OPTION_KEYS = ["application", "agent", "apiKey", "endpoint", "keepalive", "environment", "retries", "timeout"];
+
+export class SDK {
+ static defaultEventLogger: EventLogger = (_, eventName, data) => {
+ if (eventName === "error") console.error(data);
+ };
+
+ private _eventLogger: EventLogger;
+ private _publisher: ContextPublisher;
+ private _provider: ContextDataProvider;
+ private readonly _client: Client;
+
+ constructor(options: ClientOptions & SDKOptions) {
+ const clientOptions = Object.assign(
+ { agent: "absmartly-javascript-sdk" },
+ ...Object.entries(options || {})
+ .filter((x) => CLIENT_OPTION_KEYS.indexOf(x[0]) !== -1)
+ .map((x) => ({ [x[0]]: x[1] })),
+ ) as ClientOptions;
+
+ this._client = (options.client as Client) || new Client(clientOptions);
+ this._eventLogger = options.eventLogger || SDK.defaultEventLogger;
+ this._publisher = (options.publisher as ContextPublisher) || new ContextPublisher();
+ this._provider = (options.provider as ContextDataProvider) || new ContextDataProvider();
+ }
+
+ getContextData(requestOptions: ClientRequestOptions): Promise {
+ return this._provider.getContextData(this, requestOptions);
+ }
+
+ createContext(
+ params: ContextParams,
+ options?: Partial,
+ requestOptions?: Partial,
+ ): Context {
+ SDK._validateParams(params);
+ const fullOptions = SDK._contextOptions(options);
+ const data = this._provider.getContextData(this, requestOptions);
+ return new Context(this, fullOptions, params, data);
+ }
+
+ createContextWith(
+ params: ContextParams,
+ data: ContextData | Promise,
+ options?: Partial,
+ ): Context {
+ SDK._validateParams(params);
+ const fullOptions = SDK._contextOptions(options);
+ return new Context(this, fullOptions, params, data);
+ }
+
+ setEventLogger(logger: EventLogger): void {
+ this._eventLogger = logger;
+ }
+
+ getEventLogger(): EventLogger {
+ return this._eventLogger;
+ }
+
+ setContextPublisher(publisher: ContextPublisher): void {
+ this._publisher = publisher;
+ }
+
+ getContextPublisher(): ContextPublisher {
+ return this._publisher;
+ }
+
+ setContextDataProvider(provider: ContextDataProvider): void {
+ this._provider = provider;
+ }
+
+ getContextDataProvider(): ContextDataProvider {
+ return this._provider;
+ }
+
+ getClient(): Client {
+ return this._client;
+ }
+
+ private static _contextOptions(options?: Partial): ContextOptions {
+ return Object.assign(
+ { publishDelay: isLongLivedApp() ? 100 : -1, refreshPeriod: 0 },
+ options || {},
+ ) as ContextOptions;
+ }
+
+ private static _validateParams(params: ContextParams): void {
+ for (const [key, value] of Object.entries(params.units)) {
+ const type = typeof value;
+ if (type !== "string" && type !== "number") {
+ throw new Error(`Unit '${key}' UID is of unsupported type '${type}'. UID must be one of ['string', 'number']`);
+ }
+ if (typeof value === "string" && value.length === 0) {
+ throw new Error(`Unit '${key}' UID length must be >= 1`);
+ }
+ }
+ }
+}
+```
+
+- [ ] **Step 4: Run tests to verify they pass**
+
+Run: `npx vitest run src/__tests__/sdk.test.ts`
+
+Expected: All tests pass
+
+- [ ] **Step 5: Commit**
+
+```bash
+git add src/sdk.ts src/__tests__/sdk.test.ts
+git commit -m "feat: add SDK class with context creation and configuration"
+```
+
+---
+
+## Task 15: Config Merge Utility
+
+**Files:**
+- Create: `src/config.ts`
+- Create: `src/__tests__/config.test.ts`
+
+- [ ] **Step 1: Write the failing tests**
+
+```typescript
+import { describe, expect, test, vi } from "vitest";
+import { mergeConfig } from "../config";
+
+function mockContext(variableKeys: Record, variableValues: Record = {}) {
+ return {
+ variableKeys: () => variableKeys,
+ variableValue: (key: string, defaultValue: unknown) =>
+ key in variableValues ? variableValues[key] : defaultValue,
+ };
+}
+
+describe("mergeConfig", () => {
+ test("returns new object, does not mutate original", () => {
+ const original = { key: "value" };
+ const context = mockContext({});
+ const result = mergeConfig(context as never, original);
+ expect(result).not.toBe(original);
+ expect(result).toEqual({ key: "value" });
+ });
+
+ test("creates getter for experiment variable", () => {
+ const context = mockContext(
+ { "button.color": ["exp_test"] },
+ { "button.color": "red" },
+ );
+ const config = { button: { color: "blue" } };
+ const result = mergeConfig(context as never, config);
+ expect(result.button.color).toBe("red");
+ });
+
+ test("falls back to default when variable not set", () => {
+ const context = mockContext({ "button.color": ["exp_test"] });
+ const config = { button: { color: "blue" } };
+ const result = mergeConfig(context as never, config);
+ expect(result.button.color).toBe("blue");
+ });
+});
+```
+
+- [ ] **Step 2: Run tests to verify they fail**
+
+Run: `npx vitest run src/__tests__/config.test.ts`
+
+Expected: FAIL - module not found
+
+- [ ] **Step 3: Write src/config.ts**
+
+```typescript
+import { isObject } from "./utils";
+
+interface ConfigContext {
+ variableKeys(): Record;
+ variableValue(key: string, defaultValue: unknown): unknown;
+}
+
+export function mergeConfig(context: ConfigContext, previousConfig: Record): Record {
+ const merged = structuredClone(previousConfig);
+ const keys = context.variableKeys();
+
+ for (const [variableKey, experimentName] of Object.entries(keys)) {
+ let target: Record | undefined = merged;
+ const frags = variableKey.split(".");
+
+ for (let index = 0; index < frags.length; ++index) {
+ const frag = frags[index]!;
+
+ if (target === undefined) break;
+
+ if (`_${frag}_setter` in target) {
+ console.error(
+ `Config key '${frags.slice(0, index + 1).join(".")}' already set by experiment '${target[`_${frag}_setter`]}'.`,
+ );
+ target = undefined;
+ break;
+ }
+
+ if (frag in target) {
+ if (index < frags.length - 1) {
+ if (!isObject(target[frag])) {
+ console.warn(
+ `Config key '${variableKey}' for experiment '${experimentName}' is overriding non-object value at '${frags.slice(0, index + 1).join(".")}' with an object.`,
+ );
+ target[frag] = {};
+ target = target[frag] as Record;
+ } else {
+ target = target[frag] as Record;
+ }
+ }
+ }
+
+ if (index === frags.length - 1) {
+ const defaultValue = target[frag];
+
+ Object.defineProperty(target, `_${frag}_setter`, { value: experimentName, writable: false });
+ Object.defineProperty(target, frag, {
+ get: () => context.variableValue(variableKey, defaultValue),
+ });
+ }
+ }
+ }
+
+ return merged;
+}
+```
+
+- [ ] **Step 4: Run tests to verify they pass**
+
+Run: `npx vitest run src/__tests__/config.test.ts`
+
+Expected: All tests pass
+
+- [ ] **Step 5: Commit**
+
+```bash
+git add src/config.ts src/__tests__/config.test.ts
+git commit -m "feat: add mergeConfig utility for experiment variable injection"
+```
+
+---
+
+## Task 16: Public API & Index
+
+**Files:**
+- Create: `src/index.ts`
+- Remove: `src/__tests__/placeholder.test.ts`
+
+- [ ] **Step 1: Write src/index.ts**
+
+```typescript
+export { SDK } from "./sdk";
+export { Context } from "./context";
+export { ContextDataProvider } from "./provider";
+export { ContextPublisher } from "./publisher";
+export { mergeConfig } from "./config";
+
+export type {
+ ApplicationObject,
+ Attribute,
+ Assignment,
+ ClientOptions,
+ ClientRequestOptions,
+ ContextData,
+ ContextOptions,
+ ContextParams,
+ CustomFieldValue,
+ CustomFieldValueType,
+ EventLogger,
+ EventLoggerData,
+ EventName,
+ Experiment,
+ ExperimentData,
+ Exposure,
+ Goal,
+ JSONValue,
+ NormalizedClientOptions,
+ PublishParams,
+ SDKOptions,
+ Unit,
+ Units,
+} from "./types";
+```
+
+- [ ] **Step 2: Remove placeholder test**
+
+```bash
+rm -f src/__tests__/placeholder.test.ts
+```
+
+- [ ] **Step 3: Verify full build**
+
+```bash
+npx tsc --noEmit && npx tsup
+```
+
+Expected: Build succeeds, `dist/` contains all output files with correct exports
+
+- [ ] **Step 4: Verify all tests pass**
+
+```bash
+npx vitest run
+```
+
+Expected: All tests across all modules pass
+
+- [ ] **Step 5: Commit**
+
+```bash
+git add -A
+git commit -m "feat: add public API exports and verify complete build"
+```
+
+---
+
+## Task 17: Full Integration & Cleanup
+
+**Files:**
+- Modify: `package.json` (if needed)
+- Remove: any leftover old files
+
+- [ ] **Step 1: Clean up any remaining old files**
+
+```bash
+rm -rf js/ lib/ es/ dist/ types/
+```
+
+Verify no old config files remain.
+
+- [ ] **Step 2: Run full build pipeline**
+
+```bash
+npm run build
+```
+
+Expected: `dist/` contains:
+- `index.js` (ESM)
+- `index.cjs` (CommonJS)
+- `index.global.js` (browser IIFE)
+- `index.d.ts` (TypeScript declarations)
+- `index.d.cts` (CTS declarations)
+
+- [ ] **Step 3: Run full test suite with coverage**
+
+```bash
+npm run test:coverage
+```
+
+Expected: All tests pass with high coverage
+
+- [ ] **Step 4: Verify TypeScript strict mode passes**
+
+```bash
+npx tsc --noEmit
+```
+
+Expected: No type errors
+
+- [ ] **Step 5: Commit**
+
+```bash
+git add -A
+git commit -m "chore: final cleanup and verify full build pipeline"
+```
diff --git a/jest.config.js b/jest.config.js
deleted file mode 100644
index b4c18e5..0000000
--- a/jest.config.js
+++ /dev/null
@@ -1,10 +0,0 @@
-/** @type {import('ts-jest').JestConfigWithTsJest} */
-module.exports = {
- clearMocks: true,
- coverageDirectory: "coverage",
- testEnvironment: "node",
- testRegex: "/__tests__/.*\\.(test|spec)\\.[t|j]sx?$",
- transform: {
- "^.+\\.[t|j]sx?$": ["ts-jest"],
- },
-};
diff --git a/package-lock.json b/package-lock.json
index 163ba5d..e585c7f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,16592 +1,2900 @@
{
- "name": "@absmartly/javascript-sdk",
- "version": "1.13.2",
- "lockfileVersion": 2,
- "requires": true,
- "packages": {
- "": {
- "name": "@absmartly/javascript-sdk",
- "version": "1.13.2",
- "license": "Apache-2.0",
- "dependencies": {
- "core-js": "^3.20.0",
- "node-fetch": "^2.6.7",
- "rfdc": "^1.3.0"
- },
- "devDependencies": {
- "@babel/cli": "^7.17.3",
- "@babel/core": "^7.17.4",
- "@babel/eslint-parser": "^7.17.0",
- "@babel/plugin-proposal-class-properties": "^7.16.7",
- "@babel/plugin-proposal-export-default-from": "^7.16.7",
- "@babel/plugin-proposal-export-namespace-from": "^7.16.7",
- "@babel/plugin-proposal-logical-assignment-operators": "^7.16.7",
- "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.7",
- "@babel/plugin-proposal-numeric-separator": "^7.16.7",
- "@babel/plugin-proposal-optional-chaining": "^7.16.7",
- "@babel/plugin-proposal-throw-expressions": "^7.16.7",
- "@babel/plugin-syntax-dynamic-import": "^7.8.3",
- "@babel/plugin-syntax-import-meta": "^7.10.4",
- "@babel/plugin-transform-runtime": "^7.16.7",
- "@babel/preset-env": "^7.16.11",
- "@babel/preset-typescript": "^7.18.6",
- "@babel/register": "^7.17.0",
- "@types/jest": "^29.2.5",
- "@types/node-fetch": "^2.6.2",
- "@typescript-eslint/eslint-plugin": "^5.48.2",
- "@typescript-eslint/parser": "^5.48.2",
- "babel-jest": "^29",
- "babel-loader": "^8.2.3",
- "eslint": "^7.32.0",
- "eslint-config-prettier": "^7.1.0",
- "jest": "^29.3.1",
- "prettier": "^2.4.1",
- "terser-webpack-plugin": "^5.3.1",
- "ts-jest": "^29.0.5",
- "ts-loader": "^9.4.2",
- "typescript": "^4.9.4",
- "webpack": "^5.60.0",
- "webpack-bundle-analyzer": "^4.5.0",
- "webpack-cli": "^4.9.1"
- },
- "engines": {
- "node": ">=6",
- "npm": ">=3"
- }
- },
- "node_modules/@ampproject/remapping": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz",
- "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==",
- "dev": true,
- "dependencies": {
- "@jridgewell/gen-mapping": "^0.1.0",
- "@jridgewell/trace-mapping": "^0.3.9"
- },
- "engines": {
- "node": ">=6.0.0"
- }
- },
- "node_modules/@babel/cli": {
- "version": "7.20.7",
- "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.20.7.tgz",
- "integrity": "sha512-WylgcELHB66WwQqItxNILsMlaTd8/SO6SgTTjMp4uCI7P4QyH1r3nqgFmO3BfM4AtfniHgFMH3EpYFj/zynBkQ==",
- "dev": true,
- "dependencies": {
- "@jridgewell/trace-mapping": "^0.3.8",
- "commander": "^4.0.1",
- "convert-source-map": "^1.1.0",
- "fs-readdir-recursive": "^1.1.0",
- "glob": "^7.2.0",
- "make-dir": "^2.1.0",
- "slash": "^2.0.0"
- },
- "bin": {
- "babel": "bin/babel.js",
- "babel-external-helpers": "bin/babel-external-helpers.js"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "optionalDependencies": {
- "@nicolo-ribaudo/chokidar-2": "2.1.8-no-fsevents.3",
- "chokidar": "^3.4.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/code-frame": {
- "version": "7.23.4",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.4.tgz",
- "integrity": "sha512-r1IONyb6Ia+jYR2vvIDhdWdlTGhqbBoFqLTQidzZ4kepUFH15ejXvFHxCVbtl7BOXIudsIubf4E81xeA3h3IXA==",
- "dev": true,
- "dependencies": {
- "@babel/highlight": "^7.23.4",
- "chalk": "^2.4.2"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/compat-data": {
- "version": "7.20.10",
- "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.10.tgz",
- "integrity": "sha512-sEnuDPpOJR/fcafHMjpcpGN5M2jbUGUHwmuWKM/YdPzeEDJg8bgmbcWQFUfE32MQjti1koACvoPVsDe8Uq+idg==",
- "dev": true,
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/core": {
- "version": "7.20.7",
- "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.7.tgz",
- "integrity": "sha512-t1ZjCluspe5DW24bn2Rr1CDb2v9rn/hROtg9a2tmd0+QYf4bsloYfLQzjG4qHPNMhWtKdGC33R5AxGR2Af2cBw==",
- "dev": true,
- "dependencies": {
- "@ampproject/remapping": "^2.1.0",
- "@babel/code-frame": "^7.18.6",
- "@babel/generator": "^7.20.7",
- "@babel/helper-compilation-targets": "^7.20.7",
- "@babel/helper-module-transforms": "^7.20.7",
- "@babel/helpers": "^7.20.7",
- "@babel/parser": "^7.20.7",
- "@babel/template": "^7.20.7",
- "@babel/traverse": "^7.20.7",
- "@babel/types": "^7.20.7",
- "convert-source-map": "^1.7.0",
- "debug": "^4.1.0",
- "gensync": "^1.0.0-beta.2",
- "json5": "^2.2.1",
- "semver": "^6.3.0"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/babel"
- }
- },
- "node_modules/@babel/eslint-parser": {
- "version": "7.19.1",
- "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.19.1.tgz",
- "integrity": "sha512-AqNf2QWt1rtu2/1rLswy6CDP7H9Oh3mMhk177Y67Rg8d7RD9WfOLLv8CGn6tisFvS2htm86yIe1yLF6I1UDaGQ==",
- "dev": true,
- "dependencies": {
- "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1",
- "eslint-visitor-keys": "^2.1.0",
- "semver": "^6.3.0"
- },
- "engines": {
- "node": "^10.13.0 || ^12.13.0 || >=14.0.0"
- },
- "peerDependencies": {
- "@babel/core": ">=7.11.0",
- "eslint": "^7.5.0 || ^8.0.0"
- }
- },
- "node_modules/@babel/generator": {
- "version": "7.23.4",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.4.tgz",
- "integrity": "sha512-esuS49Cga3HcThFNebGhlgsrVLkvhqvYDTzgjfFFlHJcIfLe5jFmRRfCQ1KuBfc4Jrtn3ndLgKWAKjBE+IraYQ==",
- "dev": true,
- "dependencies": {
- "@babel/types": "^7.23.4",
- "@jridgewell/gen-mapping": "^0.3.2",
- "@jridgewell/trace-mapping": "^0.3.17",
- "jsesc": "^2.5.1"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz",
- "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==",
- "dev": true,
- "dependencies": {
- "@jridgewell/set-array": "^1.0.1",
- "@jridgewell/sourcemap-codec": "^1.4.10",
- "@jridgewell/trace-mapping": "^0.3.9"
- },
- "engines": {
- "node": ">=6.0.0"
- }
- },
- "node_modules/@babel/helper-annotate-as-pure": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz",
- "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==",
- "dev": true,
- "dependencies": {
- "@babel/types": "^7.18.6"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": {
- "version": "7.18.9",
- "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz",
- "integrity": "sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==",
- "dev": true,
- "dependencies": {
- "@babel/helper-explode-assignable-expression": "^7.18.6",
- "@babel/types": "^7.18.9"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-compilation-targets": {
- "version": "7.20.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz",
- "integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==",
- "dev": true,
- "dependencies": {
- "@babel/compat-data": "^7.20.5",
- "@babel/helper-validator-option": "^7.18.6",
- "browserslist": "^4.21.3",
- "lru-cache": "^5.1.1",
- "semver": "^6.3.0"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0"
- }
- },
- "node_modules/@babel/helper-create-class-features-plugin": {
- "version": "7.20.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.20.7.tgz",
- "integrity": "sha512-LtoWbDXOaidEf50hmdDqn9g8VEzsorMexoWMQdQODbvmqYmaF23pBP5VNPAGIFHsFQCIeKokDiz3CH5Y2jlY6w==",
- "dev": true,
- "dependencies": {
- "@babel/helper-annotate-as-pure": "^7.18.6",
- "@babel/helper-environment-visitor": "^7.18.9",
- "@babel/helper-function-name": "^7.19.0",
- "@babel/helper-member-expression-to-functions": "^7.20.7",
- "@babel/helper-optimise-call-expression": "^7.18.6",
- "@babel/helper-replace-supers": "^7.20.7",
- "@babel/helper-split-export-declaration": "^7.18.6"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0"
- }
- },
- "node_modules/@babel/helper-create-regexp-features-plugin": {
- "version": "7.20.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.20.5.tgz",
- "integrity": "sha512-m68B1lkg3XDGX5yCvGO0kPx3v9WIYLnzjKfPcQiwntEQa5ZeRkPmo2X/ISJc8qxWGfwUr+kvZAeEzAwLec2r2w==",
- "dev": true,
- "dependencies": {
- "@babel/helper-annotate-as-pure": "^7.18.6",
- "regexpu-core": "^5.2.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0"
- }
- },
- "node_modules/@babel/helper-define-polyfill-provider": {
- "version": "0.3.3",
- "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz",
- "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==",
- "dev": true,
- "dependencies": {
- "@babel/helper-compilation-targets": "^7.17.7",
- "@babel/helper-plugin-utils": "^7.16.7",
- "debug": "^4.1.1",
- "lodash.debounce": "^4.0.8",
- "resolve": "^1.14.2",
- "semver": "^6.1.2"
- },
- "peerDependencies": {
- "@babel/core": "^7.4.0-0"
- }
- },
- "node_modules/@babel/helper-environment-visitor": {
- "version": "7.22.20",
- "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz",
- "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==",
- "dev": true,
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-explode-assignable-expression": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz",
- "integrity": "sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==",
- "dev": true,
- "dependencies": {
- "@babel/types": "^7.18.6"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-function-name": {
- "version": "7.23.0",
- "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz",
- "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==",
- "dev": true,
- "dependencies": {
- "@babel/template": "^7.22.15",
- "@babel/types": "^7.23.0"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-hoist-variables": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz",
- "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==",
- "dev": true,
- "dependencies": {
- "@babel/types": "^7.22.5"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-member-expression-to-functions": {
- "version": "7.20.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.20.7.tgz",
- "integrity": "sha512-9J0CxJLq315fEdi4s7xK5TQaNYjZw+nDVpVqr1axNGKzdrdwYBD5b4uKv3n75aABG0rCCTK8Im8Ww7eYfMrZgw==",
- "dev": true,
- "dependencies": {
- "@babel/types": "^7.20.7"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-module-imports": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz",
- "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==",
- "dev": true,
- "dependencies": {
- "@babel/types": "^7.18.6"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-module-transforms": {
- "version": "7.20.11",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.11.tgz",
- "integrity": "sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==",
- "dev": true,
- "dependencies": {
- "@babel/helper-environment-visitor": "^7.18.9",
- "@babel/helper-module-imports": "^7.18.6",
- "@babel/helper-simple-access": "^7.20.2",
- "@babel/helper-split-export-declaration": "^7.18.6",
- "@babel/helper-validator-identifier": "^7.19.1",
- "@babel/template": "^7.20.7",
- "@babel/traverse": "^7.20.10",
- "@babel/types": "^7.20.7"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-optimise-call-expression": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz",
- "integrity": "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==",
- "dev": true,
- "dependencies": {
- "@babel/types": "^7.18.6"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-plugin-utils": {
- "version": "7.20.2",
- "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz",
- "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==",
- "dev": true,
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-remap-async-to-generator": {
- "version": "7.18.9",
- "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz",
- "integrity": "sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==",
- "dev": true,
- "dependencies": {
- "@babel/helper-annotate-as-pure": "^7.18.6",
- "@babel/helper-environment-visitor": "^7.18.9",
- "@babel/helper-wrap-function": "^7.18.9",
- "@babel/types": "^7.18.9"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0"
- }
- },
- "node_modules/@babel/helper-replace-supers": {
- "version": "7.20.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.20.7.tgz",
- "integrity": "sha512-vujDMtB6LVfNW13jhlCrp48QNslK6JXi7lQG736HVbHz/mbf4Dc7tIRh1Xf5C0rF7BP8iiSxGMCmY6Ci1ven3A==",
- "dev": true,
- "dependencies": {
- "@babel/helper-environment-visitor": "^7.18.9",
- "@babel/helper-member-expression-to-functions": "^7.20.7",
- "@babel/helper-optimise-call-expression": "^7.18.6",
- "@babel/template": "^7.20.7",
- "@babel/traverse": "^7.20.7",
- "@babel/types": "^7.20.7"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-simple-access": {
- "version": "7.20.2",
- "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz",
- "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==",
- "dev": true,
- "dependencies": {
- "@babel/types": "^7.20.2"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-skip-transparent-expression-wrappers": {
- "version": "7.20.0",
- "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.20.0.tgz",
- "integrity": "sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg==",
- "dev": true,
- "dependencies": {
- "@babel/types": "^7.20.0"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-split-export-declaration": {
- "version": "7.22.6",
- "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz",
- "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==",
- "dev": true,
- "dependencies": {
- "@babel/types": "^7.22.5"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-string-parser": {
- "version": "7.23.4",
- "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz",
- "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==",
- "dev": true,
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-validator-identifier": {
- "version": "7.22.20",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
- "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
- "dev": true,
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-validator-option": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz",
- "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==",
- "dev": true,
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helper-wrap-function": {
- "version": "7.20.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.20.5.tgz",
- "integrity": "sha512-bYMxIWK5mh+TgXGVqAtnu5Yn1un+v8DDZtqyzKRLUzrh70Eal2O3aZ7aPYiMADO4uKlkzOiRiZ6GX5q3qxvW9Q==",
- "dev": true,
- "dependencies": {
- "@babel/helper-function-name": "^7.19.0",
- "@babel/template": "^7.18.10",
- "@babel/traverse": "^7.20.5",
- "@babel/types": "^7.20.5"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/helpers": {
- "version": "7.20.7",
- "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.7.tgz",
- "integrity": "sha512-PBPjs5BppzsGaxHQCDKnZ6Gd9s6xl8bBCluz3vEInLGRJmnZan4F6BYCeqtyXqkk4W5IlPmjK4JlOuZkpJ3xZA==",
- "dev": true,
- "dependencies": {
- "@babel/template": "^7.20.7",
- "@babel/traverse": "^7.20.7",
- "@babel/types": "^7.20.7"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/highlight": {
- "version": "7.23.4",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz",
- "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==",
- "dev": true,
- "dependencies": {
- "@babel/helper-validator-identifier": "^7.22.20",
- "chalk": "^2.4.2",
- "js-tokens": "^4.0.0"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/parser": {
- "version": "7.23.4",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.4.tgz",
- "integrity": "sha512-vf3Xna6UEprW+7t6EtOmFpHNAuxw3xqPZghy+brsnusscJRW5BMUzzHZc5ICjULee81WeUV2jjakG09MDglJXQ==",
- "dev": true,
- "bin": {
- "parser": "bin/babel-parser.js"
- },
- "engines": {
- "node": ">=6.0.0"
- }
- },
- "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz",
- "integrity": "sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.18.6"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0"
- }
- },
- "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": {
- "version": "7.20.7",
- "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.20.7.tgz",
- "integrity": "sha512-sbr9+wNE5aXMBBFBICk01tt7sBf2Oc9ikRFEcem/ZORup9IMUdNhW7/wVLEbbtlWOsEubJet46mHAL2C8+2jKQ==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.20.2",
- "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0",
- "@babel/plugin-proposal-optional-chaining": "^7.20.7"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.13.0"
- }
- },
- "node_modules/@babel/plugin-proposal-async-generator-functions": {
- "version": "7.20.7",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.7.tgz",
- "integrity": "sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA==",
- "dev": true,
- "dependencies": {
- "@babel/helper-environment-visitor": "^7.18.9",
- "@babel/helper-plugin-utils": "^7.20.2",
- "@babel/helper-remap-async-to-generator": "^7.18.9",
- "@babel/plugin-syntax-async-generators": "^7.8.4"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-proposal-class-properties": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz",
- "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==",
- "dev": true,
- "dependencies": {
- "@babel/helper-create-class-features-plugin": "^7.18.6",
- "@babel/helper-plugin-utils": "^7.18.6"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-proposal-class-static-block": {
- "version": "7.20.7",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.20.7.tgz",
- "integrity": "sha512-AveGOoi9DAjUYYuUAG//Ig69GlazLnoyzMw68VCDux+c1tsnnH/OkYcpz/5xzMkEFC6UxjR5Gw1c+iY2wOGVeQ==",
- "dev": true,
- "dependencies": {
- "@babel/helper-create-class-features-plugin": "^7.20.7",
- "@babel/helper-plugin-utils": "^7.20.2",
- "@babel/plugin-syntax-class-static-block": "^7.14.5"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.12.0"
- }
- },
- "node_modules/@babel/plugin-proposal-dynamic-import": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz",
- "integrity": "sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.18.6",
- "@babel/plugin-syntax-dynamic-import": "^7.8.3"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-proposal-export-default-from": {
- "version": "7.18.10",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.18.10.tgz",
- "integrity": "sha512-5H2N3R2aQFxkV4PIBUR/i7PUSwgTZjouJKzI8eKswfIjT0PhvzkPn0t0wIS5zn6maQuvtT0t1oHtMUz61LOuow==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.18.9",
- "@babel/plugin-syntax-export-default-from": "^7.18.6"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-proposal-export-namespace-from": {
- "version": "7.18.9",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz",
- "integrity": "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.18.9",
- "@babel/plugin-syntax-export-namespace-from": "^7.8.3"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-proposal-json-strings": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz",
- "integrity": "sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.18.6",
- "@babel/plugin-syntax-json-strings": "^7.8.3"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-proposal-logical-assignment-operators": {
- "version": "7.20.7",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.20.7.tgz",
- "integrity": "sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.20.2",
- "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz",
- "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.18.6",
- "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-proposal-numeric-separator": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz",
- "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.18.6",
- "@babel/plugin-syntax-numeric-separator": "^7.10.4"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-proposal-object-rest-spread": {
- "version": "7.20.7",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz",
- "integrity": "sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==",
- "dev": true,
- "dependencies": {
- "@babel/compat-data": "^7.20.5",
- "@babel/helper-compilation-targets": "^7.20.7",
- "@babel/helper-plugin-utils": "^7.20.2",
- "@babel/plugin-syntax-object-rest-spread": "^7.8.3",
- "@babel/plugin-transform-parameters": "^7.20.7"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-proposal-optional-catch-binding": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz",
- "integrity": "sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.18.6",
- "@babel/plugin-syntax-optional-catch-binding": "^7.8.3"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-proposal-optional-chaining": {
- "version": "7.20.7",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.20.7.tgz",
- "integrity": "sha512-T+A7b1kfjtRM51ssoOfS1+wbyCVqorfyZhT99TvxxLMirPShD8CzKMRepMlCBGM5RpHMbn8s+5MMHnPstJH6mQ==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.20.2",
- "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0",
- "@babel/plugin-syntax-optional-chaining": "^7.8.3"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-proposal-private-methods": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz",
- "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==",
- "dev": true,
- "dependencies": {
- "@babel/helper-create-class-features-plugin": "^7.18.6",
- "@babel/helper-plugin-utils": "^7.18.6"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-proposal-private-property-in-object": {
- "version": "7.20.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.20.5.tgz",
- "integrity": "sha512-Vq7b9dUA12ByzB4EjQTPo25sFhY+08pQDBSZRtUAkj7lb7jahaHR5igera16QZ+3my1nYR4dKsNdYj5IjPHilQ==",
- "dev": true,
- "dependencies": {
- "@babel/helper-annotate-as-pure": "^7.18.6",
- "@babel/helper-create-class-features-plugin": "^7.20.5",
- "@babel/helper-plugin-utils": "^7.20.2",
- "@babel/plugin-syntax-private-property-in-object": "^7.14.5"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-proposal-throw-expressions": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-throw-expressions/-/plugin-proposal-throw-expressions-7.18.6.tgz",
- "integrity": "sha512-WHOrJyhGoGrdtW480L79cF7Iq/gZDZ/z6OqK7mVyFR5I37dTpog/wNgb6hmaM3HYZtULEJl++7VaMWkNZsOcHg==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.18.6",
- "@babel/plugin-syntax-throw-expressions": "^7.18.6"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-proposal-unicode-property-regex": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz",
- "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==",
- "dev": true,
- "dependencies": {
- "@babel/helper-create-regexp-features-plugin": "^7.18.6",
- "@babel/helper-plugin-utils": "^7.18.6"
- },
- "engines": {
- "node": ">=4"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-syntax-async-generators": {
- "version": "7.8.4",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz",
- "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.8.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-syntax-bigint": {
- "version": "7.8.3",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz",
- "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.8.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-syntax-class-properties": {
- "version": "7.12.13",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz",
- "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.12.13"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-syntax-class-static-block": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz",
- "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.14.5"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-syntax-dynamic-import": {
- "version": "7.8.3",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz",
- "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.8.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-syntax-export-default-from": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-default-from/-/plugin-syntax-export-default-from-7.18.6.tgz",
- "integrity": "sha512-Kr//z3ujSVNx6E9z9ih5xXXMqK07VVTuqPmqGe6Mss/zW5XPeLZeSDZoP9ab/hT4wPKqAgjl2PnhPrcpk8Seew==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.18.6"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-syntax-export-namespace-from": {
- "version": "7.8.3",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz",
- "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.8.3"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-syntax-import-assertions": {
- "version": "7.20.0",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.20.0.tgz",
- "integrity": "sha512-IUh1vakzNoWalR8ch/areW7qFopR2AEw03JlG7BbrDqmQ4X3q9uuipQwSGrUn7oGiemKjtSLDhNtQHzMHr1JdQ==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.19.0"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-syntax-import-meta": {
- "version": "7.10.4",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz",
- "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.10.4"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-syntax-json-strings": {
- "version": "7.8.3",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz",
- "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.8.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-syntax-jsx": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz",
- "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.18.6"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-syntax-logical-assignment-operators": {
- "version": "7.10.4",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz",
- "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.10.4"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": {
- "version": "7.8.3",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz",
- "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.8.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-syntax-numeric-separator": {
- "version": "7.10.4",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz",
- "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.10.4"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-syntax-object-rest-spread": {
- "version": "7.8.3",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz",
- "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.8.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-syntax-optional-catch-binding": {
- "version": "7.8.3",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz",
- "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.8.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-syntax-optional-chaining": {
- "version": "7.8.3",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz",
- "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.8.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-syntax-private-property-in-object": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz",
- "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.14.5"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-syntax-throw-expressions": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-throw-expressions/-/plugin-syntax-throw-expressions-7.18.6.tgz",
- "integrity": "sha512-rp1CqEZXGv1z1YZ3qYffBH3rhnOxrTwQG8fh2yqulTurwv9zu3Gthfd+niZBLSOi1rY6146TgF+JmVeDXaX4TQ==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.18.6"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-syntax-top-level-await": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz",
- "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.14.5"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-syntax-typescript": {
- "version": "7.20.0",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.20.0.tgz",
- "integrity": "sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.19.0"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-arrow-functions": {
- "version": "7.20.7",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.20.7.tgz",
- "integrity": "sha512-3poA5E7dzDomxj9WXWwuD6A5F3kc7VXwIJO+E+J8qtDtS+pXPAhrgEyh+9GBwBgPq1Z+bB+/JD60lp5jsN7JPQ==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.20.2"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-async-to-generator": {
- "version": "7.20.7",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.20.7.tgz",
- "integrity": "sha512-Uo5gwHPT9vgnSXQxqGtpdufUiWp96gk7yiP4Mp5bm1QMkEmLXBO7PAGYbKoJ6DhAwiNkcHFBol/x5zZZkL/t0Q==",
- "dev": true,
- "dependencies": {
- "@babel/helper-module-imports": "^7.18.6",
- "@babel/helper-plugin-utils": "^7.20.2",
- "@babel/helper-remap-async-to-generator": "^7.18.9"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-block-scoped-functions": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz",
- "integrity": "sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.18.6"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-block-scoping": {
- "version": "7.20.11",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.20.11.tgz",
- "integrity": "sha512-tA4N427a7fjf1P0/2I4ScsHGc5jcHPbb30xMbaTke2gxDuWpUfXDuX1FEymJwKk4tuGUvGcejAR6HdZVqmmPyw==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.20.2"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-classes": {
- "version": "7.20.7",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.20.7.tgz",
- "integrity": "sha512-LWYbsiXTPKl+oBlXUGlwNlJZetXD5Am+CyBdqhPsDVjM9Jc8jwBJFrKhHf900Kfk2eZG1y9MAG3UNajol7A4VQ==",
- "dev": true,
- "dependencies": {
- "@babel/helper-annotate-as-pure": "^7.18.6",
- "@babel/helper-compilation-targets": "^7.20.7",
- "@babel/helper-environment-visitor": "^7.18.9",
- "@babel/helper-function-name": "^7.19.0",
- "@babel/helper-optimise-call-expression": "^7.18.6",
- "@babel/helper-plugin-utils": "^7.20.2",
- "@babel/helper-replace-supers": "^7.20.7",
- "@babel/helper-split-export-declaration": "^7.18.6",
- "globals": "^11.1.0"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-computed-properties": {
- "version": "7.20.7",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.20.7.tgz",
- "integrity": "sha512-Lz7MvBK6DTjElHAmfu6bfANzKcxpyNPeYBGEafyA6E5HtRpjpZwU+u7Qrgz/2OR0z+5TvKYbPdphfSaAcZBrYQ==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.20.2",
- "@babel/template": "^7.20.7"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-destructuring": {
- "version": "7.20.7",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.20.7.tgz",
- "integrity": "sha512-Xwg403sRrZb81IVB79ZPqNQME23yhugYVqgTxAhT99h485F4f+GMELFhhOsscDUB7HCswepKeCKLn/GZvUKoBA==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.20.2"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-dotall-regex": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz",
- "integrity": "sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==",
- "dev": true,
- "dependencies": {
- "@babel/helper-create-regexp-features-plugin": "^7.18.6",
- "@babel/helper-plugin-utils": "^7.18.6"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-duplicate-keys": {
- "version": "7.18.9",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz",
- "integrity": "sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.18.9"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-exponentiation-operator": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz",
- "integrity": "sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==",
- "dev": true,
- "dependencies": {
- "@babel/helper-builder-binary-assignment-operator-visitor": "^7.18.6",
- "@babel/helper-plugin-utils": "^7.18.6"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-for-of": {
- "version": "7.18.8",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz",
- "integrity": "sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.18.6"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-function-name": {
- "version": "7.18.9",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz",
- "integrity": "sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==",
- "dev": true,
- "dependencies": {
- "@babel/helper-compilation-targets": "^7.18.9",
- "@babel/helper-function-name": "^7.18.9",
- "@babel/helper-plugin-utils": "^7.18.9"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-literals": {
- "version": "7.18.9",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz",
- "integrity": "sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.18.9"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-member-expression-literals": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz",
- "integrity": "sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.18.6"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-modules-amd": {
- "version": "7.20.11",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.20.11.tgz",
- "integrity": "sha512-NuzCt5IIYOW0O30UvqktzHYR2ud5bOWbY0yaxWZ6G+aFzOMJvrs5YHNikrbdaT15+KNO31nPOy5Fim3ku6Zb5g==",
- "dev": true,
- "dependencies": {
- "@babel/helper-module-transforms": "^7.20.11",
- "@babel/helper-plugin-utils": "^7.20.2"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-modules-commonjs": {
- "version": "7.20.11",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.20.11.tgz",
- "integrity": "sha512-S8e1f7WQ7cimJQ51JkAaDrEtohVEitXjgCGAS2N8S31Y42E+kWwfSz83LYz57QdBm7q9diARVqanIaH2oVgQnw==",
- "dev": true,
- "dependencies": {
- "@babel/helper-module-transforms": "^7.20.11",
- "@babel/helper-plugin-utils": "^7.20.2",
- "@babel/helper-simple-access": "^7.20.2"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-modules-systemjs": {
- "version": "7.20.11",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.20.11.tgz",
- "integrity": "sha512-vVu5g9BPQKSFEmvt2TA4Da5N+QVS66EX21d8uoOihC+OCpUoGvzVsXeqFdtAEfVa5BILAeFt+U7yVmLbQnAJmw==",
- "dev": true,
- "dependencies": {
- "@babel/helper-hoist-variables": "^7.18.6",
- "@babel/helper-module-transforms": "^7.20.11",
- "@babel/helper-plugin-utils": "^7.20.2",
- "@babel/helper-validator-identifier": "^7.19.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-modules-umd": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz",
- "integrity": "sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==",
- "dev": true,
- "dependencies": {
- "@babel/helper-module-transforms": "^7.18.6",
- "@babel/helper-plugin-utils": "^7.18.6"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-named-capturing-groups-regex": {
- "version": "7.20.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.20.5.tgz",
- "integrity": "sha512-mOW4tTzi5iTLnw+78iEq3gr8Aoq4WNRGpmSlrogqaiCBoR1HFhpU4JkpQFOHfeYx3ReVIFWOQJS4aZBRvuZ6mA==",
- "dev": true,
- "dependencies": {
- "@babel/helper-create-regexp-features-plugin": "^7.20.5",
- "@babel/helper-plugin-utils": "^7.20.2"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0"
- }
- },
- "node_modules/@babel/plugin-transform-new-target": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz",
- "integrity": "sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.18.6"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-object-super": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz",
- "integrity": "sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.18.6",
- "@babel/helper-replace-supers": "^7.18.6"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-parameters": {
- "version": "7.20.7",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.20.7.tgz",
- "integrity": "sha512-WiWBIkeHKVOSYPO0pWkxGPfKeWrCJyD3NJ53+Lrp/QMSZbsVPovrVl2aWZ19D/LTVnaDv5Ap7GJ/B2CTOZdrfA==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.20.2"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-property-literals": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz",
- "integrity": "sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.18.6"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-regenerator": {
- "version": "7.20.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.20.5.tgz",
- "integrity": "sha512-kW/oO7HPBtntbsahzQ0qSE3tFvkFwnbozz3NWFhLGqH75vLEg+sCGngLlhVkePlCs3Jv0dBBHDzCHxNiFAQKCQ==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.20.2",
- "regenerator-transform": "^0.15.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-reserved-words": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz",
- "integrity": "sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.18.6"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-runtime": {
- "version": "7.19.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.19.6.tgz",
- "integrity": "sha512-PRH37lz4JU156lYFW1p8OxE5i7d6Sl/zV58ooyr+q1J1lnQPyg5tIiXlIwNVhJaY4W3TmOtdc8jqdXQcB1v5Yw==",
- "dev": true,
- "dependencies": {
- "@babel/helper-module-imports": "^7.18.6",
- "@babel/helper-plugin-utils": "^7.19.0",
- "babel-plugin-polyfill-corejs2": "^0.3.3",
- "babel-plugin-polyfill-corejs3": "^0.6.0",
- "babel-plugin-polyfill-regenerator": "^0.4.1",
- "semver": "^6.3.0"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-shorthand-properties": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz",
- "integrity": "sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.18.6"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-spread": {
- "version": "7.20.7",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.20.7.tgz",
- "integrity": "sha512-ewBbHQ+1U/VnH1fxltbJqDeWBU1oNLG8Dj11uIv3xVf7nrQu0bPGe5Rf716r7K5Qz+SqtAOVswoVunoiBtGhxw==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.20.2",
- "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-sticky-regex": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz",
- "integrity": "sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.18.6"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-template-literals": {
- "version": "7.18.9",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz",
- "integrity": "sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.18.9"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-typeof-symbol": {
- "version": "7.18.9",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz",
- "integrity": "sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.18.9"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-typescript": {
- "version": "7.20.7",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.20.7.tgz",
- "integrity": "sha512-m3wVKEvf6SoszD8pu4NZz3PvfKRCMgk6D6d0Qi9hNnlM5M6CFS92EgF4EiHVLKbU0r/r7ty1hg7NPZwE7WRbYw==",
- "dev": true,
- "dependencies": {
- "@babel/helper-create-class-features-plugin": "^7.20.7",
- "@babel/helper-plugin-utils": "^7.20.2",
- "@babel/plugin-syntax-typescript": "^7.20.0"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-unicode-escapes": {
- "version": "7.18.10",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz",
- "integrity": "sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.18.9"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-unicode-regex": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz",
- "integrity": "sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==",
- "dev": true,
- "dependencies": {
- "@babel/helper-create-regexp-features-plugin": "^7.18.6",
- "@babel/helper-plugin-utils": "^7.18.6"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/preset-env": {
- "version": "7.20.2",
- "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.20.2.tgz",
- "integrity": "sha512-1G0efQEWR1EHkKvKHqbG+IN/QdgwfByUpM5V5QroDzGV2t3S/WXNQd693cHiHTlCFMpr9B6FkPFXDA2lQcKoDg==",
- "dev": true,
- "dependencies": {
- "@babel/compat-data": "^7.20.1",
- "@babel/helper-compilation-targets": "^7.20.0",
- "@babel/helper-plugin-utils": "^7.20.2",
- "@babel/helper-validator-option": "^7.18.6",
- "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6",
- "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.9",
- "@babel/plugin-proposal-async-generator-functions": "^7.20.1",
- "@babel/plugin-proposal-class-properties": "^7.18.6",
- "@babel/plugin-proposal-class-static-block": "^7.18.6",
- "@babel/plugin-proposal-dynamic-import": "^7.18.6",
- "@babel/plugin-proposal-export-namespace-from": "^7.18.9",
- "@babel/plugin-proposal-json-strings": "^7.18.6",
- "@babel/plugin-proposal-logical-assignment-operators": "^7.18.9",
- "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6",
- "@babel/plugin-proposal-numeric-separator": "^7.18.6",
- "@babel/plugin-proposal-object-rest-spread": "^7.20.2",
- "@babel/plugin-proposal-optional-catch-binding": "^7.18.6",
- "@babel/plugin-proposal-optional-chaining": "^7.18.9",
- "@babel/plugin-proposal-private-methods": "^7.18.6",
- "@babel/plugin-proposal-private-property-in-object": "^7.18.6",
- "@babel/plugin-proposal-unicode-property-regex": "^7.18.6",
- "@babel/plugin-syntax-async-generators": "^7.8.4",
- "@babel/plugin-syntax-class-properties": "^7.12.13",
- "@babel/plugin-syntax-class-static-block": "^7.14.5",
- "@babel/plugin-syntax-dynamic-import": "^7.8.3",
- "@babel/plugin-syntax-export-namespace-from": "^7.8.3",
- "@babel/plugin-syntax-import-assertions": "^7.20.0",
- "@babel/plugin-syntax-json-strings": "^7.8.3",
- "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4",
- "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3",
- "@babel/plugin-syntax-numeric-separator": "^7.10.4",
- "@babel/plugin-syntax-object-rest-spread": "^7.8.3",
- "@babel/plugin-syntax-optional-catch-binding": "^7.8.3",
- "@babel/plugin-syntax-optional-chaining": "^7.8.3",
- "@babel/plugin-syntax-private-property-in-object": "^7.14.5",
- "@babel/plugin-syntax-top-level-await": "^7.14.5",
- "@babel/plugin-transform-arrow-functions": "^7.18.6",
- "@babel/plugin-transform-async-to-generator": "^7.18.6",
- "@babel/plugin-transform-block-scoped-functions": "^7.18.6",
- "@babel/plugin-transform-block-scoping": "^7.20.2",
- "@babel/plugin-transform-classes": "^7.20.2",
- "@babel/plugin-transform-computed-properties": "^7.18.9",
- "@babel/plugin-transform-destructuring": "^7.20.2",
- "@babel/plugin-transform-dotall-regex": "^7.18.6",
- "@babel/plugin-transform-duplicate-keys": "^7.18.9",
- "@babel/plugin-transform-exponentiation-operator": "^7.18.6",
- "@babel/plugin-transform-for-of": "^7.18.8",
- "@babel/plugin-transform-function-name": "^7.18.9",
- "@babel/plugin-transform-literals": "^7.18.9",
- "@babel/plugin-transform-member-expression-literals": "^7.18.6",
- "@babel/plugin-transform-modules-amd": "^7.19.6",
- "@babel/plugin-transform-modules-commonjs": "^7.19.6",
- "@babel/plugin-transform-modules-systemjs": "^7.19.6",
- "@babel/plugin-transform-modules-umd": "^7.18.6",
- "@babel/plugin-transform-named-capturing-groups-regex": "^7.19.1",
- "@babel/plugin-transform-new-target": "^7.18.6",
- "@babel/plugin-transform-object-super": "^7.18.6",
- "@babel/plugin-transform-parameters": "^7.20.1",
- "@babel/plugin-transform-property-literals": "^7.18.6",
- "@babel/plugin-transform-regenerator": "^7.18.6",
- "@babel/plugin-transform-reserved-words": "^7.18.6",
- "@babel/plugin-transform-shorthand-properties": "^7.18.6",
- "@babel/plugin-transform-spread": "^7.19.0",
- "@babel/plugin-transform-sticky-regex": "^7.18.6",
- "@babel/plugin-transform-template-literals": "^7.18.9",
- "@babel/plugin-transform-typeof-symbol": "^7.18.9",
- "@babel/plugin-transform-unicode-escapes": "^7.18.10",
- "@babel/plugin-transform-unicode-regex": "^7.18.6",
- "@babel/preset-modules": "^0.1.5",
- "@babel/types": "^7.20.2",
- "babel-plugin-polyfill-corejs2": "^0.3.3",
- "babel-plugin-polyfill-corejs3": "^0.6.0",
- "babel-plugin-polyfill-regenerator": "^0.4.1",
- "core-js-compat": "^3.25.1",
- "semver": "^6.3.0"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/preset-modules": {
- "version": "0.1.5",
- "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz",
- "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.0.0",
- "@babel/plugin-proposal-unicode-property-regex": "^7.4.4",
- "@babel/plugin-transform-dotall-regex": "^7.4.4",
- "@babel/types": "^7.4.4",
- "esutils": "^2.0.2"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/preset-typescript": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.18.6.tgz",
- "integrity": "sha512-s9ik86kXBAnD760aybBucdpnLsAt0jK1xqJn2juOn9lkOvSHV60os5hxoVJsPzMQxvnUJFAlkont2DvvaYEBtQ==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.18.6",
- "@babel/helper-validator-option": "^7.18.6",
- "@babel/plugin-transform-typescript": "^7.18.6"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/register": {
- "version": "7.18.9",
- "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.18.9.tgz",
- "integrity": "sha512-ZlbnXDcNYHMR25ITwwNKT88JiaukkdVj/nG7r3wnuXkOTHc60Uy05PwMCPre0hSkY68E6zK3xz+vUJSP2jWmcw==",
- "dev": true,
- "dependencies": {
- "clone-deep": "^4.0.1",
- "find-cache-dir": "^2.0.0",
- "make-dir": "^2.1.0",
- "pirates": "^4.0.5",
- "source-map-support": "^0.5.16"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/runtime": {
- "version": "7.20.7",
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.7.tgz",
- "integrity": "sha512-UF0tvkUtxwAgZ5W/KrkHf0Rn0fdnLDU9ScxBrEVNUprE/MzirjK4MJUX1/BVDv00Sv8cljtukVK1aky++X1SjQ==",
- "dev": true,
- "dependencies": {
- "regenerator-runtime": "^0.13.11"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/template": {
- "version": "7.22.15",
- "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz",
- "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==",
- "dev": true,
- "dependencies": {
- "@babel/code-frame": "^7.22.13",
- "@babel/parser": "^7.22.15",
- "@babel/types": "^7.22.15"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/traverse": {
- "version": "7.23.4",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.4.tgz",
- "integrity": "sha512-IYM8wSUwunWTB6tFC2dkKZhxbIjHoWemdK+3f8/wq8aKhbUscxD5MX72ubd90fxvFknaLPeGw5ycU84V1obHJg==",
- "dev": true,
- "dependencies": {
- "@babel/code-frame": "^7.23.4",
- "@babel/generator": "^7.23.4",
- "@babel/helper-environment-visitor": "^7.22.20",
- "@babel/helper-function-name": "^7.23.0",
- "@babel/helper-hoist-variables": "^7.22.5",
- "@babel/helper-split-export-declaration": "^7.22.6",
- "@babel/parser": "^7.23.4",
- "@babel/types": "^7.23.4",
- "debug": "^4.1.0",
- "globals": "^11.1.0"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/types": {
- "version": "7.23.4",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.4.tgz",
- "integrity": "sha512-7uIFwVYpoplT5jp/kVv6EF93VaJ8H+Yn5IczYiaAi98ajzjfoZfslet/e0sLh+wVBjb2qqIut1b0S26VSafsSQ==",
- "dev": true,
- "dependencies": {
- "@babel/helper-string-parser": "^7.23.4",
- "@babel/helper-validator-identifier": "^7.22.20",
- "to-fast-properties": "^2.0.0"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@bcoe/v8-coverage": {
- "version": "0.2.3",
- "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz",
- "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
- "dev": true
- },
- "node_modules/@discoveryjs/json-ext": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz",
- "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==",
- "dev": true,
- "engines": {
- "node": ">=10.0.0"
- }
- },
- "node_modules/@eslint/eslintrc": {
- "version": "0.4.3",
- "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz",
- "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==",
- "dev": true,
- "dependencies": {
- "ajv": "^6.12.4",
- "debug": "^4.1.1",
- "espree": "^7.3.0",
- "globals": "^13.9.0",
- "ignore": "^4.0.6",
- "import-fresh": "^3.2.1",
- "js-yaml": "^3.13.1",
- "minimatch": "^3.0.4",
- "strip-json-comments": "^3.1.1"
- },
- "engines": {
- "node": "^10.12.0 || >=12.0.0"
- }
- },
- "node_modules/@eslint/eslintrc/node_modules/globals": {
- "version": "13.19.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz",
- "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==",
- "dev": true,
- "dependencies": {
- "type-fest": "^0.20.2"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/@eslint/eslintrc/node_modules/ignore": {
- "version": "4.0.6",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
- "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
- "dev": true,
- "engines": {
- "node": ">= 4"
- }
- },
- "node_modules/@eslint/eslintrc/node_modules/type-fest": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
- "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
- "dev": true,
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/@humanwhocodes/config-array": {
- "version": "0.5.0",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz",
- "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==",
- "dev": true,
- "dependencies": {
- "@humanwhocodes/object-schema": "^1.2.0",
- "debug": "^4.1.1",
- "minimatch": "^3.0.4"
- },
- "engines": {
- "node": ">=10.10.0"
- }
- },
- "node_modules/@humanwhocodes/object-schema": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
- "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
- "dev": true
- },
- "node_modules/@istanbuljs/load-nyc-config": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
- "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==",
- "dev": true,
- "dependencies": {
- "camelcase": "^5.3.1",
- "find-up": "^4.1.0",
- "get-package-type": "^0.1.0",
- "js-yaml": "^3.13.1",
- "resolve-from": "^5.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/@istanbuljs/schema": {
- "version": "0.1.3",
- "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz",
- "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/@jest/console": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.3.1.tgz",
- "integrity": "sha512-IRE6GD47KwcqA09RIWrabKdHPiKDGgtAL31xDxbi/RjQMsr+lY+ppxmHwY0dUEV3qvvxZzoe5Hl0RXZJOjQNUg==",
- "dev": true,
- "dependencies": {
- "@jest/types": "^29.3.1",
- "@types/node": "*",
- "chalk": "^4.0.0",
- "jest-message-util": "^29.3.1",
- "jest-util": "^29.3.1",
- "slash": "^3.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/@jest/console/node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/@jest/console/node_modules/chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/@jest/console/node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/@jest/console/node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "node_modules/@jest/console/node_modules/has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/@jest/console/node_modules/slash": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
- "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/@jest/console/node_modules/supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/@jest/core": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.3.1.tgz",
- "integrity": "sha512-0ohVjjRex985w5MmO5L3u5GR1O30DexhBSpuwx2P+9ftyqHdJXnk7IUWiP80oHMvt7ubHCJHxV0a0vlKVuZirw==",
- "dev": true,
- "dependencies": {
- "@jest/console": "^29.3.1",
- "@jest/reporters": "^29.3.1",
- "@jest/test-result": "^29.3.1",
- "@jest/transform": "^29.3.1",
- "@jest/types": "^29.3.1",
- "@types/node": "*",
- "ansi-escapes": "^4.2.1",
- "chalk": "^4.0.0",
- "ci-info": "^3.2.0",
- "exit": "^0.1.2",
- "graceful-fs": "^4.2.9",
- "jest-changed-files": "^29.2.0",
- "jest-config": "^29.3.1",
- "jest-haste-map": "^29.3.1",
- "jest-message-util": "^29.3.1",
- "jest-regex-util": "^29.2.0",
- "jest-resolve": "^29.3.1",
- "jest-resolve-dependencies": "^29.3.1",
- "jest-runner": "^29.3.1",
- "jest-runtime": "^29.3.1",
- "jest-snapshot": "^29.3.1",
- "jest-util": "^29.3.1",
- "jest-validate": "^29.3.1",
- "jest-watcher": "^29.3.1",
- "micromatch": "^4.0.4",
- "pretty-format": "^29.3.1",
- "slash": "^3.0.0",
- "strip-ansi": "^6.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- },
- "peerDependencies": {
- "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0"
- },
- "peerDependenciesMeta": {
- "node-notifier": {
- "optional": true
- }
- }
- },
- "node_modules/@jest/core/node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/@jest/core/node_modules/chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/@jest/core/node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/@jest/core/node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "node_modules/@jest/core/node_modules/has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/@jest/core/node_modules/slash": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
- "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/@jest/core/node_modules/supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/@jest/environment": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.3.1.tgz",
- "integrity": "sha512-pMmvfOPmoa1c1QpfFW0nXYtNLpofqo4BrCIk6f2kW4JFeNlHV2t3vd+3iDLf31e2ot2Mec0uqZfmI+U0K2CFag==",
- "dev": true,
- "dependencies": {
- "@jest/fake-timers": "^29.3.1",
- "@jest/types": "^29.3.1",
- "@types/node": "*",
- "jest-mock": "^29.3.1"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/@jest/expect": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.3.1.tgz",
- "integrity": "sha512-QivM7GlSHSsIAWzgfyP8dgeExPRZ9BIe2LsdPyEhCGkZkoyA+kGsoIzbKAfZCvvRzfZioKwPtCZIt5SaoxYCvg==",
- "dev": true,
- "dependencies": {
- "expect": "^29.3.1",
- "jest-snapshot": "^29.3.1"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/@jest/expect-utils": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.3.1.tgz",
- "integrity": "sha512-wlrznINZI5sMjwvUoLVk617ll/UYfGIZNxmbU+Pa7wmkL4vYzhV9R2pwVqUh4NWWuLQWkI8+8mOkxs//prKQ3g==",
- "dev": true,
- "dependencies": {
- "jest-get-type": "^29.2.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/@jest/fake-timers": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.3.1.tgz",
- "integrity": "sha512-iHTL/XpnDlFki9Tq0Q1GGuVeQ8BHZGIYsvCO5eN/O/oJaRzofG9Xndd9HuSDBI/0ZS79pg0iwn07OMTQ7ngF2A==",
- "dev": true,
- "dependencies": {
- "@jest/types": "^29.3.1",
- "@sinonjs/fake-timers": "^9.1.2",
- "@types/node": "*",
- "jest-message-util": "^29.3.1",
- "jest-mock": "^29.3.1",
- "jest-util": "^29.3.1"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/@jest/globals": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.3.1.tgz",
- "integrity": "sha512-cTicd134vOcwO59OPaB6AmdHQMCtWOe+/DitpTZVxWgMJ+YvXL1HNAmPyiGbSHmF/mXVBkvlm8YYtQhyHPnV6Q==",
- "dev": true,
- "dependencies": {
- "@jest/environment": "^29.3.1",
- "@jest/expect": "^29.3.1",
- "@jest/types": "^29.3.1",
- "jest-mock": "^29.3.1"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/@jest/reporters": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.3.1.tgz",
- "integrity": "sha512-GhBu3YFuDrcAYW/UESz1JphEAbvUjaY2vShRZRoRY1mxpCMB3yGSJ4j9n0GxVlEOdCf7qjvUfBCrTUUqhVfbRA==",
- "dev": true,
- "dependencies": {
- "@bcoe/v8-coverage": "^0.2.3",
- "@jest/console": "^29.3.1",
- "@jest/test-result": "^29.3.1",
- "@jest/transform": "^29.3.1",
- "@jest/types": "^29.3.1",
- "@jridgewell/trace-mapping": "^0.3.15",
- "@types/node": "*",
- "chalk": "^4.0.0",
- "collect-v8-coverage": "^1.0.0",
- "exit": "^0.1.2",
- "glob": "^7.1.3",
- "graceful-fs": "^4.2.9",
- "istanbul-lib-coverage": "^3.0.0",
- "istanbul-lib-instrument": "^5.1.0",
- "istanbul-lib-report": "^3.0.0",
- "istanbul-lib-source-maps": "^4.0.0",
- "istanbul-reports": "^3.1.3",
- "jest-message-util": "^29.3.1",
- "jest-util": "^29.3.1",
- "jest-worker": "^29.3.1",
- "slash": "^3.0.0",
- "string-length": "^4.0.1",
- "strip-ansi": "^6.0.0",
- "v8-to-istanbul": "^9.0.1"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- },
- "peerDependencies": {
- "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0"
- },
- "peerDependenciesMeta": {
- "node-notifier": {
- "optional": true
- }
- }
- },
- "node_modules/@jest/reporters/node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/@jest/reporters/node_modules/chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/@jest/reporters/node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/@jest/reporters/node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "node_modules/@jest/reporters/node_modules/has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/@jest/reporters/node_modules/slash": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
- "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/@jest/reporters/node_modules/supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/@jest/schemas": {
- "version": "29.0.0",
- "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.0.0.tgz",
- "integrity": "sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA==",
- "dev": true,
- "dependencies": {
- "@sinclair/typebox": "^0.24.1"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/@jest/source-map": {
- "version": "29.2.0",
- "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.2.0.tgz",
- "integrity": "sha512-1NX9/7zzI0nqa6+kgpSdKPK+WU1p+SJk3TloWZf5MzPbxri9UEeXX5bWZAPCzbQcyuAzubcdUHA7hcNznmRqWQ==",
- "dev": true,
- "dependencies": {
- "@jridgewell/trace-mapping": "^0.3.15",
- "callsites": "^3.0.0",
- "graceful-fs": "^4.2.9"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/@jest/test-result": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.3.1.tgz",
- "integrity": "sha512-qeLa6qc0ddB0kuOZyZIhfN5q0e2htngokyTWsGriedsDhItisW7SDYZ7ceOe57Ii03sL988/03wAcBh3TChMGw==",
- "dev": true,
- "dependencies": {
- "@jest/console": "^29.3.1",
- "@jest/types": "^29.3.1",
- "@types/istanbul-lib-coverage": "^2.0.0",
- "collect-v8-coverage": "^1.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/@jest/test-sequencer": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.3.1.tgz",
- "integrity": "sha512-IqYvLbieTv20ArgKoAMyhLHNrVHJfzO6ARZAbQRlY4UGWfdDnLlZEF0BvKOMd77uIiIjSZRwq3Jb3Fa3I8+2UA==",
- "dev": true,
- "dependencies": {
- "@jest/test-result": "^29.3.1",
- "graceful-fs": "^4.2.9",
- "jest-haste-map": "^29.3.1",
- "slash": "^3.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/@jest/test-sequencer/node_modules/slash": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
- "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/@jest/transform": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.3.1.tgz",
- "integrity": "sha512-8wmCFBTVGYqFNLWfcOWoVuMuKYPUBTnTMDkdvFtAYELwDOl9RGwOsvQWGPFxDJ8AWY9xM/8xCXdqmPK3+Q5Lug==",
- "dev": true,
- "dependencies": {
- "@babel/core": "^7.11.6",
- "@jest/types": "^29.3.1",
- "@jridgewell/trace-mapping": "^0.3.15",
- "babel-plugin-istanbul": "^6.1.1",
- "chalk": "^4.0.0",
- "convert-source-map": "^2.0.0",
- "fast-json-stable-stringify": "^2.1.0",
- "graceful-fs": "^4.2.9",
- "jest-haste-map": "^29.3.1",
- "jest-regex-util": "^29.2.0",
- "jest-util": "^29.3.1",
- "micromatch": "^4.0.4",
- "pirates": "^4.0.4",
- "slash": "^3.0.0",
- "write-file-atomic": "^4.0.1"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/@jest/transform/node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/@jest/transform/node_modules/chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/@jest/transform/node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/@jest/transform/node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "node_modules/@jest/transform/node_modules/convert-source-map": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
- "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
- "dev": true
- },
- "node_modules/@jest/transform/node_modules/has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/@jest/transform/node_modules/slash": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
- "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/@jest/transform/node_modules/supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/@jest/types": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.3.1.tgz",
- "integrity": "sha512-d0S0jmmTpjnhCmNpApgX3jrUZgZ22ivKJRvL2lli5hpCRoNnp1f85r2/wpKfXuYu8E7Jjh1hGfhPyup1NM5AmA==",
- "dev": true,
- "dependencies": {
- "@jest/schemas": "^29.0.0",
- "@types/istanbul-lib-coverage": "^2.0.0",
- "@types/istanbul-reports": "^3.0.0",
- "@types/node": "*",
- "@types/yargs": "^17.0.8",
- "chalk": "^4.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/@jest/types/node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/@jest/types/node_modules/chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/@jest/types/node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/@jest/types/node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "node_modules/@jest/types/node_modules/has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/@jest/types/node_modules/supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/@jridgewell/gen-mapping": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz",
- "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==",
- "dev": true,
- "dependencies": {
- "@jridgewell/set-array": "^1.0.0",
- "@jridgewell/sourcemap-codec": "^1.4.10"
- },
- "engines": {
- "node": ">=6.0.0"
- }
- },
- "node_modules/@jridgewell/resolve-uri": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
- "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
- "dev": true,
- "engines": {
- "node": ">=6.0.0"
- }
- },
- "node_modules/@jridgewell/set-array": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
- "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
- "dev": true,
- "engines": {
- "node": ">=6.0.0"
- }
- },
- "node_modules/@jridgewell/source-map": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz",
- "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==",
- "dev": true,
- "dependencies": {
- "@jridgewell/gen-mapping": "^0.3.0",
- "@jridgewell/trace-mapping": "^0.3.9"
- }
- },
- "node_modules/@jridgewell/source-map/node_modules/@jridgewell/gen-mapping": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz",
- "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==",
- "dev": true,
- "dependencies": {
- "@jridgewell/set-array": "^1.0.1",
- "@jridgewell/sourcemap-codec": "^1.4.10",
- "@jridgewell/trace-mapping": "^0.3.9"
- },
- "engines": {
- "node": ">=6.0.0"
- }
- },
- "node_modules/@jridgewell/sourcemap-codec": {
- "version": "1.4.14",
- "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
- "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
- "dev": true
- },
- "node_modules/@jridgewell/trace-mapping": {
- "version": "0.3.17",
- "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz",
- "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==",
- "dev": true,
- "dependencies": {
- "@jridgewell/resolve-uri": "3.1.0",
- "@jridgewell/sourcemap-codec": "1.4.14"
- }
- },
- "node_modules/@nicolo-ribaudo/chokidar-2": {
- "version": "2.1.8-no-fsevents.3",
- "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz",
- "integrity": "sha512-s88O1aVtXftvp5bCPB7WnmXc5IwOZZ7YPuwNPt+GtOOXpPvad1LfbmjYv+qII7zP6RU2QGnqve27dnLycEnyEQ==",
- "dev": true,
- "optional": true
- },
- "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": {
- "version": "5.1.1-v1",
- "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz",
- "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==",
- "dev": true,
- "dependencies": {
- "eslint-scope": "5.1.1"
- }
- },
- "node_modules/@nodelib/fs.scandir": {
- "version": "2.1.5",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
- "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
- "dev": true,
- "dependencies": {
- "@nodelib/fs.stat": "2.0.5",
- "run-parallel": "^1.1.9"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/@nodelib/fs.stat": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
- "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
- "dev": true,
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/@nodelib/fs.walk": {
- "version": "1.2.8",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
- "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
- "dev": true,
- "dependencies": {
- "@nodelib/fs.scandir": "2.1.5",
- "fastq": "^1.6.0"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/@polka/url": {
- "version": "1.0.0-next.21",
- "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz",
- "integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==",
- "dev": true
- },
- "node_modules/@sinclair/typebox": {
- "version": "0.24.51",
- "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz",
- "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==",
- "dev": true
- },
- "node_modules/@sinonjs/commons": {
- "version": "1.8.6",
- "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz",
- "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==",
- "dev": true,
- "dependencies": {
- "type-detect": "4.0.8"
- }
- },
- "node_modules/@sinonjs/fake-timers": {
- "version": "9.1.2",
- "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz",
- "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==",
- "dev": true,
- "dependencies": {
- "@sinonjs/commons": "^1.7.0"
- }
- },
- "node_modules/@types/babel__core": {
- "version": "7.1.20",
- "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.20.tgz",
- "integrity": "sha512-PVb6Bg2QuscZ30FvOU7z4guG6c926D9YRvOxEaelzndpMsvP+YM74Q/dAFASpg2l6+XLalxSGxcq/lrgYWZtyQ==",
- "dev": true,
- "dependencies": {
- "@babel/parser": "^7.1.0",
- "@babel/types": "^7.0.0",
- "@types/babel__generator": "*",
- "@types/babel__template": "*",
- "@types/babel__traverse": "*"
- }
- },
- "node_modules/@types/babel__generator": {
- "version": "7.6.4",
- "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz",
- "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==",
- "dev": true,
- "dependencies": {
- "@babel/types": "^7.0.0"
- }
- },
- "node_modules/@types/babel__template": {
- "version": "7.4.1",
- "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz",
- "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==",
- "dev": true,
- "dependencies": {
- "@babel/parser": "^7.1.0",
- "@babel/types": "^7.0.0"
- }
- },
- "node_modules/@types/babel__traverse": {
- "version": "7.18.3",
- "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.3.tgz",
- "integrity": "sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w==",
- "dev": true,
- "dependencies": {
- "@babel/types": "^7.3.0"
- }
- },
- "node_modules/@types/eslint": {
- "version": "8.4.10",
- "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.10.tgz",
- "integrity": "sha512-Sl/HOqN8NKPmhWo2VBEPm0nvHnu2LL3v9vKo8MEq0EtbJ4eVzGPl41VNPvn5E1i5poMk4/XD8UriLHpJvEP/Nw==",
- "dev": true,
- "dependencies": {
- "@types/estree": "*",
- "@types/json-schema": "*"
- }
- },
- "node_modules/@types/eslint-scope": {
- "version": "3.7.4",
- "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz",
- "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==",
- "dev": true,
- "dependencies": {
- "@types/eslint": "*",
- "@types/estree": "*"
- }
- },
- "node_modules/@types/estree": {
- "version": "0.0.51",
- "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz",
- "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==",
- "dev": true
- },
- "node_modules/@types/graceful-fs": {
- "version": "4.1.6",
- "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz",
- "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==",
- "dev": true,
- "dependencies": {
- "@types/node": "*"
- }
- },
- "node_modules/@types/istanbul-lib-coverage": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz",
- "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==",
- "dev": true
- },
- "node_modules/@types/istanbul-lib-report": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz",
- "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==",
- "dev": true,
- "dependencies": {
- "@types/istanbul-lib-coverage": "*"
- }
- },
- "node_modules/@types/istanbul-reports": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz",
- "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==",
- "dev": true,
- "dependencies": {
- "@types/istanbul-lib-report": "*"
- }
- },
- "node_modules/@types/jest": {
- "version": "29.2.5",
- "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.2.5.tgz",
- "integrity": "sha512-H2cSxkKgVmqNHXP7TC2L/WUorrZu8ZigyRywfVzv6EyBlxj39n4C00hjXYQWsbwqgElaj/CiAeSRmk5GoaKTgw==",
- "dev": true,
- "dependencies": {
- "expect": "^29.0.0",
- "pretty-format": "^29.0.0"
- }
- },
- "node_modules/@types/json-schema": {
- "version": "7.0.11",
- "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz",
- "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==",
- "dev": true
- },
- "node_modules/@types/node": {
- "version": "18.11.18",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz",
- "integrity": "sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==",
- "dev": true
- },
- "node_modules/@types/node-fetch": {
- "version": "2.6.2",
- "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.2.tgz",
- "integrity": "sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==",
- "dev": true,
- "dependencies": {
- "@types/node": "*",
- "form-data": "^3.0.0"
- }
- },
- "node_modules/@types/prettier": {
- "version": "2.7.2",
- "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.2.tgz",
- "integrity": "sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==",
- "dev": true
- },
- "node_modules/@types/semver": {
- "version": "7.3.13",
- "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz",
- "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==",
- "dev": true
- },
- "node_modules/@types/stack-utils": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz",
- "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==",
- "dev": true
- },
- "node_modules/@types/yargs": {
- "version": "17.0.19",
- "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.19.tgz",
- "integrity": "sha512-cAx3qamwaYX9R0fzOIZAlFpo4A+1uBVCxqpKz9D26uTF4srRXaGTTsikQmaotCtNdbhzyUH7ft6p9ktz9s6UNQ==",
- "dev": true,
- "dependencies": {
- "@types/yargs-parser": "*"
- }
- },
- "node_modules/@types/yargs-parser": {
- "version": "21.0.0",
- "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz",
- "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==",
- "dev": true
- },
- "node_modules/@typescript-eslint/eslint-plugin": {
- "version": "5.48.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.48.2.tgz",
- "integrity": "sha512-sR0Gja9Ky1teIq4qJOl0nC+Tk64/uYdX+mi+5iB//MH8gwyx8e3SOyhEzeLZEFEEfCaLf8KJq+Bd/6je1t+CAg==",
- "dev": true,
- "dependencies": {
- "@typescript-eslint/scope-manager": "5.48.2",
- "@typescript-eslint/type-utils": "5.48.2",
- "@typescript-eslint/utils": "5.48.2",
- "debug": "^4.3.4",
- "ignore": "^5.2.0",
- "natural-compare-lite": "^1.4.0",
- "regexpp": "^3.2.0",
- "semver": "^7.3.7",
- "tsutils": "^3.21.0"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "@typescript-eslint/parser": "^5.0.0",
- "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
- },
- "peerDependenciesMeta": {
- "typescript": {
- "optional": true
- }
- }
- },
- "node_modules/@typescript-eslint/eslint-plugin/node_modules/lru-cache": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
- "dev": true,
- "dependencies": {
- "yallist": "^4.0.0"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": {
- "version": "7.3.8",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
- "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
- "dev": true,
- "dependencies": {
- "lru-cache": "^6.0.0"
- },
- "bin": {
- "semver": "bin/semver.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/@typescript-eslint/eslint-plugin/node_modules/yallist": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
- "dev": true
- },
- "node_modules/@typescript-eslint/parser": {
- "version": "5.48.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.48.2.tgz",
- "integrity": "sha512-38zMsKsG2sIuM5Oi/olurGwYJXzmtdsHhn5mI/pQogP+BjYVkK5iRazCQ8RGS0V+YLk282uWElN70zAAUmaYHw==",
- "dev": true,
- "dependencies": {
- "@typescript-eslint/scope-manager": "5.48.2",
- "@typescript-eslint/types": "5.48.2",
- "@typescript-eslint/typescript-estree": "5.48.2",
- "debug": "^4.3.4"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
- },
- "peerDependenciesMeta": {
- "typescript": {
- "optional": true
- }
- }
- },
- "node_modules/@typescript-eslint/scope-manager": {
- "version": "5.48.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.2.tgz",
- "integrity": "sha512-zEUFfonQid5KRDKoI3O+uP1GnrFd4tIHlvs+sTJXiWuypUWMuDaottkJuR612wQfOkjYbsaskSIURV9xo4f+Fw==",
- "dev": true,
- "dependencies": {
- "@typescript-eslint/types": "5.48.2",
- "@typescript-eslint/visitor-keys": "5.48.2"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- }
- },
- "node_modules/@typescript-eslint/type-utils": {
- "version": "5.48.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.48.2.tgz",
- "integrity": "sha512-QVWx7J5sPMRiOMJp5dYshPxABRoZV1xbRirqSk8yuIIsu0nvMTZesKErEA3Oix1k+uvsk8Cs8TGJ6kQ0ndAcew==",
- "dev": true,
- "dependencies": {
- "@typescript-eslint/typescript-estree": "5.48.2",
- "@typescript-eslint/utils": "5.48.2",
- "debug": "^4.3.4",
- "tsutils": "^3.21.0"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "eslint": "*"
- },
- "peerDependenciesMeta": {
- "typescript": {
- "optional": true
- }
- }
- },
- "node_modules/@typescript-eslint/types": {
- "version": "5.48.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.2.tgz",
- "integrity": "sha512-hE7dA77xxu7ByBc6KCzikgfRyBCTst6dZQpwaTy25iMYOnbNljDT4hjhrGEJJ0QoMjrfqrx+j1l1B9/LtKeuqA==",
- "dev": true,
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- }
- },
- "node_modules/@typescript-eslint/typescript-estree": {
- "version": "5.48.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.2.tgz",
- "integrity": "sha512-bibvD3z6ilnoVxUBFEgkO0k0aFvUc4Cttt0dAreEr+nrAHhWzkO83PEVVuieK3DqcgL6VAK5dkzK8XUVja5Zcg==",
- "dev": true,
- "dependencies": {
- "@typescript-eslint/types": "5.48.2",
- "@typescript-eslint/visitor-keys": "5.48.2",
- "debug": "^4.3.4",
- "globby": "^11.1.0",
- "is-glob": "^4.0.3",
- "semver": "^7.3.7",
- "tsutils": "^3.21.0"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependenciesMeta": {
- "typescript": {
- "optional": true
- }
- }
- },
- "node_modules/@typescript-eslint/typescript-estree/node_modules/lru-cache": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
- "dev": true,
- "dependencies": {
- "yallist": "^4.0.0"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": {
- "version": "7.3.8",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
- "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
- "dev": true,
- "dependencies": {
- "lru-cache": "^6.0.0"
- },
- "bin": {
- "semver": "bin/semver.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/@typescript-eslint/typescript-estree/node_modules/yallist": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
- "dev": true
- },
- "node_modules/@typescript-eslint/utils": {
- "version": "5.48.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.2.tgz",
- "integrity": "sha512-2h18c0d7jgkw6tdKTlNaM7wyopbLRBiit8oAxoP89YnuBOzCZ8g8aBCaCqq7h208qUTroL7Whgzam7UY3HVLow==",
- "dev": true,
- "dependencies": {
- "@types/json-schema": "^7.0.9",
- "@types/semver": "^7.3.12",
- "@typescript-eslint/scope-manager": "5.48.2",
- "@typescript-eslint/types": "5.48.2",
- "@typescript-eslint/typescript-estree": "5.48.2",
- "eslint-scope": "^5.1.1",
- "eslint-utils": "^3.0.0",
- "semver": "^7.3.7"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
- }
- },
- "node_modules/@typescript-eslint/utils/node_modules/lru-cache": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
- "dev": true,
- "dependencies": {
- "yallist": "^4.0.0"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/@typescript-eslint/utils/node_modules/semver": {
- "version": "7.3.8",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
- "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
- "dev": true,
- "dependencies": {
- "lru-cache": "^6.0.0"
- },
- "bin": {
- "semver": "bin/semver.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/@typescript-eslint/utils/node_modules/yallist": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
- "dev": true
- },
- "node_modules/@typescript-eslint/visitor-keys": {
- "version": "5.48.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.2.tgz",
- "integrity": "sha512-z9njZLSkwmjFWUelGEwEbdf4NwKvfHxvGC0OcGN1Hp/XNDIcJ7D5DpPNPv6x6/mFvc1tQHsaWmpD/a4gOvvCJQ==",
- "dev": true,
- "dependencies": {
- "@typescript-eslint/types": "5.48.2",
- "eslint-visitor-keys": "^3.3.0"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- }
- },
- "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz",
- "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==",
- "dev": true,
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- }
- },
- "node_modules/@webassemblyjs/ast": {
- "version": "1.11.1",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz",
- "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==",
- "dev": true,
- "dependencies": {
- "@webassemblyjs/helper-numbers": "1.11.1",
- "@webassemblyjs/helper-wasm-bytecode": "1.11.1"
- }
- },
- "node_modules/@webassemblyjs/floating-point-hex-parser": {
- "version": "1.11.1",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz",
- "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==",
- "dev": true
- },
- "node_modules/@webassemblyjs/helper-api-error": {
- "version": "1.11.1",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz",
- "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==",
- "dev": true
- },
- "node_modules/@webassemblyjs/helper-buffer": {
- "version": "1.11.1",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz",
- "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==",
- "dev": true
- },
- "node_modules/@webassemblyjs/helper-numbers": {
- "version": "1.11.1",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz",
- "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==",
- "dev": true,
- "dependencies": {
- "@webassemblyjs/floating-point-hex-parser": "1.11.1",
- "@webassemblyjs/helper-api-error": "1.11.1",
- "@xtuc/long": "4.2.2"
- }
- },
- "node_modules/@webassemblyjs/helper-wasm-bytecode": {
- "version": "1.11.1",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz",
- "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==",
- "dev": true
- },
- "node_modules/@webassemblyjs/helper-wasm-section": {
- "version": "1.11.1",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz",
- "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==",
- "dev": true,
- "dependencies": {
- "@webassemblyjs/ast": "1.11.1",
- "@webassemblyjs/helper-buffer": "1.11.1",
- "@webassemblyjs/helper-wasm-bytecode": "1.11.1",
- "@webassemblyjs/wasm-gen": "1.11.1"
- }
- },
- "node_modules/@webassemblyjs/ieee754": {
- "version": "1.11.1",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz",
- "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==",
- "dev": true,
- "dependencies": {
- "@xtuc/ieee754": "^1.2.0"
- }
- },
- "node_modules/@webassemblyjs/leb128": {
- "version": "1.11.1",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz",
- "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==",
- "dev": true,
- "dependencies": {
- "@xtuc/long": "4.2.2"
- }
- },
- "node_modules/@webassemblyjs/utf8": {
- "version": "1.11.1",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz",
- "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==",
- "dev": true
- },
- "node_modules/@webassemblyjs/wasm-edit": {
- "version": "1.11.1",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz",
- "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==",
- "dev": true,
- "dependencies": {
- "@webassemblyjs/ast": "1.11.1",
- "@webassemblyjs/helper-buffer": "1.11.1",
- "@webassemblyjs/helper-wasm-bytecode": "1.11.1",
- "@webassemblyjs/helper-wasm-section": "1.11.1",
- "@webassemblyjs/wasm-gen": "1.11.1",
- "@webassemblyjs/wasm-opt": "1.11.1",
- "@webassemblyjs/wasm-parser": "1.11.1",
- "@webassemblyjs/wast-printer": "1.11.1"
- }
- },
- "node_modules/@webassemblyjs/wasm-gen": {
- "version": "1.11.1",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz",
- "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==",
- "dev": true,
- "dependencies": {
- "@webassemblyjs/ast": "1.11.1",
- "@webassemblyjs/helper-wasm-bytecode": "1.11.1",
- "@webassemblyjs/ieee754": "1.11.1",
- "@webassemblyjs/leb128": "1.11.1",
- "@webassemblyjs/utf8": "1.11.1"
- }
- },
- "node_modules/@webassemblyjs/wasm-opt": {
- "version": "1.11.1",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz",
- "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==",
- "dev": true,
- "dependencies": {
- "@webassemblyjs/ast": "1.11.1",
- "@webassemblyjs/helper-buffer": "1.11.1",
- "@webassemblyjs/wasm-gen": "1.11.1",
- "@webassemblyjs/wasm-parser": "1.11.1"
- }
- },
- "node_modules/@webassemblyjs/wasm-parser": {
- "version": "1.11.1",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz",
- "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==",
- "dev": true,
- "dependencies": {
- "@webassemblyjs/ast": "1.11.1",
- "@webassemblyjs/helper-api-error": "1.11.1",
- "@webassemblyjs/helper-wasm-bytecode": "1.11.1",
- "@webassemblyjs/ieee754": "1.11.1",
- "@webassemblyjs/leb128": "1.11.1",
- "@webassemblyjs/utf8": "1.11.1"
- }
- },
- "node_modules/@webassemblyjs/wast-printer": {
- "version": "1.11.1",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz",
- "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==",
- "dev": true,
- "dependencies": {
- "@webassemblyjs/ast": "1.11.1",
- "@xtuc/long": "4.2.2"
- }
- },
- "node_modules/@webpack-cli/configtest": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.2.0.tgz",
- "integrity": "sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==",
- "dev": true,
- "peerDependencies": {
- "webpack": "4.x.x || 5.x.x",
- "webpack-cli": "4.x.x"
- }
- },
- "node_modules/@webpack-cli/info": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.5.0.tgz",
- "integrity": "sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ==",
- "dev": true,
- "dependencies": {
- "envinfo": "^7.7.3"
- },
- "peerDependencies": {
- "webpack-cli": "4.x.x"
- }
- },
- "node_modules/@webpack-cli/serve": {
- "version": "1.7.0",
- "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.7.0.tgz",
- "integrity": "sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==",
- "dev": true,
- "peerDependencies": {
- "webpack-cli": "4.x.x"
- },
- "peerDependenciesMeta": {
- "webpack-dev-server": {
- "optional": true
- }
- }
- },
- "node_modules/@xtuc/ieee754": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
- "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==",
- "dev": true
- },
- "node_modules/@xtuc/long": {
- "version": "4.2.2",
- "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz",
- "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==",
- "dev": true
- },
- "node_modules/acorn": {
- "version": "8.8.1",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz",
- "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==",
- "dev": true,
- "bin": {
- "acorn": "bin/acorn"
- },
- "engines": {
- "node": ">=0.4.0"
- }
- },
- "node_modules/acorn-jsx": {
- "version": "5.3.2",
- "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
- "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
- "dev": true,
- "peerDependencies": {
- "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
- }
- },
- "node_modules/ajv": {
- "version": "6.12.6",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
- "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
- "dev": true,
- "dependencies": {
- "fast-deep-equal": "^3.1.1",
- "fast-json-stable-stringify": "^2.0.0",
- "json-schema-traverse": "^0.4.1",
- "uri-js": "^4.2.2"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/epoberezkin"
- }
- },
- "node_modules/ajv-keywords": {
- "version": "3.5.2",
- "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
- "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
- "dev": true,
- "peerDependencies": {
- "ajv": "^6.9.1"
- }
- },
- "node_modules/ansi-colors": {
- "version": "4.1.3",
- "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz",
- "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/ansi-escapes": {
- "version": "4.3.2",
- "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
- "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==",
- "dev": true,
- "dependencies": {
- "type-fest": "^0.21.3"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/ansi-styles": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
- "dev": true,
- "dependencies": {
- "color-convert": "^1.9.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/anymatch": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
- "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
- "dev": true,
- "dependencies": {
- "normalize-path": "^3.0.0",
- "picomatch": "^2.0.4"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/argparse": {
- "version": "1.0.10",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
- "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
- "dev": true,
- "dependencies": {
- "sprintf-js": "~1.0.2"
- }
- },
- "node_modules/array-union": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
- "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/astral-regex": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
- "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/asynckit": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
- "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
- "dev": true
- },
- "node_modules/babel-jest": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.3.1.tgz",
- "integrity": "sha512-aard+xnMoxgjwV70t0L6wkW/3HQQtV+O0PEimxKgzNqCJnbYmroPojdP2tqKSOAt8QAKV/uSZU8851M7B5+fcA==",
- "dev": true,
- "dependencies": {
- "@jest/transform": "^29.3.1",
- "@types/babel__core": "^7.1.14",
- "babel-plugin-istanbul": "^6.1.1",
- "babel-preset-jest": "^29.2.0",
- "chalk": "^4.0.0",
- "graceful-fs": "^4.2.9",
- "slash": "^3.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.8.0"
- }
- },
- "node_modules/babel-jest/node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/babel-jest/node_modules/chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/babel-jest/node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/babel-jest/node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "node_modules/babel-jest/node_modules/has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/babel-jest/node_modules/slash": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
- "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/babel-jest/node_modules/supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/babel-loader": {
- "version": "8.3.0",
- "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.3.0.tgz",
- "integrity": "sha512-H8SvsMF+m9t15HNLMipppzkC+Y2Yq+v3SonZyU70RBL/h1gxPkH08Ot8pEE9Z4Kd+czyWJClmFS8qzIP9OZ04Q==",
- "dev": true,
- "dependencies": {
- "find-cache-dir": "^3.3.1",
- "loader-utils": "^2.0.0",
- "make-dir": "^3.1.0",
- "schema-utils": "^2.6.5"
- },
- "engines": {
- "node": ">= 8.9"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0",
- "webpack": ">=2"
- }
- },
- "node_modules/babel-loader/node_modules/find-cache-dir": {
- "version": "3.3.2",
- "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz",
- "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==",
- "dev": true,
- "dependencies": {
- "commondir": "^1.0.1",
- "make-dir": "^3.0.2",
- "pkg-dir": "^4.1.0"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/avajs/find-cache-dir?sponsor=1"
- }
- },
- "node_modules/babel-loader/node_modules/make-dir": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
- "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
- "dev": true,
- "dependencies": {
- "semver": "^6.0.0"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/babel-loader/node_modules/pkg-dir": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
- "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
- "dev": true,
- "dependencies": {
- "find-up": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/babel-plugin-istanbul": {
- "version": "6.1.1",
- "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz",
- "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==",
- "dev": true,
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.0.0",
- "@istanbuljs/load-nyc-config": "^1.0.0",
- "@istanbuljs/schema": "^0.1.2",
- "istanbul-lib-instrument": "^5.0.4",
- "test-exclude": "^6.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/babel-plugin-jest-hoist": {
- "version": "29.2.0",
- "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.2.0.tgz",
- "integrity": "sha512-TnspP2WNiR3GLfCsUNHqeXw0RoQ2f9U5hQ5L3XFpwuO8htQmSrhh8qsB6vi5Yi8+kuynN1yjDjQsPfkebmB6ZA==",
- "dev": true,
- "dependencies": {
- "@babel/template": "^7.3.3",
- "@babel/types": "^7.3.3",
- "@types/babel__core": "^7.1.14",
- "@types/babel__traverse": "^7.0.6"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/babel-plugin-polyfill-corejs2": {
- "version": "0.3.3",
- "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz",
- "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==",
- "dev": true,
- "dependencies": {
- "@babel/compat-data": "^7.17.7",
- "@babel/helper-define-polyfill-provider": "^0.3.3",
- "semver": "^6.1.1"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/babel-plugin-polyfill-corejs3": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz",
- "integrity": "sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==",
- "dev": true,
- "dependencies": {
- "@babel/helper-define-polyfill-provider": "^0.3.3",
- "core-js-compat": "^3.25.1"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/babel-plugin-polyfill-regenerator": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz",
- "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==",
- "dev": true,
- "dependencies": {
- "@babel/helper-define-polyfill-provider": "^0.3.3"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/babel-preset-current-node-syntax": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz",
- "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==",
- "dev": true,
- "dependencies": {
- "@babel/plugin-syntax-async-generators": "^7.8.4",
- "@babel/plugin-syntax-bigint": "^7.8.3",
- "@babel/plugin-syntax-class-properties": "^7.8.3",
- "@babel/plugin-syntax-import-meta": "^7.8.3",
- "@babel/plugin-syntax-json-strings": "^7.8.3",
- "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3",
- "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3",
- "@babel/plugin-syntax-numeric-separator": "^7.8.3",
- "@babel/plugin-syntax-object-rest-spread": "^7.8.3",
- "@babel/plugin-syntax-optional-catch-binding": "^7.8.3",
- "@babel/plugin-syntax-optional-chaining": "^7.8.3",
- "@babel/plugin-syntax-top-level-await": "^7.8.3"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0"
- }
- },
- "node_modules/babel-preset-jest": {
- "version": "29.2.0",
- "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.2.0.tgz",
- "integrity": "sha512-z9JmMJppMxNv8N7fNRHvhMg9cvIkMxQBXgFkane3yKVEvEOP+kB50lk8DFRvF9PGqbyXxlmebKWhuDORO8RgdA==",
- "dev": true,
- "dependencies": {
- "babel-plugin-jest-hoist": "^29.2.0",
- "babel-preset-current-node-syntax": "^1.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0"
- }
- },
- "node_modules/balanced-match": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
- "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
- "dev": true
- },
- "node_modules/big.js": {
- "version": "5.2.2",
- "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
- "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==",
- "dev": true,
- "engines": {
- "node": "*"
- }
- },
- "node_modules/binary-extensions": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
- "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
- "dev": true,
- "optional": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/brace-expansion": {
- "version": "1.1.11",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
- "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
- "dev": true,
- "dependencies": {
- "balanced-match": "^1.0.0",
- "concat-map": "0.0.1"
- }
- },
- "node_modules/braces": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
- "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
- "dev": true,
- "dependencies": {
- "fill-range": "^7.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/browserslist": {
- "version": "4.21.4",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz",
- "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==",
- "dev": true,
- "funding": [
- {
- "type": "opencollective",
- "url": "https://opencollective.com/browserslist"
- },
- {
- "type": "tidelift",
- "url": "https://tidelift.com/funding/github/npm/browserslist"
- }
- ],
- "dependencies": {
- "caniuse-lite": "^1.0.30001400",
- "electron-to-chromium": "^1.4.251",
- "node-releases": "^2.0.6",
- "update-browserslist-db": "^1.0.9"
- },
- "bin": {
- "browserslist": "cli.js"
- },
- "engines": {
- "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
- }
- },
- "node_modules/bs-logger": {
- "version": "0.2.6",
- "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz",
- "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==",
- "dev": true,
- "dependencies": {
- "fast-json-stable-stringify": "2.x"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/bser": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz",
- "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==",
- "dev": true,
- "dependencies": {
- "node-int64": "^0.4.0"
- }
- },
- "node_modules/buffer-from": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
- "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
- "dev": true
- },
- "node_modules/callsites": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
- "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/camelcase": {
- "version": "5.3.1",
- "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
- "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/caniuse-lite": {
- "version": "1.0.30001535",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001535.tgz",
- "integrity": "sha512-48jLyUkiWFfhm/afF7cQPqPjaUmSraEhK4j+FCTJpgnGGEZHqyLe3hmWH7lIooZdSzXL0ReMvHz0vKDoTBsrwg==",
- "dev": true,
- "funding": [
- {
- "type": "opencollective",
- "url": "https://opencollective.com/browserslist"
- },
- {
- "type": "tidelift",
- "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
- },
- {
- "type": "github",
- "url": "https://github.com/sponsors/ai"
- }
- ]
- },
- "node_modules/chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/char-regex": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz",
- "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==",
- "dev": true,
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/chokidar": {
- "version": "3.5.3",
- "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
- "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
- "dev": true,
- "funding": [
- {
- "type": "individual",
- "url": "https://paulmillr.com/funding/"
- }
- ],
- "optional": true,
- "dependencies": {
- "anymatch": "~3.1.2",
- "braces": "~3.0.2",
- "glob-parent": "~5.1.2",
- "is-binary-path": "~2.1.0",
- "is-glob": "~4.0.1",
- "normalize-path": "~3.0.0",
- "readdirp": "~3.6.0"
- },
- "engines": {
- "node": ">= 8.10.0"
- },
- "optionalDependencies": {
- "fsevents": "~2.3.2"
- }
- },
- "node_modules/chrome-trace-event": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz",
- "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==",
- "dev": true,
- "engines": {
- "node": ">=6.0"
- }
- },
- "node_modules/ci-info": {
- "version": "3.7.1",
- "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.7.1.tgz",
- "integrity": "sha512-4jYS4MOAaCIStSRwiuxc4B8MYhIe676yO1sYGzARnjXkWpmzZMMYxY6zu8WYWDhSuth5zhrQ1rhNSibyyvv4/w==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/sibiraj-s"
- }
- ],
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/cjs-module-lexer": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz",
- "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==",
- "dev": true
- },
- "node_modules/cliui": {
- "version": "8.0.1",
- "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
- "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
- "dev": true,
- "dependencies": {
- "string-width": "^4.2.0",
- "strip-ansi": "^6.0.1",
- "wrap-ansi": "^7.0.0"
- },
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/clone-deep": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz",
- "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==",
- "dev": true,
- "dependencies": {
- "is-plain-object": "^2.0.4",
- "kind-of": "^6.0.2",
- "shallow-clone": "^3.0.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/co": {
- "version": "4.6.0",
- "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
- "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==",
- "dev": true,
- "engines": {
- "iojs": ">= 1.0.0",
- "node": ">= 0.12.0"
- }
- },
- "node_modules/collect-v8-coverage": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz",
- "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==",
- "dev": true
- },
- "node_modules/color-convert": {
- "version": "1.9.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
- "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "dev": true,
- "dependencies": {
- "color-name": "1.1.3"
- }
- },
- "node_modules/color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
- "dev": true
- },
- "node_modules/colorette": {
- "version": "2.0.19",
- "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz",
- "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==",
- "dev": true
- },
- "node_modules/combined-stream": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
- "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
- "dev": true,
- "dependencies": {
- "delayed-stream": "~1.0.0"
- },
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/commander": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
- "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==",
- "dev": true,
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/commondir": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
- "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==",
- "dev": true
- },
- "node_modules/concat-map": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
- "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
- "dev": true
- },
- "node_modules/convert-source-map": {
- "version": "1.9.0",
- "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
- "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
- "dev": true
- },
- "node_modules/core-js": {
- "version": "3.27.1",
- "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.27.1.tgz",
- "integrity": "sha512-GutwJLBChfGCpwwhbYoqfv03LAfmiz7e7D/BNxzeMxwQf10GRSzqiOjx7AmtEk+heiD/JWmBuyBPgFtx0Sg1ww==",
- "hasInstallScript": true,
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/core-js"
- }
- },
- "node_modules/core-js-compat": {
- "version": "3.27.1",
- "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.27.1.tgz",
- "integrity": "sha512-Dg91JFeCDA17FKnneN7oCMz4BkQ4TcffkgHP4OWwp9yx3pi7ubqMDXXSacfNak1PQqjc95skyt+YBLHQJnkJwA==",
- "dev": true,
- "dependencies": {
- "browserslist": "^4.21.4"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/core-js"
- }
- },
- "node_modules/cross-spawn": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
- "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
- "dev": true,
- "dependencies": {
- "path-key": "^3.1.0",
- "shebang-command": "^2.0.0",
- "which": "^2.0.1"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/debug": {
- "version": "4.3.4",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
- "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
- "dev": true,
- "dependencies": {
- "ms": "2.1.2"
- },
- "engines": {
- "node": ">=6.0"
- },
- "peerDependenciesMeta": {
- "supports-color": {
- "optional": true
- }
- }
- },
- "node_modules/dedent": {
- "version": "0.7.0",
- "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz",
- "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==",
- "dev": true
- },
- "node_modules/deep-is": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
- "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
- "dev": true
- },
- "node_modules/deepmerge": {
- "version": "4.2.2",
- "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz",
- "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/delayed-stream": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
- "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
- "dev": true,
- "engines": {
- "node": ">=0.4.0"
- }
- },
- "node_modules/detect-newline": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz",
- "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/diff-sequences": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.3.1.tgz",
- "integrity": "sha512-hlM3QR272NXCi4pq+N4Kok4kOp6EsgOM3ZSpJI7Da3UAs+Ttsi8MRmB6trM/lhyzUxGfOgnpkHtgqm5Q/CTcfQ==",
- "dev": true,
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/dir-glob": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
- "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
- "dev": true,
- "dependencies": {
- "path-type": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/doctrine": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
- "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
- "dev": true,
- "dependencies": {
- "esutils": "^2.0.2"
- },
- "engines": {
- "node": ">=6.0.0"
- }
- },
- "node_modules/duplexer": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz",
- "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==",
- "dev": true
- },
- "node_modules/electron-to-chromium": {
- "version": "1.4.284",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz",
- "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==",
- "dev": true
- },
- "node_modules/emittery": {
- "version": "0.13.1",
- "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz",
- "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==",
- "dev": true,
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sindresorhus/emittery?sponsor=1"
- }
- },
- "node_modules/emoji-regex": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
- "dev": true
- },
- "node_modules/emojis-list": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz",
- "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==",
- "dev": true,
- "engines": {
- "node": ">= 4"
- }
- },
- "node_modules/enhanced-resolve": {
- "version": "5.12.0",
- "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz",
- "integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==",
- "dev": true,
- "dependencies": {
- "graceful-fs": "^4.2.4",
- "tapable": "^2.2.0"
- },
- "engines": {
- "node": ">=10.13.0"
- }
- },
- "node_modules/enquirer": {
- "version": "2.3.6",
- "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz",
- "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==",
- "dev": true,
- "dependencies": {
- "ansi-colors": "^4.1.1"
- },
- "engines": {
- "node": ">=8.6"
- }
- },
- "node_modules/envinfo": {
- "version": "7.8.1",
- "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz",
- "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==",
- "dev": true,
- "bin": {
- "envinfo": "dist/cli.js"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/error-ex": {
- "version": "1.3.2",
- "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
- "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
- "dev": true,
- "dependencies": {
- "is-arrayish": "^0.2.1"
- }
- },
- "node_modules/es-module-lexer": {
- "version": "0.9.3",
- "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz",
- "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==",
- "dev": true
- },
- "node_modules/escalade": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
- "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/escape-string-regexp": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
- "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
- "dev": true,
- "engines": {
- "node": ">=0.8.0"
- }
- },
- "node_modules/eslint": {
- "version": "7.32.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz",
- "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==",
- "dev": true,
- "dependencies": {
- "@babel/code-frame": "7.12.11",
- "@eslint/eslintrc": "^0.4.3",
- "@humanwhocodes/config-array": "^0.5.0",
- "ajv": "^6.10.0",
- "chalk": "^4.0.0",
- "cross-spawn": "^7.0.2",
- "debug": "^4.0.1",
- "doctrine": "^3.0.0",
- "enquirer": "^2.3.5",
- "escape-string-regexp": "^4.0.0",
- "eslint-scope": "^5.1.1",
- "eslint-utils": "^2.1.0",
- "eslint-visitor-keys": "^2.0.0",
- "espree": "^7.3.1",
- "esquery": "^1.4.0",
- "esutils": "^2.0.2",
- "fast-deep-equal": "^3.1.3",
- "file-entry-cache": "^6.0.1",
- "functional-red-black-tree": "^1.0.1",
- "glob-parent": "^5.1.2",
- "globals": "^13.6.0",
- "ignore": "^4.0.6",
- "import-fresh": "^3.0.0",
- "imurmurhash": "^0.1.4",
- "is-glob": "^4.0.0",
- "js-yaml": "^3.13.1",
- "json-stable-stringify-without-jsonify": "^1.0.1",
- "levn": "^0.4.1",
- "lodash.merge": "^4.6.2",
- "minimatch": "^3.0.4",
- "natural-compare": "^1.4.0",
- "optionator": "^0.9.1",
- "progress": "^2.0.0",
- "regexpp": "^3.1.0",
- "semver": "^7.2.1",
- "strip-ansi": "^6.0.0",
- "strip-json-comments": "^3.1.0",
- "table": "^6.0.9",
- "text-table": "^0.2.0",
- "v8-compile-cache": "^2.0.3"
- },
- "bin": {
- "eslint": "bin/eslint.js"
- },
- "engines": {
- "node": "^10.12.0 || >=12.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
- "node_modules/eslint-config-prettier": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-7.2.0.tgz",
- "integrity": "sha512-rV4Qu0C3nfJKPOAhFujFxB7RMP+URFyQqqOZW9DMRD7ZDTFyjaIlETU3xzHELt++4ugC0+Jm084HQYkkJe+Ivg==",
- "dev": true,
- "bin": {
- "eslint-config-prettier": "bin/cli.js"
- },
- "peerDependencies": {
- "eslint": ">=7.0.0"
- }
- },
- "node_modules/eslint-scope": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
- "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
- "dev": true,
- "dependencies": {
- "esrecurse": "^4.3.0",
- "estraverse": "^4.1.1"
- },
- "engines": {
- "node": ">=8.0.0"
- }
- },
- "node_modules/eslint-utils": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz",
- "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==",
- "dev": true,
- "dependencies": {
- "eslint-visitor-keys": "^2.0.0"
- },
- "engines": {
- "node": "^10.0.0 || ^12.0.0 || >= 14.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/mysticatea"
- },
- "peerDependencies": {
- "eslint": ">=5"
- }
- },
- "node_modules/eslint-visitor-keys": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
- "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
- "dev": true,
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/eslint/node_modules/@babel/code-frame": {
- "version": "7.12.11",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz",
- "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==",
- "dev": true,
- "dependencies": {
- "@babel/highlight": "^7.10.4"
- }
- },
- "node_modules/eslint/node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/eslint/node_modules/chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/eslint/node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/eslint/node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "node_modules/eslint/node_modules/escape-string-regexp": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
- "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
- "dev": true,
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/eslint/node_modules/eslint-utils": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz",
- "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==",
- "dev": true,
- "dependencies": {
- "eslint-visitor-keys": "^1.1.0"
- },
- "engines": {
- "node": ">=6"
- },
- "funding": {
- "url": "https://github.com/sponsors/mysticatea"
- }
- },
- "node_modules/eslint/node_modules/eslint-utils/node_modules/eslint-visitor-keys": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
- "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/eslint/node_modules/globals": {
- "version": "13.19.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz",
- "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==",
- "dev": true,
- "dependencies": {
- "type-fest": "^0.20.2"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/eslint/node_modules/has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/eslint/node_modules/ignore": {
- "version": "4.0.6",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
- "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
- "dev": true,
- "engines": {
- "node": ">= 4"
- }
- },
- "node_modules/eslint/node_modules/lru-cache": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
- "dev": true,
- "dependencies": {
- "yallist": "^4.0.0"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/eslint/node_modules/semver": {
- "version": "7.3.8",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
- "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
- "dev": true,
- "dependencies": {
- "lru-cache": "^6.0.0"
- },
- "bin": {
- "semver": "bin/semver.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/eslint/node_modules/supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/eslint/node_modules/type-fest": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
- "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
- "dev": true,
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/eslint/node_modules/yallist": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
- "dev": true
- },
- "node_modules/espree": {
- "version": "7.3.1",
- "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz",
- "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==",
- "dev": true,
- "dependencies": {
- "acorn": "^7.4.0",
- "acorn-jsx": "^5.3.1",
- "eslint-visitor-keys": "^1.3.0"
- },
- "engines": {
- "node": "^10.12.0 || >=12.0.0"
- }
- },
- "node_modules/espree/node_modules/acorn": {
- "version": "7.4.1",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
- "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
- "dev": true,
- "bin": {
- "acorn": "bin/acorn"
- },
- "engines": {
- "node": ">=0.4.0"
- }
- },
- "node_modules/espree/node_modules/eslint-visitor-keys": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
- "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/esprima": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
- "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
- "dev": true,
- "bin": {
- "esparse": "bin/esparse.js",
- "esvalidate": "bin/esvalidate.js"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/esquery": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz",
- "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==",
- "dev": true,
- "dependencies": {
- "estraverse": "^5.1.0"
- },
- "engines": {
- "node": ">=0.10"
- }
- },
- "node_modules/esquery/node_modules/estraverse": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
- "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
- "dev": true,
- "engines": {
- "node": ">=4.0"
- }
- },
- "node_modules/esrecurse": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
- "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
- "dev": true,
- "dependencies": {
- "estraverse": "^5.2.0"
- },
- "engines": {
- "node": ">=4.0"
- }
- },
- "node_modules/esrecurse/node_modules/estraverse": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
- "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
- "dev": true,
- "engines": {
- "node": ">=4.0"
- }
- },
- "node_modules/estraverse": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
- "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
- "dev": true,
- "engines": {
- "node": ">=4.0"
- }
- },
- "node_modules/esutils": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
- "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/events": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
- "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
- "dev": true,
- "engines": {
- "node": ">=0.8.x"
- }
- },
- "node_modules/execa": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
- "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==",
- "dev": true,
- "dependencies": {
- "cross-spawn": "^7.0.3",
- "get-stream": "^6.0.0",
- "human-signals": "^2.1.0",
- "is-stream": "^2.0.0",
- "merge-stream": "^2.0.0",
- "npm-run-path": "^4.0.1",
- "onetime": "^5.1.2",
- "signal-exit": "^3.0.3",
- "strip-final-newline": "^2.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sindresorhus/execa?sponsor=1"
- }
- },
- "node_modules/exit": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
- "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==",
- "dev": true,
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/expect": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/expect/-/expect-29.3.1.tgz",
- "integrity": "sha512-gGb1yTgU30Q0O/tQq+z30KBWv24ApkMgFUpvKBkyLUBL68Wv8dHdJxTBZFl/iT8K/bqDHvUYRH6IIN3rToopPA==",
- "dev": true,
- "dependencies": {
- "@jest/expect-utils": "^29.3.1",
- "jest-get-type": "^29.2.0",
- "jest-matcher-utils": "^29.3.1",
- "jest-message-util": "^29.3.1",
- "jest-util": "^29.3.1"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/fast-deep-equal": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
- "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
- "dev": true
- },
- "node_modules/fast-glob": {
- "version": "3.2.12",
- "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz",
- "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==",
- "dev": true,
- "dependencies": {
- "@nodelib/fs.stat": "^2.0.2",
- "@nodelib/fs.walk": "^1.2.3",
- "glob-parent": "^5.1.2",
- "merge2": "^1.3.0",
- "micromatch": "^4.0.4"
- },
- "engines": {
- "node": ">=8.6.0"
- }
- },
- "node_modules/fast-json-stable-stringify": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
- "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
- "dev": true
- },
- "node_modules/fast-levenshtein": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
- "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
- "dev": true
- },
- "node_modules/fastest-levenshtein": {
- "version": "1.0.16",
- "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz",
- "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==",
- "dev": true,
- "engines": {
- "node": ">= 4.9.1"
- }
- },
- "node_modules/fastq": {
- "version": "1.15.0",
- "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz",
- "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==",
- "dev": true,
- "dependencies": {
- "reusify": "^1.0.4"
- }
- },
- "node_modules/fb-watchman": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz",
- "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==",
- "dev": true,
- "dependencies": {
- "bser": "2.1.1"
- }
- },
- "node_modules/file-entry-cache": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
- "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
- "dev": true,
- "dependencies": {
- "flat-cache": "^3.0.4"
- },
- "engines": {
- "node": "^10.12.0 || >=12.0.0"
- }
- },
- "node_modules/fill-range": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
- "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
- "dev": true,
- "dependencies": {
- "to-regex-range": "^5.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/find-cache-dir": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz",
- "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==",
- "dev": true,
- "dependencies": {
- "commondir": "^1.0.1",
- "make-dir": "^2.0.0",
- "pkg-dir": "^3.0.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/find-up": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
- "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
- "dev": true,
- "dependencies": {
- "locate-path": "^5.0.0",
- "path-exists": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/flat-cache": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
- "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==",
- "dev": true,
- "dependencies": {
- "flatted": "^3.1.0",
- "rimraf": "^3.0.2"
- },
- "engines": {
- "node": "^10.12.0 || >=12.0.0"
- }
- },
- "node_modules/flatted": {
- "version": "3.2.7",
- "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz",
- "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==",
- "dev": true
- },
- "node_modules/form-data": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz",
- "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==",
- "dev": true,
- "dependencies": {
- "asynckit": "^0.4.0",
- "combined-stream": "^1.0.8",
- "mime-types": "^2.1.12"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/fs-readdir-recursive": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz",
- "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==",
- "dev": true
- },
- "node_modules/fs.realpath": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
- "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
- "dev": true
- },
- "node_modules/fsevents": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
- "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
- "dev": true,
- "hasInstallScript": true,
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
- }
- },
- "node_modules/function-bind": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
- "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
- "dev": true
- },
- "node_modules/functional-red-black-tree": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
- "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==",
- "dev": true
- },
- "node_modules/gensync": {
- "version": "1.0.0-beta.2",
- "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
- "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
- "dev": true,
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/get-caller-file": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
- "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
- "dev": true,
- "engines": {
- "node": "6.* || 8.* || >= 10.*"
- }
- },
- "node_modules/get-package-type": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz",
- "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==",
- "dev": true,
- "engines": {
- "node": ">=8.0.0"
- }
- },
- "node_modules/get-stream": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
- "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
- "dev": true,
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/glob": {
- "version": "7.2.3",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
- "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
- "dev": true,
- "dependencies": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.1.1",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
- },
- "engines": {
- "node": "*"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
- "node_modules/glob-parent": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
- "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
- "dev": true,
- "dependencies": {
- "is-glob": "^4.0.1"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/glob-to-regexp": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
- "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==",
- "dev": true
- },
- "node_modules/globals": {
- "version": "11.12.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
- "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/globby": {
- "version": "11.1.0",
- "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
- "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
- "dev": true,
- "dependencies": {
- "array-union": "^2.1.0",
- "dir-glob": "^3.0.1",
- "fast-glob": "^3.2.9",
- "ignore": "^5.2.0",
- "merge2": "^1.4.1",
- "slash": "^3.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/globby/node_modules/slash": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
- "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/graceful-fs": {
- "version": "4.2.10",
- "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
- "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==",
- "dev": true
- },
- "node_modules/gzip-size": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz",
- "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==",
- "dev": true,
- "dependencies": {
- "duplexer": "^0.1.2"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/has": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
- "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
- "dev": true,
- "dependencies": {
- "function-bind": "^1.1.1"
- },
- "engines": {
- "node": ">= 0.4.0"
- }
- },
- "node_modules/has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/html-escaper": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
- "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
- "dev": true
- },
- "node_modules/human-signals": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
- "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==",
- "dev": true,
- "engines": {
- "node": ">=10.17.0"
- }
- },
- "node_modules/ignore": {
- "version": "5.2.4",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
- "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==",
- "dev": true,
- "engines": {
- "node": ">= 4"
- }
- },
- "node_modules/import-fresh": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
- "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
- "dev": true,
- "dependencies": {
- "parent-module": "^1.0.0",
- "resolve-from": "^4.0.0"
- },
- "engines": {
- "node": ">=6"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/import-fresh/node_modules/resolve-from": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
- "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/import-local": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz",
- "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==",
- "dev": true,
- "dependencies": {
- "pkg-dir": "^4.2.0",
- "resolve-cwd": "^3.0.0"
- },
- "bin": {
- "import-local-fixture": "fixtures/cli.js"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/import-local/node_modules/pkg-dir": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
- "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
- "dev": true,
- "dependencies": {
- "find-up": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/imurmurhash": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
- "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
- "dev": true,
- "engines": {
- "node": ">=0.8.19"
- }
- },
- "node_modules/inflight": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
- "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
- "dev": true,
- "dependencies": {
- "once": "^1.3.0",
- "wrappy": "1"
- }
- },
- "node_modules/inherits": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
- "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
- "dev": true
- },
- "node_modules/interpret": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz",
- "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==",
- "dev": true,
- "engines": {
- "node": ">= 0.10"
- }
- },
- "node_modules/is-arrayish": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
- "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
- "dev": true
- },
- "node_modules/is-binary-path": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
- "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
- "dev": true,
- "optional": true,
- "dependencies": {
- "binary-extensions": "^2.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/is-core-module": {
- "version": "2.11.0",
- "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz",
- "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==",
- "dev": true,
- "dependencies": {
- "has": "^1.0.3"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-extglob": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
- "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/is-fullwidth-code-point": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
- "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/is-generator-fn": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz",
- "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/is-glob": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
- "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
- "dev": true,
- "dependencies": {
- "is-extglob": "^2.1.1"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/is-number": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
- "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
- "dev": true,
- "engines": {
- "node": ">=0.12.0"
- }
- },
- "node_modules/is-plain-object": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
- "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
- "dev": true,
- "dependencies": {
- "isobject": "^3.0.1"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/is-stream": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
- "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
- "dev": true,
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/isexe": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
- "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
- "dev": true
- },
- "node_modules/isobject": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
- "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/istanbul-lib-coverage": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz",
- "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/istanbul-lib-instrument": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz",
- "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==",
- "dev": true,
- "dependencies": {
- "@babel/core": "^7.12.3",
- "@babel/parser": "^7.14.7",
- "@istanbuljs/schema": "^0.1.2",
- "istanbul-lib-coverage": "^3.2.0",
- "semver": "^6.3.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/istanbul-lib-report": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz",
- "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==",
- "dev": true,
- "dependencies": {
- "istanbul-lib-coverage": "^3.0.0",
- "make-dir": "^3.0.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/istanbul-lib-report/node_modules/has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/istanbul-lib-report/node_modules/make-dir": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
- "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
- "dev": true,
- "dependencies": {
- "semver": "^6.0.0"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/istanbul-lib-report/node_modules/supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/istanbul-lib-source-maps": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz",
- "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==",
- "dev": true,
- "dependencies": {
- "debug": "^4.1.1",
- "istanbul-lib-coverage": "^3.0.0",
- "source-map": "^0.6.1"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/istanbul-reports": {
- "version": "3.1.5",
- "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz",
- "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==",
- "dev": true,
- "dependencies": {
- "html-escaper": "^2.0.0",
- "istanbul-lib-report": "^3.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/jest": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/jest/-/jest-29.3.1.tgz",
- "integrity": "sha512-6iWfL5DTT0Np6UYs/y5Niu7WIfNv/wRTtN5RSXt2DIEft3dx3zPuw/3WJQBCJfmEzvDiEKwoqMbGD9n49+qLSA==",
- "dev": true,
- "dependencies": {
- "@jest/core": "^29.3.1",
- "@jest/types": "^29.3.1",
- "import-local": "^3.0.2",
- "jest-cli": "^29.3.1"
- },
- "bin": {
- "jest": "bin/jest.js"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- },
- "peerDependencies": {
- "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0"
- },
- "peerDependenciesMeta": {
- "node-notifier": {
- "optional": true
- }
- }
- },
- "node_modules/jest-changed-files": {
- "version": "29.2.0",
- "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.2.0.tgz",
- "integrity": "sha512-qPVmLLyBmvF5HJrY7krDisx6Voi8DmlV3GZYX0aFNbaQsZeoz1hfxcCMbqDGuQCxU1dJy9eYc2xscE8QrCCYaA==",
- "dev": true,
- "dependencies": {
- "execa": "^5.0.0",
- "p-limit": "^3.1.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-changed-files/node_modules/p-limit": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
- "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
- "dev": true,
- "dependencies": {
- "yocto-queue": "^0.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/jest-circus": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.3.1.tgz",
- "integrity": "sha512-wpr26sEvwb3qQQbdlmei+gzp6yoSSoSL6GsLPxnuayZSMrSd5Ka7IjAvatpIernBvT2+Ic6RLTg+jSebScmasg==",
- "dev": true,
- "dependencies": {
- "@jest/environment": "^29.3.1",
- "@jest/expect": "^29.3.1",
- "@jest/test-result": "^29.3.1",
- "@jest/types": "^29.3.1",
- "@types/node": "*",
- "chalk": "^4.0.0",
- "co": "^4.6.0",
- "dedent": "^0.7.0",
- "is-generator-fn": "^2.0.0",
- "jest-each": "^29.3.1",
- "jest-matcher-utils": "^29.3.1",
- "jest-message-util": "^29.3.1",
- "jest-runtime": "^29.3.1",
- "jest-snapshot": "^29.3.1",
- "jest-util": "^29.3.1",
- "p-limit": "^3.1.0",
- "pretty-format": "^29.3.1",
- "slash": "^3.0.0",
- "stack-utils": "^2.0.3"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-circus/node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/jest-circus/node_modules/chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/jest-circus/node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/jest-circus/node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "node_modules/jest-circus/node_modules/has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/jest-circus/node_modules/p-limit": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
- "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
- "dev": true,
- "dependencies": {
- "yocto-queue": "^0.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/jest-circus/node_modules/slash": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
- "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/jest-circus/node_modules/supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/jest-cli": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.3.1.tgz",
- "integrity": "sha512-TO/ewvwyvPOiBBuWZ0gm04z3WWP8TIK8acgPzE4IxgsLKQgb377NYGrQLc3Wl/7ndWzIH2CDNNsUjGxwLL43VQ==",
- "dev": true,
- "dependencies": {
- "@jest/core": "^29.3.1",
- "@jest/test-result": "^29.3.1",
- "@jest/types": "^29.3.1",
- "chalk": "^4.0.0",
- "exit": "^0.1.2",
- "graceful-fs": "^4.2.9",
- "import-local": "^3.0.2",
- "jest-config": "^29.3.1",
- "jest-util": "^29.3.1",
- "jest-validate": "^29.3.1",
- "prompts": "^2.0.1",
- "yargs": "^17.3.1"
- },
- "bin": {
- "jest": "bin/jest.js"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- },
- "peerDependencies": {
- "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0"
- },
- "peerDependenciesMeta": {
- "node-notifier": {
- "optional": true
- }
- }
- },
- "node_modules/jest-cli/node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/jest-cli/node_modules/chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/jest-cli/node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/jest-cli/node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "node_modules/jest-cli/node_modules/has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/jest-cli/node_modules/supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/jest-config": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.3.1.tgz",
- "integrity": "sha512-y0tFHdj2WnTEhxmGUK1T7fgLen7YK4RtfvpLFBXfQkh2eMJAQq24Vx9472lvn5wg0MAO6B+iPfJfzdR9hJYalg==",
- "dev": true,
- "dependencies": {
- "@babel/core": "^7.11.6",
- "@jest/test-sequencer": "^29.3.1",
- "@jest/types": "^29.3.1",
- "babel-jest": "^29.3.1",
- "chalk": "^4.0.0",
- "ci-info": "^3.2.0",
- "deepmerge": "^4.2.2",
- "glob": "^7.1.3",
- "graceful-fs": "^4.2.9",
- "jest-circus": "^29.3.1",
- "jest-environment-node": "^29.3.1",
- "jest-get-type": "^29.2.0",
- "jest-regex-util": "^29.2.0",
- "jest-resolve": "^29.3.1",
- "jest-runner": "^29.3.1",
- "jest-util": "^29.3.1",
- "jest-validate": "^29.3.1",
- "micromatch": "^4.0.4",
- "parse-json": "^5.2.0",
- "pretty-format": "^29.3.1",
- "slash": "^3.0.0",
- "strip-json-comments": "^3.1.1"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- },
- "peerDependencies": {
- "@types/node": "*",
- "ts-node": ">=9.0.0"
- },
- "peerDependenciesMeta": {
- "@types/node": {
- "optional": true
- },
- "ts-node": {
- "optional": true
- }
- }
- },
- "node_modules/jest-config/node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/jest-config/node_modules/chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/jest-config/node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/jest-config/node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "node_modules/jest-config/node_modules/has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/jest-config/node_modules/slash": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
- "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/jest-config/node_modules/supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/jest-diff": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.3.1.tgz",
- "integrity": "sha512-vU8vyiO7568tmin2lA3r2DP8oRvzhvRcD4DjpXc6uGveQodyk7CKLhQlCSiwgx3g0pFaE88/KLZ0yaTWMc4Uiw==",
- "dev": true,
- "dependencies": {
- "chalk": "^4.0.0",
- "diff-sequences": "^29.3.1",
- "jest-get-type": "^29.2.0",
- "pretty-format": "^29.3.1"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-diff/node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/jest-diff/node_modules/chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/jest-diff/node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/jest-diff/node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "node_modules/jest-diff/node_modules/has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/jest-diff/node_modules/supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/jest-docblock": {
- "version": "29.2.0",
- "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.2.0.tgz",
- "integrity": "sha512-bkxUsxTgWQGbXV5IENmfiIuqZhJcyvF7tU4zJ/7ioTutdz4ToB5Yx6JOFBpgI+TphRY4lhOyCWGNH/QFQh5T6A==",
- "dev": true,
- "dependencies": {
- "detect-newline": "^3.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-each": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.3.1.tgz",
- "integrity": "sha512-qrZH7PmFB9rEzCSl00BWjZYuS1BSOH8lLuC0azQE9lQrAx3PWGKHTDudQiOSwIy5dGAJh7KA0ScYlCP7JxvFYA==",
- "dev": true,
- "dependencies": {
- "@jest/types": "^29.3.1",
- "chalk": "^4.0.0",
- "jest-get-type": "^29.2.0",
- "jest-util": "^29.3.1",
- "pretty-format": "^29.3.1"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-each/node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/jest-each/node_modules/chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/jest-each/node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/jest-each/node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "node_modules/jest-each/node_modules/has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/jest-each/node_modules/supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/jest-environment-node": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.3.1.tgz",
- "integrity": "sha512-xm2THL18Xf5sIHoU7OThBPtuH6Lerd+Y1NLYiZJlkE3hbE+7N7r8uvHIl/FkZ5ymKXJe/11SQuf3fv4v6rUMag==",
- "dev": true,
- "dependencies": {
- "@jest/environment": "^29.3.1",
- "@jest/fake-timers": "^29.3.1",
- "@jest/types": "^29.3.1",
- "@types/node": "*",
- "jest-mock": "^29.3.1",
- "jest-util": "^29.3.1"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-get-type": {
- "version": "29.2.0",
- "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.2.0.tgz",
- "integrity": "sha512-uXNJlg8hKFEnDgFsrCjznB+sTxdkuqiCL6zMgA75qEbAJjJYTs9XPrvDctrEig2GDow22T/LvHgO57iJhXB/UA==",
- "dev": true,
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-haste-map": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.3.1.tgz",
- "integrity": "sha512-/FFtvoG1xjbbPXQLFef+WSU4yrc0fc0Dds6aRPBojUid7qlPqZvxdUBA03HW0fnVHXVCnCdkuoghYItKNzc/0A==",
- "dev": true,
- "dependencies": {
- "@jest/types": "^29.3.1",
- "@types/graceful-fs": "^4.1.3",
- "@types/node": "*",
- "anymatch": "^3.0.3",
- "fb-watchman": "^2.0.0",
- "graceful-fs": "^4.2.9",
- "jest-regex-util": "^29.2.0",
- "jest-util": "^29.3.1",
- "jest-worker": "^29.3.1",
- "micromatch": "^4.0.4",
- "walker": "^1.0.8"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- },
- "optionalDependencies": {
- "fsevents": "^2.3.2"
- }
- },
- "node_modules/jest-leak-detector": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.3.1.tgz",
- "integrity": "sha512-3DA/VVXj4zFOPagGkuqHnSQf1GZBmmlagpguxEERO6Pla2g84Q1MaVIB3YMxgUaFIaYag8ZnTyQgiZ35YEqAQA==",
- "dev": true,
- "dependencies": {
- "jest-get-type": "^29.2.0",
- "pretty-format": "^29.3.1"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-matcher-utils": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.3.1.tgz",
- "integrity": "sha512-fkRMZUAScup3txIKfMe3AIZZmPEjWEdsPJFK3AIy5qRohWqQFg1qrmKfYXR9qEkNc7OdAu2N4KPHibEmy4HPeQ==",
- "dev": true,
- "dependencies": {
- "chalk": "^4.0.0",
- "jest-diff": "^29.3.1",
- "jest-get-type": "^29.2.0",
- "pretty-format": "^29.3.1"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-matcher-utils/node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/jest-matcher-utils/node_modules/chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/jest-matcher-utils/node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/jest-matcher-utils/node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "node_modules/jest-matcher-utils/node_modules/has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/jest-matcher-utils/node_modules/supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/jest-message-util": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.3.1.tgz",
- "integrity": "sha512-lMJTbgNcDm5z+6KDxWtqOFWlGQxD6XaYwBqHR8kmpkP+WWWG90I35kdtQHY67Ay5CSuydkTBbJG+tH9JShFCyA==",
- "dev": true,
- "dependencies": {
- "@babel/code-frame": "^7.12.13",
- "@jest/types": "^29.3.1",
- "@types/stack-utils": "^2.0.0",
- "chalk": "^4.0.0",
- "graceful-fs": "^4.2.9",
- "micromatch": "^4.0.4",
- "pretty-format": "^29.3.1",
- "slash": "^3.0.0",
- "stack-utils": "^2.0.3"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-message-util/node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/jest-message-util/node_modules/chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/jest-message-util/node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/jest-message-util/node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "node_modules/jest-message-util/node_modules/has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/jest-message-util/node_modules/slash": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
- "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/jest-message-util/node_modules/supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/jest-mock": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.3.1.tgz",
- "integrity": "sha512-H8/qFDtDVMFvFP4X8NuOT3XRDzOUTz+FeACjufHzsOIBAxivLqkB1PoLCaJx9iPPQ8dZThHPp/G3WRWyMgA3JA==",
- "dev": true,
- "dependencies": {
- "@jest/types": "^29.3.1",
- "@types/node": "*",
- "jest-util": "^29.3.1"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-pnp-resolver": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz",
- "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==",
- "dev": true,
- "engines": {
- "node": ">=6"
- },
- "peerDependencies": {
- "jest-resolve": "*"
- },
- "peerDependenciesMeta": {
- "jest-resolve": {
- "optional": true
- }
- }
- },
- "node_modules/jest-regex-util": {
- "version": "29.2.0",
- "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.2.0.tgz",
- "integrity": "sha512-6yXn0kg2JXzH30cr2NlThF+70iuO/3irbaB4mh5WyqNIvLLP+B6sFdluO1/1RJmslyh/f9osnefECflHvTbwVA==",
- "dev": true,
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-resolve": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.3.1.tgz",
- "integrity": "sha512-amXJgH/Ng712w3Uz5gqzFBBjxV8WFLSmNjoreBGMqxgCz5cH7swmBZzgBaCIOsvb0NbpJ0vgaSFdJqMdT+rADw==",
- "dev": true,
- "dependencies": {
- "chalk": "^4.0.0",
- "graceful-fs": "^4.2.9",
- "jest-haste-map": "^29.3.1",
- "jest-pnp-resolver": "^1.2.2",
- "jest-util": "^29.3.1",
- "jest-validate": "^29.3.1",
- "resolve": "^1.20.0",
- "resolve.exports": "^1.1.0",
- "slash": "^3.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-resolve-dependencies": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.3.1.tgz",
- "integrity": "sha512-Vk0cYq0byRw2WluNmNWGqPeRnZ3p3hHmjJMp2dyyZeYIfiBskwq4rpiuGFR6QGAdbj58WC7HN4hQHjf2mpvrLA==",
- "dev": true,
- "dependencies": {
- "jest-regex-util": "^29.2.0",
- "jest-snapshot": "^29.3.1"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-resolve/node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/jest-resolve/node_modules/chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/jest-resolve/node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/jest-resolve/node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "node_modules/jest-resolve/node_modules/has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/jest-resolve/node_modules/slash": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
- "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/jest-resolve/node_modules/supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/jest-runner": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.3.1.tgz",
- "integrity": "sha512-oFvcwRNrKMtE6u9+AQPMATxFcTySyKfLhvso7Sdk/rNpbhg4g2GAGCopiInk1OP4q6gz3n6MajW4+fnHWlU3bA==",
- "dev": true,
- "dependencies": {
- "@jest/console": "^29.3.1",
- "@jest/environment": "^29.3.1",
- "@jest/test-result": "^29.3.1",
- "@jest/transform": "^29.3.1",
- "@jest/types": "^29.3.1",
- "@types/node": "*",
- "chalk": "^4.0.0",
- "emittery": "^0.13.1",
- "graceful-fs": "^4.2.9",
- "jest-docblock": "^29.2.0",
- "jest-environment-node": "^29.3.1",
- "jest-haste-map": "^29.3.1",
- "jest-leak-detector": "^29.3.1",
- "jest-message-util": "^29.3.1",
- "jest-resolve": "^29.3.1",
- "jest-runtime": "^29.3.1",
- "jest-util": "^29.3.1",
- "jest-watcher": "^29.3.1",
- "jest-worker": "^29.3.1",
- "p-limit": "^3.1.0",
- "source-map-support": "0.5.13"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-runner/node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/jest-runner/node_modules/chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/jest-runner/node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/jest-runner/node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "node_modules/jest-runner/node_modules/has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/jest-runner/node_modules/p-limit": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
- "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
- "dev": true,
- "dependencies": {
- "yocto-queue": "^0.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/jest-runner/node_modules/source-map-support": {
- "version": "0.5.13",
- "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz",
- "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==",
- "dev": true,
- "dependencies": {
- "buffer-from": "^1.0.0",
- "source-map": "^0.6.0"
- }
- },
- "node_modules/jest-runner/node_modules/supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/jest-runtime": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.3.1.tgz",
- "integrity": "sha512-jLzkIxIqXwBEOZx7wx9OO9sxoZmgT2NhmQKzHQm1xwR1kNW/dn0OjxR424VwHHf1SPN6Qwlb5pp1oGCeFTQ62A==",
- "dev": true,
- "dependencies": {
- "@jest/environment": "^29.3.1",
- "@jest/fake-timers": "^29.3.1",
- "@jest/globals": "^29.3.1",
- "@jest/source-map": "^29.2.0",
- "@jest/test-result": "^29.3.1",
- "@jest/transform": "^29.3.1",
- "@jest/types": "^29.3.1",
- "@types/node": "*",
- "chalk": "^4.0.0",
- "cjs-module-lexer": "^1.0.0",
- "collect-v8-coverage": "^1.0.0",
- "glob": "^7.1.3",
- "graceful-fs": "^4.2.9",
- "jest-haste-map": "^29.3.1",
- "jest-message-util": "^29.3.1",
- "jest-mock": "^29.3.1",
- "jest-regex-util": "^29.2.0",
- "jest-resolve": "^29.3.1",
- "jest-snapshot": "^29.3.1",
- "jest-util": "^29.3.1",
- "slash": "^3.0.0",
- "strip-bom": "^4.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-runtime/node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/jest-runtime/node_modules/chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/jest-runtime/node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/jest-runtime/node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "node_modules/jest-runtime/node_modules/has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/jest-runtime/node_modules/slash": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
- "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/jest-runtime/node_modules/supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/jest-snapshot": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.3.1.tgz",
- "integrity": "sha512-+3JOc+s28upYLI2OJM4PWRGK9AgpsMs/ekNryUV0yMBClT9B1DF2u2qay8YxcQd338PPYSFNb0lsar1B49sLDA==",
- "dev": true,
- "dependencies": {
- "@babel/core": "^7.11.6",
- "@babel/generator": "^7.7.2",
- "@babel/plugin-syntax-jsx": "^7.7.2",
- "@babel/plugin-syntax-typescript": "^7.7.2",
- "@babel/traverse": "^7.7.2",
- "@babel/types": "^7.3.3",
- "@jest/expect-utils": "^29.3.1",
- "@jest/transform": "^29.3.1",
- "@jest/types": "^29.3.1",
- "@types/babel__traverse": "^7.0.6",
- "@types/prettier": "^2.1.5",
- "babel-preset-current-node-syntax": "^1.0.0",
- "chalk": "^4.0.0",
- "expect": "^29.3.1",
- "graceful-fs": "^4.2.9",
- "jest-diff": "^29.3.1",
- "jest-get-type": "^29.2.0",
- "jest-haste-map": "^29.3.1",
- "jest-matcher-utils": "^29.3.1",
- "jest-message-util": "^29.3.1",
- "jest-util": "^29.3.1",
- "natural-compare": "^1.4.0",
- "pretty-format": "^29.3.1",
- "semver": "^7.3.5"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-snapshot/node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/jest-snapshot/node_modules/chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/jest-snapshot/node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/jest-snapshot/node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "node_modules/jest-snapshot/node_modules/has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/jest-snapshot/node_modules/lru-cache": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
- "dev": true,
- "dependencies": {
- "yallist": "^4.0.0"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/jest-snapshot/node_modules/semver": {
- "version": "7.3.8",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
- "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
- "dev": true,
- "dependencies": {
- "lru-cache": "^6.0.0"
- },
- "bin": {
- "semver": "bin/semver.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/jest-snapshot/node_modules/supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/jest-snapshot/node_modules/yallist": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
- "dev": true
- },
- "node_modules/jest-util": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.3.1.tgz",
- "integrity": "sha512-7YOVZaiX7RJLv76ZfHt4nbNEzzTRiMW/IiOG7ZOKmTXmoGBxUDefgMAxQubu6WPVqP5zSzAdZG0FfLcC7HOIFQ==",
- "dev": true,
- "dependencies": {
- "@jest/types": "^29.3.1",
- "@types/node": "*",
- "chalk": "^4.0.0",
- "ci-info": "^3.2.0",
- "graceful-fs": "^4.2.9",
- "picomatch": "^2.2.3"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-util/node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/jest-util/node_modules/chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/jest-util/node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/jest-util/node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "node_modules/jest-util/node_modules/has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/jest-util/node_modules/supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/jest-validate": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.3.1.tgz",
- "integrity": "sha512-N9Lr3oYR2Mpzuelp1F8negJR3YE+L1ebk1rYA5qYo9TTY3f9OWdptLoNSPP9itOCBIRBqjt/S5XHlzYglLN67g==",
- "dev": true,
- "dependencies": {
- "@jest/types": "^29.3.1",
- "camelcase": "^6.2.0",
- "chalk": "^4.0.0",
- "jest-get-type": "^29.2.0",
- "leven": "^3.1.0",
- "pretty-format": "^29.3.1"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-validate/node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/jest-validate/node_modules/camelcase": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
- "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
- "dev": true,
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/jest-validate/node_modules/chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/jest-validate/node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/jest-validate/node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "node_modules/jest-validate/node_modules/has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/jest-validate/node_modules/supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/jest-watcher": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.3.1.tgz",
- "integrity": "sha512-RspXG2BQFDsZSRKGCT/NiNa8RkQ1iKAjrO0//soTMWx/QUt+OcxMqMSBxz23PYGqUuWm2+m2mNNsmj0eIoOaFg==",
- "dev": true,
- "dependencies": {
- "@jest/test-result": "^29.3.1",
- "@jest/types": "^29.3.1",
- "@types/node": "*",
- "ansi-escapes": "^4.2.1",
- "chalk": "^4.0.0",
- "emittery": "^0.13.1",
- "jest-util": "^29.3.1",
- "string-length": "^4.0.1"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-watcher/node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/jest-watcher/node_modules/chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/jest-watcher/node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/jest-watcher/node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "node_modules/jest-watcher/node_modules/has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/jest-watcher/node_modules/supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/jest-worker": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.3.1.tgz",
- "integrity": "sha512-lY4AnnmsEWeiXirAIA0c9SDPbuCBq8IYuDVL8PMm0MZ2PEs2yPvRA/J64QBXuZp7CYKrDM/rmNrc9/i3KJQncw==",
- "dev": true,
- "dependencies": {
- "@types/node": "*",
- "jest-util": "^29.3.1",
- "merge-stream": "^2.0.0",
- "supports-color": "^8.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-worker/node_modules/has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/jest-worker/node_modules/supports-color": {
- "version": "8.1.1",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
- "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
- "dev": true,
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/supports-color?sponsor=1"
- }
- },
- "node_modules/js-tokens": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
- "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
- "dev": true
- },
- "node_modules/js-yaml": {
- "version": "3.14.1",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
- "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
- "dev": true,
- "dependencies": {
- "argparse": "^1.0.7",
- "esprima": "^4.0.0"
- },
- "bin": {
- "js-yaml": "bin/js-yaml.js"
- }
- },
- "node_modules/jsesc": {
- "version": "2.5.2",
- "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
- "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
- "dev": true,
- "bin": {
- "jsesc": "bin/jsesc"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/json-parse-even-better-errors": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
- "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
- "dev": true
- },
- "node_modules/json-schema-traverse": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
- "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
- "dev": true
- },
- "node_modules/json-stable-stringify-without-jsonify": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
- "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
- "dev": true
- },
- "node_modules/json5": {
- "version": "2.2.3",
- "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
- "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
- "dev": true,
- "bin": {
- "json5": "lib/cli.js"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/kind-of": {
- "version": "6.0.3",
- "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
- "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/kleur": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
- "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/leven": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
- "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/levn": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
- "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
- "dev": true,
- "dependencies": {
- "prelude-ls": "^1.2.1",
- "type-check": "~0.4.0"
- },
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/lines-and-columns": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
- "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
- "dev": true
- },
- "node_modules/loader-runner": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz",
- "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==",
- "dev": true,
- "engines": {
- "node": ">=6.11.5"
- }
- },
- "node_modules/loader-utils": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz",
- "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==",
- "dev": true,
- "dependencies": {
- "big.js": "^5.2.2",
- "emojis-list": "^3.0.0",
- "json5": "^2.1.2"
- },
- "engines": {
- "node": ">=8.9.0"
- }
- },
- "node_modules/locate-path": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
- "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
- "dev": true,
- "dependencies": {
- "p-locate": "^4.1.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/lodash": {
- "version": "4.17.21",
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
- "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
- "dev": true
- },
- "node_modules/lodash.debounce": {
- "version": "4.0.8",
- "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
- "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==",
- "dev": true
- },
- "node_modules/lodash.memoize": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
- "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==",
- "dev": true
- },
- "node_modules/lodash.merge": {
- "version": "4.6.2",
- "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
- "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
- "dev": true
- },
- "node_modules/lodash.truncate": {
- "version": "4.4.2",
- "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz",
- "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==",
- "dev": true
- },
- "node_modules/lru-cache": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
- "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
- "dev": true,
- "dependencies": {
- "yallist": "^3.0.2"
- }
- },
- "node_modules/make-dir": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
- "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==",
- "dev": true,
- "dependencies": {
- "pify": "^4.0.1",
- "semver": "^5.6.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/make-dir/node_modules/semver": {
- "version": "5.7.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
- "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
- "dev": true,
- "bin": {
- "semver": "bin/semver"
- }
- },
- "node_modules/make-error": {
- "version": "1.3.6",
- "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
- "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
- "dev": true
- },
- "node_modules/makeerror": {
- "version": "1.0.12",
- "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz",
- "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==",
- "dev": true,
- "dependencies": {
- "tmpl": "1.0.5"
- }
- },
- "node_modules/merge-stream": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
- "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
- "dev": true
- },
- "node_modules/merge2": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
- "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
- "dev": true,
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/micromatch": {
- "version": "4.0.5",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
- "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
- "dev": true,
- "dependencies": {
- "braces": "^3.0.2",
- "picomatch": "^2.3.1"
- },
- "engines": {
- "node": ">=8.6"
- }
- },
- "node_modules/mime-db": {
- "version": "1.52.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
- "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
- "dev": true,
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/mime-types": {
- "version": "2.1.35",
- "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
- "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
- "dev": true,
- "dependencies": {
- "mime-db": "1.52.0"
- },
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/mimic-fn": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
- "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
- "dev": true,
- "dependencies": {
- "brace-expansion": "^1.1.7"
- },
- "engines": {
- "node": "*"
- }
- },
- "node_modules/mrmime": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz",
- "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==",
- "dev": true,
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
- "dev": true
- },
- "node_modules/natural-compare": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
- "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
- "dev": true
- },
- "node_modules/natural-compare-lite": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz",
- "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==",
- "dev": true
- },
- "node_modules/neo-async": {
- "version": "2.6.2",
- "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
- "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
- "dev": true
- },
- "node_modules/node-fetch": {
- "version": "2.6.8",
- "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.8.tgz",
- "integrity": "sha512-RZ6dBYuj8dRSfxpUSu+NsdF1dpPpluJxwOp+6IoDp/sH2QNDSvurYsAa+F1WxY2RjA1iP93xhcsUoYbF2XBqVg==",
- "dependencies": {
- "whatwg-url": "^5.0.0"
- },
- "engines": {
- "node": "4.x || >=6.0.0"
- },
- "peerDependencies": {
- "encoding": "^0.1.0"
- },
- "peerDependenciesMeta": {
- "encoding": {
- "optional": true
- }
- }
- },
- "node_modules/node-fetch/node_modules/tr46": {
- "version": "0.0.3",
- "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
- "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
- },
- "node_modules/node-fetch/node_modules/webidl-conversions": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
- "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
- },
- "node_modules/node-fetch/node_modules/whatwg-url": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
- "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
- "dependencies": {
- "tr46": "~0.0.3",
- "webidl-conversions": "^3.0.0"
- }
- },
- "node_modules/node-int64": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
- "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==",
- "dev": true
- },
- "node_modules/node-releases": {
- "version": "2.0.8",
- "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.8.tgz",
- "integrity": "sha512-dFSmB8fFHEH/s81Xi+Y/15DQY6VHW81nXRj86EMSL3lmuTmK1e+aT4wrFCkTbm+gSwkw4KpX+rT/pMM2c1mF+A==",
- "dev": true
- },
- "node_modules/normalize-path": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
- "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/npm-run-path": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
- "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
- "dev": true,
- "dependencies": {
- "path-key": "^3.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/once": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
- "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
- "dev": true,
- "dependencies": {
- "wrappy": "1"
- }
- },
- "node_modules/onetime": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
- "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
- "dev": true,
- "dependencies": {
- "mimic-fn": "^2.1.0"
- },
- "engines": {
- "node": ">=6"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/opener": {
- "version": "1.5.2",
- "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz",
- "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==",
- "dev": true,
- "bin": {
- "opener": "bin/opener-bin.js"
- }
- },
- "node_modules/optionator": {
- "version": "0.9.1",
- "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
- "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==",
- "dev": true,
- "dependencies": {
- "deep-is": "^0.1.3",
- "fast-levenshtein": "^2.0.6",
- "levn": "^0.4.1",
- "prelude-ls": "^1.2.1",
- "type-check": "^0.4.0",
- "word-wrap": "^1.2.3"
- },
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/p-limit": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
- "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
- "dev": true,
- "dependencies": {
- "p-try": "^2.0.0"
- },
- "engines": {
- "node": ">=6"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/p-locate": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
- "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
- "dev": true,
- "dependencies": {
- "p-limit": "^2.2.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/p-try": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
- "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/parent-module": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
- "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
- "dev": true,
- "dependencies": {
- "callsites": "^3.0.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/parse-json": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
- "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
- "dev": true,
- "dependencies": {
- "@babel/code-frame": "^7.0.0",
- "error-ex": "^1.3.1",
- "json-parse-even-better-errors": "^2.3.0",
- "lines-and-columns": "^1.1.6"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/path-exists": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
- "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/path-is-absolute": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
- "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/path-key": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
- "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/path-parse": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
- "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
- "dev": true
- },
- "node_modules/path-type": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
- "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/picocolors": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
- "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
- "dev": true
- },
- "node_modules/picomatch": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
- "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
- "dev": true,
- "engines": {
- "node": ">=8.6"
- },
- "funding": {
- "url": "https://github.com/sponsors/jonschlinkert"
- }
- },
- "node_modules/pify": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
- "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/pirates": {
- "version": "4.0.5",
- "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz",
- "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==",
- "dev": true,
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/pkg-dir": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz",
- "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==",
- "dev": true,
- "dependencies": {
- "find-up": "^3.0.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/pkg-dir/node_modules/find-up": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
- "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
- "dev": true,
- "dependencies": {
- "locate-path": "^3.0.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/pkg-dir/node_modules/locate-path": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
- "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
- "dev": true,
- "dependencies": {
- "p-locate": "^3.0.0",
- "path-exists": "^3.0.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/pkg-dir/node_modules/p-locate": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
- "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
- "dev": true,
- "dependencies": {
- "p-limit": "^2.0.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/pkg-dir/node_modules/path-exists": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
- "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/prelude-ls": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
- "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
- "dev": true,
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/prettier": {
- "version": "2.8.1",
- "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.1.tgz",
- "integrity": "sha512-lqGoSJBQNJidqCHE80vqZJHWHRFoNYsSpP9AjFhlhi9ODCJA541svILes/+/1GM3VaL/abZi7cpFzOpdR9UPKg==",
- "dev": true,
- "bin": {
- "prettier": "bin-prettier.js"
- },
- "engines": {
- "node": ">=10.13.0"
- },
- "funding": {
- "url": "https://github.com/prettier/prettier?sponsor=1"
- }
- },
- "node_modules/pretty-format": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.3.1.tgz",
- "integrity": "sha512-FyLnmb1cYJV8biEIiRyzRFvs2lry7PPIvOqKVe1GCUEYg4YGmlx1qG9EJNMxArYm7piII4qb8UV1Pncq5dxmcg==",
- "dev": true,
- "dependencies": {
- "@jest/schemas": "^29.0.0",
- "ansi-styles": "^5.0.0",
- "react-is": "^18.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/pretty-format/node_modules/ansi-styles": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
- "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
- "dev": true,
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/progress": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
- "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
- "dev": true,
- "engines": {
- "node": ">=0.4.0"
- }
- },
- "node_modules/prompts": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz",
- "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==",
- "dev": true,
- "dependencies": {
- "kleur": "^3.0.3",
- "sisteransi": "^1.0.5"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/punycode": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
- "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/queue-microtask": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
- "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ]
- },
- "node_modules/randombytes": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
- "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
- "dev": true,
- "dependencies": {
- "safe-buffer": "^5.1.0"
- }
- },
- "node_modules/react-is": {
- "version": "18.2.0",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
- "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==",
- "dev": true
- },
- "node_modules/readdirp": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
- "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
- "dev": true,
- "optional": true,
- "dependencies": {
- "picomatch": "^2.2.1"
- },
- "engines": {
- "node": ">=8.10.0"
- }
- },
- "node_modules/rechoir": {
- "version": "0.7.1",
- "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz",
- "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==",
- "dev": true,
- "dependencies": {
- "resolve": "^1.9.0"
- },
- "engines": {
- "node": ">= 0.10"
- }
- },
- "node_modules/regenerate": {
- "version": "1.4.2",
- "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
- "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==",
- "dev": true
- },
- "node_modules/regenerate-unicode-properties": {
- "version": "10.1.0",
- "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz",
- "integrity": "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==",
- "dev": true,
- "dependencies": {
- "regenerate": "^1.4.2"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/regenerator-runtime": {
- "version": "0.13.11",
- "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
- "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==",
- "dev": true
- },
- "node_modules/regenerator-transform": {
- "version": "0.15.1",
- "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.1.tgz",
- "integrity": "sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg==",
- "dev": true,
- "dependencies": {
- "@babel/runtime": "^7.8.4"
- }
- },
- "node_modules/regexpp": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
- "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==",
- "dev": true,
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/mysticatea"
- }
- },
- "node_modules/regexpu-core": {
- "version": "5.2.2",
- "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.2.2.tgz",
- "integrity": "sha512-T0+1Zp2wjF/juXMrMxHxidqGYn8U4R+zleSJhX9tQ1PUsS8a9UtYfbsF9LdiVgNX3kiX8RNaKM42nfSgvFJjmw==",
- "dev": true,
- "dependencies": {
- "regenerate": "^1.4.2",
- "regenerate-unicode-properties": "^10.1.0",
- "regjsgen": "^0.7.1",
- "regjsparser": "^0.9.1",
- "unicode-match-property-ecmascript": "^2.0.0",
- "unicode-match-property-value-ecmascript": "^2.1.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/regjsgen": {
- "version": "0.7.1",
- "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.7.1.tgz",
- "integrity": "sha512-RAt+8H2ZEzHeYWxZ3H2z6tF18zyyOnlcdaafLrm21Bguj7uZy6ULibiAFdXEtKQY4Sy7wDTwDiOazasMLc4KPA==",
- "dev": true
- },
- "node_modules/regjsparser": {
- "version": "0.9.1",
- "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz",
- "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==",
- "dev": true,
- "dependencies": {
- "jsesc": "~0.5.0"
- },
- "bin": {
- "regjsparser": "bin/parser"
- }
- },
- "node_modules/regjsparser/node_modules/jsesc": {
- "version": "0.5.0",
- "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz",
- "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==",
- "dev": true,
- "bin": {
- "jsesc": "bin/jsesc"
- }
- },
- "node_modules/require-directory": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
- "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/require-from-string": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
- "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/resolve": {
- "version": "1.22.1",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
- "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
- "dev": true,
- "dependencies": {
- "is-core-module": "^2.9.0",
- "path-parse": "^1.0.7",
- "supports-preserve-symlinks-flag": "^1.0.0"
- },
- "bin": {
- "resolve": "bin/resolve"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/resolve-cwd": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz",
- "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==",
- "dev": true,
- "dependencies": {
- "resolve-from": "^5.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/resolve-from": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
- "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/resolve.exports": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.1.tgz",
- "integrity": "sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ==",
- "dev": true,
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/reusify": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
- "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
- "dev": true,
- "engines": {
- "iojs": ">=1.0.0",
- "node": ">=0.10.0"
- }
- },
- "node_modules/rfdc": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz",
- "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA=="
- },
- "node_modules/rimraf": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
- "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
- "dev": true,
- "dependencies": {
- "glob": "^7.1.3"
- },
- "bin": {
- "rimraf": "bin.js"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
- "node_modules/run-parallel": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
- "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ],
- "dependencies": {
- "queue-microtask": "^1.2.2"
- }
- },
- "node_modules/safe-buffer": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
- "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ]
- },
- "node_modules/schema-utils": {
- "version": "2.7.1",
- "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz",
- "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==",
- "dev": true,
- "dependencies": {
- "@types/json-schema": "^7.0.5",
- "ajv": "^6.12.4",
- "ajv-keywords": "^3.5.2"
- },
- "engines": {
- "node": ">= 8.9.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/webpack"
- }
- },
- "node_modules/semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
- "dev": true,
- "bin": {
- "semver": "bin/semver.js"
- }
- },
- "node_modules/serialize-javascript": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz",
- "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==",
- "dev": true,
- "dependencies": {
- "randombytes": "^2.1.0"
- }
- },
- "node_modules/shallow-clone": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz",
- "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==",
- "dev": true,
- "dependencies": {
- "kind-of": "^6.0.2"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/shebang-command": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
- "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
- "dev": true,
- "dependencies": {
- "shebang-regex": "^3.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/shebang-regex": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
- "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/signal-exit": {
- "version": "3.0.7",
- "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
- "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
- "dev": true
- },
- "node_modules/sirv": {
- "version": "1.0.19",
- "resolved": "https://registry.npmjs.org/sirv/-/sirv-1.0.19.tgz",
- "integrity": "sha512-JuLThK3TnZG1TAKDwNIqNq6QA2afLOCcm+iE8D1Kj3GA40pSPsxQjjJl0J8X3tsR7T+CP1GavpzLwYkgVLWrZQ==",
- "dev": true,
- "dependencies": {
- "@polka/url": "^1.0.0-next.20",
- "mrmime": "^1.0.0",
- "totalist": "^1.0.0"
- },
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/sisteransi": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
- "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==",
- "dev": true
- },
- "node_modules/slash": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz",
- "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/slice-ansi": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz",
- "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^4.0.0",
- "astral-regex": "^2.0.0",
- "is-fullwidth-code-point": "^3.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/slice-ansi?sponsor=1"
- }
- },
- "node_modules/slice-ansi/node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/slice-ansi/node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/slice-ansi/node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "node_modules/source-map": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
- "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/source-map-support": {
- "version": "0.5.21",
- "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
- "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
- "dev": true,
- "dependencies": {
- "buffer-from": "^1.0.0",
- "source-map": "^0.6.0"
- }
- },
- "node_modules/sprintf-js": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
- "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
- "dev": true
- },
- "node_modules/stack-utils": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz",
- "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==",
- "dev": true,
- "dependencies": {
- "escape-string-regexp": "^2.0.0"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/stack-utils/node_modules/escape-string-regexp": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz",
- "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/string-length": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz",
- "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==",
- "dev": true,
- "dependencies": {
- "char-regex": "^1.0.2",
- "strip-ansi": "^6.0.0"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/string-width": {
- "version": "4.2.3",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
- "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
- "dev": true,
- "dependencies": {
- "emoji-regex": "^8.0.0",
- "is-fullwidth-code-point": "^3.0.0",
- "strip-ansi": "^6.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/strip-ansi": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
- "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "dev": true,
- "dependencies": {
- "ansi-regex": "^5.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/strip-bom": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz",
- "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/strip-final-newline": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
- "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/strip-json-comments": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
- "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
- "dev": true,
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/supports-color": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
- "dev": true,
- "dependencies": {
- "has-flag": "^3.0.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/supports-preserve-symlinks-flag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
- "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
- "dev": true,
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/table": {
- "version": "6.8.1",
- "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz",
- "integrity": "sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==",
- "dev": true,
- "dependencies": {
- "ajv": "^8.0.1",
- "lodash.truncate": "^4.4.2",
- "slice-ansi": "^4.0.0",
- "string-width": "^4.2.3",
- "strip-ansi": "^6.0.1"
- },
- "engines": {
- "node": ">=10.0.0"
- }
- },
- "node_modules/table/node_modules/ajv": {
- "version": "8.12.0",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
- "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
- "dev": true,
- "dependencies": {
- "fast-deep-equal": "^3.1.1",
- "json-schema-traverse": "^1.0.0",
- "require-from-string": "^2.0.2",
- "uri-js": "^4.2.2"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/epoberezkin"
- }
- },
- "node_modules/table/node_modules/json-schema-traverse": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
- "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
- "dev": true
- },
- "node_modules/tapable": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
- "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/terser": {
- "version": "5.16.1",
- "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.1.tgz",
- "integrity": "sha512-xvQfyfA1ayT0qdK47zskQgRZeWLoOQ8JQ6mIgRGVNwZKdQMU+5FkCBjmv4QjcrTzyZquRw2FVtlJSRUmMKQslw==",
- "dev": true,
- "dependencies": {
- "@jridgewell/source-map": "^0.3.2",
- "acorn": "^8.5.0",
- "commander": "^2.20.0",
- "source-map-support": "~0.5.20"
- },
- "bin": {
- "terser": "bin/terser"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/terser-webpack-plugin": {
- "version": "5.3.6",
- "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.6.tgz",
- "integrity": "sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ==",
- "dev": true,
- "dependencies": {
- "@jridgewell/trace-mapping": "^0.3.14",
- "jest-worker": "^27.4.5",
- "schema-utils": "^3.1.1",
- "serialize-javascript": "^6.0.0",
- "terser": "^5.14.1"
- },
- "engines": {
- "node": ">= 10.13.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/webpack"
- },
- "peerDependencies": {
- "webpack": "^5.1.0"
- },
- "peerDependenciesMeta": {
- "@swc/core": {
- "optional": true
- },
- "esbuild": {
- "optional": true
- },
- "uglify-js": {
- "optional": true
- }
- }
- },
- "node_modules/terser-webpack-plugin/node_modules/has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/terser-webpack-plugin/node_modules/jest-worker": {
- "version": "27.5.1",
- "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz",
- "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==",
- "dev": true,
- "dependencies": {
- "@types/node": "*",
- "merge-stream": "^2.0.0",
- "supports-color": "^8.0.0"
- },
- "engines": {
- "node": ">= 10.13.0"
- }
- },
- "node_modules/terser-webpack-plugin/node_modules/schema-utils": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz",
- "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==",
- "dev": true,
- "dependencies": {
- "@types/json-schema": "^7.0.8",
- "ajv": "^6.12.5",
- "ajv-keywords": "^3.5.2"
- },
- "engines": {
- "node": ">= 10.13.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/webpack"
- }
- },
- "node_modules/terser-webpack-plugin/node_modules/supports-color": {
- "version": "8.1.1",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
- "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
- "dev": true,
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/supports-color?sponsor=1"
- }
- },
- "node_modules/terser/node_modules/commander": {
- "version": "2.20.3",
- "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
- "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
- "dev": true
- },
- "node_modules/test-exclude": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz",
- "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==",
- "dev": true,
- "dependencies": {
- "@istanbuljs/schema": "^0.1.2",
- "glob": "^7.1.4",
- "minimatch": "^3.0.4"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/text-table": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
- "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
- "dev": true
- },
- "node_modules/tmpl": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz",
- "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==",
- "dev": true
- },
- "node_modules/to-fast-properties": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
- "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/to-regex-range": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
- "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
- "dev": true,
- "dependencies": {
- "is-number": "^7.0.0"
- },
- "engines": {
- "node": ">=8.0"
- }
- },
- "node_modules/totalist": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/totalist/-/totalist-1.1.0.tgz",
- "integrity": "sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/ts-jest": {
- "version": "29.0.5",
- "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.5.tgz",
- "integrity": "sha512-PL3UciSgIpQ7f6XjVOmbi96vmDHUqAyqDr8YxzopDqX3kfgYtX1cuNeBjP+L9sFXi6nzsGGA6R3fP3DDDJyrxA==",
- "dev": true,
- "dependencies": {
- "bs-logger": "0.x",
- "fast-json-stable-stringify": "2.x",
- "jest-util": "^29.0.0",
- "json5": "^2.2.3",
- "lodash.memoize": "4.x",
- "make-error": "1.x",
- "semver": "7.x",
- "yargs-parser": "^21.0.1"
- },
- "bin": {
- "ts-jest": "cli.js"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- },
- "peerDependencies": {
- "@babel/core": ">=7.0.0-beta.0 <8",
- "@jest/types": "^29.0.0",
- "babel-jest": "^29.0.0",
- "jest": "^29.0.0",
- "typescript": ">=4.3"
- },
- "peerDependenciesMeta": {
- "@babel/core": {
- "optional": true
- },
- "@jest/types": {
- "optional": true
- },
- "babel-jest": {
- "optional": true
- },
- "esbuild": {
- "optional": true
- }
- }
- },
- "node_modules/ts-jest/node_modules/lru-cache": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
- "dev": true,
- "dependencies": {
- "yallist": "^4.0.0"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/ts-jest/node_modules/semver": {
- "version": "7.3.8",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
- "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
- "dev": true,
- "dependencies": {
- "lru-cache": "^6.0.0"
- },
- "bin": {
- "semver": "bin/semver.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/ts-jest/node_modules/yallist": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
- "dev": true
- },
- "node_modules/ts-loader": {
- "version": "9.4.2",
- "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.4.2.tgz",
- "integrity": "sha512-OmlC4WVmFv5I0PpaxYb+qGeGOdm5giHU7HwDDUjw59emP2UYMHy9fFSDcYgSNoH8sXcj4hGCSEhlDZ9ULeDraA==",
- "dev": true,
- "dependencies": {
- "chalk": "^4.1.0",
- "enhanced-resolve": "^5.0.0",
- "micromatch": "^4.0.0",
- "semver": "^7.3.4"
- },
- "engines": {
- "node": ">=12.0.0"
- },
- "peerDependencies": {
- "typescript": "*",
- "webpack": "^5.0.0"
- }
- },
- "node_modules/ts-loader/node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/ts-loader/node_modules/chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/ts-loader/node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/ts-loader/node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "node_modules/ts-loader/node_modules/has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/ts-loader/node_modules/lru-cache": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
- "dev": true,
- "dependencies": {
- "yallist": "^4.0.0"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/ts-loader/node_modules/semver": {
- "version": "7.3.8",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
- "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
- "dev": true,
- "dependencies": {
- "lru-cache": "^6.0.0"
- },
- "bin": {
- "semver": "bin/semver.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/ts-loader/node_modules/supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/ts-loader/node_modules/yallist": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
- "dev": true
- },
- "node_modules/tslib": {
- "version": "1.14.1",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
- "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
- "dev": true
- },
- "node_modules/tsutils": {
- "version": "3.21.0",
- "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
- "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
- "dev": true,
- "dependencies": {
- "tslib": "^1.8.1"
- },
- "engines": {
- "node": ">= 6"
- },
- "peerDependencies": {
- "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta"
- }
- },
- "node_modules/type-check": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
- "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
- "dev": true,
- "dependencies": {
- "prelude-ls": "^1.2.1"
- },
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/type-detect": {
- "version": "4.0.8",
- "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
- "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/type-fest": {
- "version": "0.21.3",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz",
- "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==",
- "dev": true,
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/typescript": {
- "version": "4.9.4",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz",
- "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==",
- "dev": true,
- "bin": {
- "tsc": "bin/tsc",
- "tsserver": "bin/tsserver"
- },
- "engines": {
- "node": ">=4.2.0"
- }
- },
- "node_modules/unicode-canonical-property-names-ecmascript": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz",
- "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/unicode-match-property-ecmascript": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz",
- "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==",
- "dev": true,
- "dependencies": {
- "unicode-canonical-property-names-ecmascript": "^2.0.0",
- "unicode-property-aliases-ecmascript": "^2.0.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/unicode-match-property-value-ecmascript": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz",
- "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/unicode-property-aliases-ecmascript": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz",
- "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/update-browserslist-db": {
- "version": "1.0.10",
- "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz",
- "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==",
- "dev": true,
- "funding": [
- {
- "type": "opencollective",
- "url": "https://opencollective.com/browserslist"
- },
- {
- "type": "tidelift",
- "url": "https://tidelift.com/funding/github/npm/browserslist"
- }
- ],
- "dependencies": {
- "escalade": "^3.1.1",
- "picocolors": "^1.0.0"
- },
- "bin": {
- "browserslist-lint": "cli.js"
- },
- "peerDependencies": {
- "browserslist": ">= 4.21.0"
- }
- },
- "node_modules/uri-js": {
- "version": "4.4.1",
- "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
- "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
- "dev": true,
- "dependencies": {
- "punycode": "^2.1.0"
- }
- },
- "node_modules/v8-compile-cache": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz",
- "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==",
- "dev": true
- },
- "node_modules/v8-to-istanbul": {
- "version": "9.0.1",
- "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz",
- "integrity": "sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==",
- "dev": true,
- "dependencies": {
- "@jridgewell/trace-mapping": "^0.3.12",
- "@types/istanbul-lib-coverage": "^2.0.1",
- "convert-source-map": "^1.6.0"
- },
- "engines": {
- "node": ">=10.12.0"
- }
- },
- "node_modules/walker": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz",
- "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==",
- "dev": true,
- "dependencies": {
- "makeerror": "1.0.12"
- }
- },
- "node_modules/watchpack": {
- "version": "2.4.0",
- "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz",
- "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==",
- "dev": true,
- "dependencies": {
- "glob-to-regexp": "^0.4.1",
- "graceful-fs": "^4.1.2"
- },
- "engines": {
- "node": ">=10.13.0"
- }
- },
- "node_modules/webpack": {
- "version": "5.76.0",
- "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.0.tgz",
- "integrity": "sha512-l5sOdYBDunyf72HW8dF23rFtWq/7Zgvt/9ftMof71E/yUb1YLOBmTgA2K4vQthB3kotMrSj609txVE0dnr2fjA==",
- "dev": true,
- "dependencies": {
- "@types/eslint-scope": "^3.7.3",
- "@types/estree": "^0.0.51",
- "@webassemblyjs/ast": "1.11.1",
- "@webassemblyjs/wasm-edit": "1.11.1",
- "@webassemblyjs/wasm-parser": "1.11.1",
- "acorn": "^8.7.1",
- "acorn-import-assertions": "^1.7.6",
- "browserslist": "^4.14.5",
- "chrome-trace-event": "^1.0.2",
- "enhanced-resolve": "^5.10.0",
- "es-module-lexer": "^0.9.0",
- "eslint-scope": "5.1.1",
- "events": "^3.2.0",
- "glob-to-regexp": "^0.4.1",
- "graceful-fs": "^4.2.9",
- "json-parse-even-better-errors": "^2.3.1",
- "loader-runner": "^4.2.0",
- "mime-types": "^2.1.27",
- "neo-async": "^2.6.2",
- "schema-utils": "^3.1.0",
- "tapable": "^2.1.1",
- "terser-webpack-plugin": "^5.1.3",
- "watchpack": "^2.4.0",
- "webpack-sources": "^3.2.3"
- },
- "bin": {
- "webpack": "bin/webpack.js"
- },
- "engines": {
- "node": ">=10.13.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/webpack"
- },
- "peerDependenciesMeta": {
- "webpack-cli": {
- "optional": true
- }
- }
- },
- "node_modules/webpack-bundle-analyzer": {
- "version": "4.7.0",
- "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.7.0.tgz",
- "integrity": "sha512-j9b8ynpJS4K+zfO5GGwsAcQX4ZHpWV+yRiHDiL+bE0XHJ8NiPYLTNVQdlFYWxtpg9lfAQNlwJg16J9AJtFSXRg==",
- "dev": true,
- "dependencies": {
- "acorn": "^8.0.4",
- "acorn-walk": "^8.0.0",
- "chalk": "^4.1.0",
- "commander": "^7.2.0",
- "gzip-size": "^6.0.0",
- "lodash": "^4.17.20",
- "opener": "^1.5.2",
- "sirv": "^1.0.7",
- "ws": "^7.3.1"
- },
- "bin": {
- "webpack-bundle-analyzer": "lib/bin/analyzer.js"
- },
- "engines": {
- "node": ">= 10.13.0"
- }
- },
- "node_modules/webpack-bundle-analyzer/node_modules/acorn-walk": {
- "version": "8.2.0",
- "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
- "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
- "dev": true,
- "engines": {
- "node": ">=0.4.0"
- }
- },
- "node_modules/webpack-bundle-analyzer/node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/webpack-bundle-analyzer/node_modules/chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/webpack-bundle-analyzer/node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/webpack-bundle-analyzer/node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "node_modules/webpack-bundle-analyzer/node_modules/commander": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
- "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
- "dev": true,
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/webpack-bundle-analyzer/node_modules/has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/webpack-bundle-analyzer/node_modules/supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/webpack-cli": {
- "version": "4.10.0",
- "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.10.0.tgz",
- "integrity": "sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w==",
- "dev": true,
- "dependencies": {
- "@discoveryjs/json-ext": "^0.5.0",
- "@webpack-cli/configtest": "^1.2.0",
- "@webpack-cli/info": "^1.5.0",
- "@webpack-cli/serve": "^1.7.0",
- "colorette": "^2.0.14",
- "commander": "^7.0.0",
- "cross-spawn": "^7.0.3",
- "fastest-levenshtein": "^1.0.12",
- "import-local": "^3.0.2",
- "interpret": "^2.2.0",
- "rechoir": "^0.7.0",
- "webpack-merge": "^5.7.3"
- },
- "bin": {
- "webpack-cli": "bin/cli.js"
- },
- "engines": {
- "node": ">=10.13.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/webpack"
- },
- "peerDependencies": {
- "webpack": "4.x.x || 5.x.x"
- },
- "peerDependenciesMeta": {
- "@webpack-cli/generators": {
- "optional": true
- },
- "@webpack-cli/migrate": {
- "optional": true
- },
- "webpack-bundle-analyzer": {
- "optional": true
- },
- "webpack-dev-server": {
- "optional": true
- }
- }
- },
- "node_modules/webpack-cli/node_modules/commander": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
- "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
- "dev": true,
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/webpack-merge": {
- "version": "5.8.0",
- "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz",
- "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==",
- "dev": true,
- "dependencies": {
- "clone-deep": "^4.0.1",
- "wildcard": "^2.0.0"
- },
- "engines": {
- "node": ">=10.0.0"
- }
- },
- "node_modules/webpack-sources": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz",
- "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==",
- "dev": true,
- "engines": {
- "node": ">=10.13.0"
- }
- },
- "node_modules/webpack/node_modules/acorn-import-assertions": {
- "version": "1.8.0",
- "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz",
- "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==",
- "dev": true,
- "peerDependencies": {
- "acorn": "^8"
- }
- },
- "node_modules/webpack/node_modules/schema-utils": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz",
- "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==",
- "dev": true,
- "dependencies": {
- "@types/json-schema": "^7.0.8",
- "ajv": "^6.12.5",
- "ajv-keywords": "^3.5.2"
- },
- "engines": {
- "node": ">= 10.13.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/webpack"
- }
- },
- "node_modules/which": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
- "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
- "dev": true,
- "dependencies": {
- "isexe": "^2.0.0"
- },
- "bin": {
- "node-which": "bin/node-which"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/wildcard": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz",
- "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==",
- "dev": true
- },
- "node_modules/word-wrap": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
- "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/wrap-ansi": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
- "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^4.0.0",
- "string-width": "^4.1.0",
- "strip-ansi": "^6.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
- }
- },
- "node_modules/wrap-ansi/node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/wrap-ansi/node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/wrap-ansi/node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "node_modules/wrappy": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
- "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
- "dev": true
- },
- "node_modules/write-file-atomic": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz",
- "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==",
- "dev": true,
- "dependencies": {
- "imurmurhash": "^0.1.4",
- "signal-exit": "^3.0.7"
- },
- "engines": {
- "node": "^12.13.0 || ^14.15.0 || >=16.0.0"
- }
- },
- "node_modules/ws": {
- "version": "7.5.9",
- "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz",
- "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
- "dev": true,
- "engines": {
- "node": ">=8.3.0"
- },
- "peerDependencies": {
- "bufferutil": "^4.0.1",
- "utf-8-validate": "^5.0.2"
- },
- "peerDependenciesMeta": {
- "bufferutil": {
- "optional": true
- },
- "utf-8-validate": {
- "optional": true
- }
- }
- },
- "node_modules/y18n": {
- "version": "5.0.8",
- "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
- "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
- "dev": true,
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/yallist": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
- "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
- "dev": true
- },
- "node_modules/yargs": {
- "version": "17.6.2",
- "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz",
- "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==",
- "dev": true,
- "dependencies": {
- "cliui": "^8.0.1",
- "escalade": "^3.1.1",
- "get-caller-file": "^2.0.5",
- "require-directory": "^2.1.1",
- "string-width": "^4.2.3",
- "y18n": "^5.0.5",
- "yargs-parser": "^21.1.1"
- },
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/yargs-parser": {
- "version": "21.1.1",
- "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
- "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
- "dev": true,
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/yocto-queue": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
- "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
- "dev": true,
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- }
- },
- "dependencies": {
- "@ampproject/remapping": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz",
- "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==",
- "dev": true,
- "requires": {
- "@jridgewell/gen-mapping": "^0.1.0",
- "@jridgewell/trace-mapping": "^0.3.9"
- }
- },
- "@babel/cli": {
- "version": "7.20.7",
- "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.20.7.tgz",
- "integrity": "sha512-WylgcELHB66WwQqItxNILsMlaTd8/SO6SgTTjMp4uCI7P4QyH1r3nqgFmO3BfM4AtfniHgFMH3EpYFj/zynBkQ==",
- "dev": true,
- "requires": {
- "@jridgewell/trace-mapping": "^0.3.8",
- "@nicolo-ribaudo/chokidar-2": "2.1.8-no-fsevents.3",
- "chokidar": "^3.4.0",
- "commander": "^4.0.1",
- "convert-source-map": "^1.1.0",
- "fs-readdir-recursive": "^1.1.0",
- "glob": "^7.2.0",
- "make-dir": "^2.1.0",
- "slash": "^2.0.0"
- }
- },
- "@babel/code-frame": {
- "version": "7.23.4",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.4.tgz",
- "integrity": "sha512-r1IONyb6Ia+jYR2vvIDhdWdlTGhqbBoFqLTQidzZ4kepUFH15ejXvFHxCVbtl7BOXIudsIubf4E81xeA3h3IXA==",
- "dev": true,
- "requires": {
- "@babel/highlight": "^7.23.4",
- "chalk": "^2.4.2"
- }
- },
- "@babel/compat-data": {
- "version": "7.20.10",
- "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.10.tgz",
- "integrity": "sha512-sEnuDPpOJR/fcafHMjpcpGN5M2jbUGUHwmuWKM/YdPzeEDJg8bgmbcWQFUfE32MQjti1koACvoPVsDe8Uq+idg==",
- "dev": true
- },
- "@babel/core": {
- "version": "7.20.7",
- "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.7.tgz",
- "integrity": "sha512-t1ZjCluspe5DW24bn2Rr1CDb2v9rn/hROtg9a2tmd0+QYf4bsloYfLQzjG4qHPNMhWtKdGC33R5AxGR2Af2cBw==",
- "dev": true,
- "requires": {
- "@ampproject/remapping": "^2.1.0",
- "@babel/code-frame": "^7.18.6",
- "@babel/generator": "^7.20.7",
- "@babel/helper-compilation-targets": "^7.20.7",
- "@babel/helper-module-transforms": "^7.20.7",
- "@babel/helpers": "^7.20.7",
- "@babel/parser": "^7.20.7",
- "@babel/template": "^7.20.7",
- "@babel/traverse": "^7.20.7",
- "@babel/types": "^7.20.7",
- "convert-source-map": "^1.7.0",
- "debug": "^4.1.0",
- "gensync": "^1.0.0-beta.2",
- "json5": "^2.2.1",
- "semver": "^6.3.0"
- }
- },
- "@babel/eslint-parser": {
- "version": "7.19.1",
- "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.19.1.tgz",
- "integrity": "sha512-AqNf2QWt1rtu2/1rLswy6CDP7H9Oh3mMhk177Y67Rg8d7RD9WfOLLv8CGn6tisFvS2htm86yIe1yLF6I1UDaGQ==",
- "dev": true,
- "requires": {
- "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1",
- "eslint-visitor-keys": "^2.1.0",
- "semver": "^6.3.0"
- }
- },
- "@babel/generator": {
- "version": "7.23.4",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.4.tgz",
- "integrity": "sha512-esuS49Cga3HcThFNebGhlgsrVLkvhqvYDTzgjfFFlHJcIfLe5jFmRRfCQ1KuBfc4Jrtn3ndLgKWAKjBE+IraYQ==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.23.4",
- "@jridgewell/gen-mapping": "^0.3.2",
- "@jridgewell/trace-mapping": "^0.3.17",
- "jsesc": "^2.5.1"
- },
- "dependencies": {
- "@jridgewell/gen-mapping": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz",
- "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==",
- "dev": true,
- "requires": {
- "@jridgewell/set-array": "^1.0.1",
- "@jridgewell/sourcemap-codec": "^1.4.10",
- "@jridgewell/trace-mapping": "^0.3.9"
- }
- }
- }
- },
- "@babel/helper-annotate-as-pure": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz",
- "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.18.6"
- }
- },
- "@babel/helper-builder-binary-assignment-operator-visitor": {
- "version": "7.18.9",
- "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz",
- "integrity": "sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==",
- "dev": true,
- "requires": {
- "@babel/helper-explode-assignable-expression": "^7.18.6",
- "@babel/types": "^7.18.9"
- }
- },
- "@babel/helper-compilation-targets": {
- "version": "7.20.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz",
- "integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==",
- "dev": true,
- "requires": {
- "@babel/compat-data": "^7.20.5",
- "@babel/helper-validator-option": "^7.18.6",
- "browserslist": "^4.21.3",
- "lru-cache": "^5.1.1",
- "semver": "^6.3.0"
- }
- },
- "@babel/helper-create-class-features-plugin": {
- "version": "7.20.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.20.7.tgz",
- "integrity": "sha512-LtoWbDXOaidEf50hmdDqn9g8VEzsorMexoWMQdQODbvmqYmaF23pBP5VNPAGIFHsFQCIeKokDiz3CH5Y2jlY6w==",
- "dev": true,
- "requires": {
- "@babel/helper-annotate-as-pure": "^7.18.6",
- "@babel/helper-environment-visitor": "^7.18.9",
- "@babel/helper-function-name": "^7.19.0",
- "@babel/helper-member-expression-to-functions": "^7.20.7",
- "@babel/helper-optimise-call-expression": "^7.18.6",
- "@babel/helper-replace-supers": "^7.20.7",
- "@babel/helper-split-export-declaration": "^7.18.6"
- }
- },
- "@babel/helper-create-regexp-features-plugin": {
- "version": "7.20.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.20.5.tgz",
- "integrity": "sha512-m68B1lkg3XDGX5yCvGO0kPx3v9WIYLnzjKfPcQiwntEQa5ZeRkPmo2X/ISJc8qxWGfwUr+kvZAeEzAwLec2r2w==",
- "dev": true,
- "requires": {
- "@babel/helper-annotate-as-pure": "^7.18.6",
- "regexpu-core": "^5.2.1"
- }
- },
- "@babel/helper-define-polyfill-provider": {
- "version": "0.3.3",
- "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz",
- "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==",
- "dev": true,
- "requires": {
- "@babel/helper-compilation-targets": "^7.17.7",
- "@babel/helper-plugin-utils": "^7.16.7",
- "debug": "^4.1.1",
- "lodash.debounce": "^4.0.8",
- "resolve": "^1.14.2",
- "semver": "^6.1.2"
- }
- },
- "@babel/helper-environment-visitor": {
- "version": "7.22.20",
- "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz",
- "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==",
- "dev": true
- },
- "@babel/helper-explode-assignable-expression": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz",
- "integrity": "sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.18.6"
- }
- },
- "@babel/helper-function-name": {
- "version": "7.23.0",
- "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz",
- "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==",
- "dev": true,
- "requires": {
- "@babel/template": "^7.22.15",
- "@babel/types": "^7.23.0"
- }
- },
- "@babel/helper-hoist-variables": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz",
- "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.22.5"
- }
- },
- "@babel/helper-member-expression-to-functions": {
- "version": "7.20.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.20.7.tgz",
- "integrity": "sha512-9J0CxJLq315fEdi4s7xK5TQaNYjZw+nDVpVqr1axNGKzdrdwYBD5b4uKv3n75aABG0rCCTK8Im8Ww7eYfMrZgw==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.20.7"
- }
- },
- "@babel/helper-module-imports": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz",
- "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.18.6"
- }
- },
- "@babel/helper-module-transforms": {
- "version": "7.20.11",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.11.tgz",
- "integrity": "sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==",
- "dev": true,
- "requires": {
- "@babel/helper-environment-visitor": "^7.18.9",
- "@babel/helper-module-imports": "^7.18.6",
- "@babel/helper-simple-access": "^7.20.2",
- "@babel/helper-split-export-declaration": "^7.18.6",
- "@babel/helper-validator-identifier": "^7.19.1",
- "@babel/template": "^7.20.7",
- "@babel/traverse": "^7.20.10",
- "@babel/types": "^7.20.7"
- }
- },
- "@babel/helper-optimise-call-expression": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz",
- "integrity": "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.18.6"
- }
- },
- "@babel/helper-plugin-utils": {
- "version": "7.20.2",
- "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz",
- "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==",
- "dev": true
- },
- "@babel/helper-remap-async-to-generator": {
- "version": "7.18.9",
- "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz",
- "integrity": "sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==",
- "dev": true,
- "requires": {
- "@babel/helper-annotate-as-pure": "^7.18.6",
- "@babel/helper-environment-visitor": "^7.18.9",
- "@babel/helper-wrap-function": "^7.18.9",
- "@babel/types": "^7.18.9"
- }
- },
- "@babel/helper-replace-supers": {
- "version": "7.20.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.20.7.tgz",
- "integrity": "sha512-vujDMtB6LVfNW13jhlCrp48QNslK6JXi7lQG736HVbHz/mbf4Dc7tIRh1Xf5C0rF7BP8iiSxGMCmY6Ci1ven3A==",
- "dev": true,
- "requires": {
- "@babel/helper-environment-visitor": "^7.18.9",
- "@babel/helper-member-expression-to-functions": "^7.20.7",
- "@babel/helper-optimise-call-expression": "^7.18.6",
- "@babel/template": "^7.20.7",
- "@babel/traverse": "^7.20.7",
- "@babel/types": "^7.20.7"
- }
- },
- "@babel/helper-simple-access": {
- "version": "7.20.2",
- "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz",
- "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.20.2"
- }
- },
- "@babel/helper-skip-transparent-expression-wrappers": {
- "version": "7.20.0",
- "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.20.0.tgz",
- "integrity": "sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.20.0"
- }
- },
- "@babel/helper-split-export-declaration": {
- "version": "7.22.6",
- "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz",
- "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.22.5"
- }
- },
- "@babel/helper-string-parser": {
- "version": "7.23.4",
- "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz",
- "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==",
- "dev": true
- },
- "@babel/helper-validator-identifier": {
- "version": "7.22.20",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
- "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
- "dev": true
- },
- "@babel/helper-validator-option": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz",
- "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==",
- "dev": true
- },
- "@babel/helper-wrap-function": {
- "version": "7.20.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.20.5.tgz",
- "integrity": "sha512-bYMxIWK5mh+TgXGVqAtnu5Yn1un+v8DDZtqyzKRLUzrh70Eal2O3aZ7aPYiMADO4uKlkzOiRiZ6GX5q3qxvW9Q==",
- "dev": true,
- "requires": {
- "@babel/helper-function-name": "^7.19.0",
- "@babel/template": "^7.18.10",
- "@babel/traverse": "^7.20.5",
- "@babel/types": "^7.20.5"
- }
- },
- "@babel/helpers": {
- "version": "7.20.7",
- "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.7.tgz",
- "integrity": "sha512-PBPjs5BppzsGaxHQCDKnZ6Gd9s6xl8bBCluz3vEInLGRJmnZan4F6BYCeqtyXqkk4W5IlPmjK4JlOuZkpJ3xZA==",
- "dev": true,
- "requires": {
- "@babel/template": "^7.20.7",
- "@babel/traverse": "^7.20.7",
- "@babel/types": "^7.20.7"
- }
- },
- "@babel/highlight": {
- "version": "7.23.4",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz",
- "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==",
- "dev": true,
- "requires": {
- "@babel/helper-validator-identifier": "^7.22.20",
- "chalk": "^2.4.2",
- "js-tokens": "^4.0.0"
- }
- },
- "@babel/parser": {
- "version": "7.23.4",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.4.tgz",
- "integrity": "sha512-vf3Xna6UEprW+7t6EtOmFpHNAuxw3xqPZghy+brsnusscJRW5BMUzzHZc5ICjULee81WeUV2jjakG09MDglJXQ==",
- "dev": true
- },
- "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz",
- "integrity": "sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.18.6"
- }
- },
- "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": {
- "version": "7.20.7",
- "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.20.7.tgz",
- "integrity": "sha512-sbr9+wNE5aXMBBFBICk01tt7sBf2Oc9ikRFEcem/ZORup9IMUdNhW7/wVLEbbtlWOsEubJet46mHAL2C8+2jKQ==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.20.2",
- "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0",
- "@babel/plugin-proposal-optional-chaining": "^7.20.7"
- }
- },
- "@babel/plugin-proposal-async-generator-functions": {
- "version": "7.20.7",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.7.tgz",
- "integrity": "sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA==",
- "dev": true,
- "requires": {
- "@babel/helper-environment-visitor": "^7.18.9",
- "@babel/helper-plugin-utils": "^7.20.2",
- "@babel/helper-remap-async-to-generator": "^7.18.9",
- "@babel/plugin-syntax-async-generators": "^7.8.4"
- }
- },
- "@babel/plugin-proposal-class-properties": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz",
- "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==",
- "dev": true,
- "requires": {
- "@babel/helper-create-class-features-plugin": "^7.18.6",
- "@babel/helper-plugin-utils": "^7.18.6"
- }
- },
- "@babel/plugin-proposal-class-static-block": {
- "version": "7.20.7",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.20.7.tgz",
- "integrity": "sha512-AveGOoi9DAjUYYuUAG//Ig69GlazLnoyzMw68VCDux+c1tsnnH/OkYcpz/5xzMkEFC6UxjR5Gw1c+iY2wOGVeQ==",
- "dev": true,
- "requires": {
- "@babel/helper-create-class-features-plugin": "^7.20.7",
- "@babel/helper-plugin-utils": "^7.20.2",
- "@babel/plugin-syntax-class-static-block": "^7.14.5"
- }
- },
- "@babel/plugin-proposal-dynamic-import": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz",
- "integrity": "sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.18.6",
- "@babel/plugin-syntax-dynamic-import": "^7.8.3"
- }
- },
- "@babel/plugin-proposal-export-default-from": {
- "version": "7.18.10",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.18.10.tgz",
- "integrity": "sha512-5H2N3R2aQFxkV4PIBUR/i7PUSwgTZjouJKzI8eKswfIjT0PhvzkPn0t0wIS5zn6maQuvtT0t1oHtMUz61LOuow==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.18.9",
- "@babel/plugin-syntax-export-default-from": "^7.18.6"
- }
- },
- "@babel/plugin-proposal-export-namespace-from": {
- "version": "7.18.9",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz",
- "integrity": "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.18.9",
- "@babel/plugin-syntax-export-namespace-from": "^7.8.3"
- }
- },
- "@babel/plugin-proposal-json-strings": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz",
- "integrity": "sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.18.6",
- "@babel/plugin-syntax-json-strings": "^7.8.3"
- }
- },
- "@babel/plugin-proposal-logical-assignment-operators": {
- "version": "7.20.7",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.20.7.tgz",
- "integrity": "sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.20.2",
- "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4"
- }
- },
- "@babel/plugin-proposal-nullish-coalescing-operator": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz",
- "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.18.6",
- "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3"
- }
- },
- "@babel/plugin-proposal-numeric-separator": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz",
- "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.18.6",
- "@babel/plugin-syntax-numeric-separator": "^7.10.4"
- }
- },
- "@babel/plugin-proposal-object-rest-spread": {
- "version": "7.20.7",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz",
- "integrity": "sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==",
- "dev": true,
- "requires": {
- "@babel/compat-data": "^7.20.5",
- "@babel/helper-compilation-targets": "^7.20.7",
- "@babel/helper-plugin-utils": "^7.20.2",
- "@babel/plugin-syntax-object-rest-spread": "^7.8.3",
- "@babel/plugin-transform-parameters": "^7.20.7"
- }
- },
- "@babel/plugin-proposal-optional-catch-binding": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz",
- "integrity": "sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.18.6",
- "@babel/plugin-syntax-optional-catch-binding": "^7.8.3"
- }
- },
- "@babel/plugin-proposal-optional-chaining": {
- "version": "7.20.7",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.20.7.tgz",
- "integrity": "sha512-T+A7b1kfjtRM51ssoOfS1+wbyCVqorfyZhT99TvxxLMirPShD8CzKMRepMlCBGM5RpHMbn8s+5MMHnPstJH6mQ==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.20.2",
- "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0",
- "@babel/plugin-syntax-optional-chaining": "^7.8.3"
- }
- },
- "@babel/plugin-proposal-private-methods": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz",
- "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==",
- "dev": true,
- "requires": {
- "@babel/helper-create-class-features-plugin": "^7.18.6",
- "@babel/helper-plugin-utils": "^7.18.6"
- }
- },
- "@babel/plugin-proposal-private-property-in-object": {
- "version": "7.20.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.20.5.tgz",
- "integrity": "sha512-Vq7b9dUA12ByzB4EjQTPo25sFhY+08pQDBSZRtUAkj7lb7jahaHR5igera16QZ+3my1nYR4dKsNdYj5IjPHilQ==",
- "dev": true,
- "requires": {
- "@babel/helper-annotate-as-pure": "^7.18.6",
- "@babel/helper-create-class-features-plugin": "^7.20.5",
- "@babel/helper-plugin-utils": "^7.20.2",
- "@babel/plugin-syntax-private-property-in-object": "^7.14.5"
- }
- },
- "@babel/plugin-proposal-throw-expressions": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-throw-expressions/-/plugin-proposal-throw-expressions-7.18.6.tgz",
- "integrity": "sha512-WHOrJyhGoGrdtW480L79cF7Iq/gZDZ/z6OqK7mVyFR5I37dTpog/wNgb6hmaM3HYZtULEJl++7VaMWkNZsOcHg==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.18.6",
- "@babel/plugin-syntax-throw-expressions": "^7.18.6"
- }
- },
- "@babel/plugin-proposal-unicode-property-regex": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz",
- "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==",
- "dev": true,
- "requires": {
- "@babel/helper-create-regexp-features-plugin": "^7.18.6",
- "@babel/helper-plugin-utils": "^7.18.6"
- }
- },
- "@babel/plugin-syntax-async-generators": {
- "version": "7.8.4",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz",
- "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.8.0"
- }
- },
- "@babel/plugin-syntax-bigint": {
- "version": "7.8.3",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz",
- "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.8.0"
- }
- },
- "@babel/plugin-syntax-class-properties": {
- "version": "7.12.13",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz",
- "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.12.13"
- }
- },
- "@babel/plugin-syntax-class-static-block": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz",
- "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.14.5"
- }
- },
- "@babel/plugin-syntax-dynamic-import": {
- "version": "7.8.3",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz",
- "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.8.0"
- }
- },
- "@babel/plugin-syntax-export-default-from": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-default-from/-/plugin-syntax-export-default-from-7.18.6.tgz",
- "integrity": "sha512-Kr//z3ujSVNx6E9z9ih5xXXMqK07VVTuqPmqGe6Mss/zW5XPeLZeSDZoP9ab/hT4wPKqAgjl2PnhPrcpk8Seew==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.18.6"
- }
- },
- "@babel/plugin-syntax-export-namespace-from": {
- "version": "7.8.3",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz",
- "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.8.3"
- }
- },
- "@babel/plugin-syntax-import-assertions": {
- "version": "7.20.0",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.20.0.tgz",
- "integrity": "sha512-IUh1vakzNoWalR8ch/areW7qFopR2AEw03JlG7BbrDqmQ4X3q9uuipQwSGrUn7oGiemKjtSLDhNtQHzMHr1JdQ==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.19.0"
- }
- },
- "@babel/plugin-syntax-import-meta": {
- "version": "7.10.4",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz",
- "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.10.4"
- }
- },
- "@babel/plugin-syntax-json-strings": {
- "version": "7.8.3",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz",
- "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.8.0"
- }
- },
- "@babel/plugin-syntax-jsx": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz",
- "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.18.6"
- }
- },
- "@babel/plugin-syntax-logical-assignment-operators": {
- "version": "7.10.4",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz",
- "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.10.4"
- }
- },
- "@babel/plugin-syntax-nullish-coalescing-operator": {
- "version": "7.8.3",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz",
- "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.8.0"
- }
- },
- "@babel/plugin-syntax-numeric-separator": {
- "version": "7.10.4",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz",
- "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.10.4"
- }
- },
- "@babel/plugin-syntax-object-rest-spread": {
- "version": "7.8.3",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz",
- "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.8.0"
- }
- },
- "@babel/plugin-syntax-optional-catch-binding": {
- "version": "7.8.3",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz",
- "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.8.0"
- }
- },
- "@babel/plugin-syntax-optional-chaining": {
- "version": "7.8.3",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz",
- "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.8.0"
- }
- },
- "@babel/plugin-syntax-private-property-in-object": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz",
- "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.14.5"
- }
- },
- "@babel/plugin-syntax-throw-expressions": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-throw-expressions/-/plugin-syntax-throw-expressions-7.18.6.tgz",
- "integrity": "sha512-rp1CqEZXGv1z1YZ3qYffBH3rhnOxrTwQG8fh2yqulTurwv9zu3Gthfd+niZBLSOi1rY6146TgF+JmVeDXaX4TQ==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.18.6"
- }
- },
- "@babel/plugin-syntax-top-level-await": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz",
- "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.14.5"
- }
- },
- "@babel/plugin-syntax-typescript": {
- "version": "7.20.0",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.20.0.tgz",
- "integrity": "sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.19.0"
- }
- },
- "@babel/plugin-transform-arrow-functions": {
- "version": "7.20.7",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.20.7.tgz",
- "integrity": "sha512-3poA5E7dzDomxj9WXWwuD6A5F3kc7VXwIJO+E+J8qtDtS+pXPAhrgEyh+9GBwBgPq1Z+bB+/JD60lp5jsN7JPQ==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.20.2"
- }
- },
- "@babel/plugin-transform-async-to-generator": {
- "version": "7.20.7",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.20.7.tgz",
- "integrity": "sha512-Uo5gwHPT9vgnSXQxqGtpdufUiWp96gk7yiP4Mp5bm1QMkEmLXBO7PAGYbKoJ6DhAwiNkcHFBol/x5zZZkL/t0Q==",
- "dev": true,
- "requires": {
- "@babel/helper-module-imports": "^7.18.6",
- "@babel/helper-plugin-utils": "^7.20.2",
- "@babel/helper-remap-async-to-generator": "^7.18.9"
- }
- },
- "@babel/plugin-transform-block-scoped-functions": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz",
- "integrity": "sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.18.6"
- }
- },
- "@babel/plugin-transform-block-scoping": {
- "version": "7.20.11",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.20.11.tgz",
- "integrity": "sha512-tA4N427a7fjf1P0/2I4ScsHGc5jcHPbb30xMbaTke2gxDuWpUfXDuX1FEymJwKk4tuGUvGcejAR6HdZVqmmPyw==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.20.2"
- }
- },
- "@babel/plugin-transform-classes": {
- "version": "7.20.7",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.20.7.tgz",
- "integrity": "sha512-LWYbsiXTPKl+oBlXUGlwNlJZetXD5Am+CyBdqhPsDVjM9Jc8jwBJFrKhHf900Kfk2eZG1y9MAG3UNajol7A4VQ==",
- "dev": true,
- "requires": {
- "@babel/helper-annotate-as-pure": "^7.18.6",
- "@babel/helper-compilation-targets": "^7.20.7",
- "@babel/helper-environment-visitor": "^7.18.9",
- "@babel/helper-function-name": "^7.19.0",
- "@babel/helper-optimise-call-expression": "^7.18.6",
- "@babel/helper-plugin-utils": "^7.20.2",
- "@babel/helper-replace-supers": "^7.20.7",
- "@babel/helper-split-export-declaration": "^7.18.6",
- "globals": "^11.1.0"
- }
- },
- "@babel/plugin-transform-computed-properties": {
- "version": "7.20.7",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.20.7.tgz",
- "integrity": "sha512-Lz7MvBK6DTjElHAmfu6bfANzKcxpyNPeYBGEafyA6E5HtRpjpZwU+u7Qrgz/2OR0z+5TvKYbPdphfSaAcZBrYQ==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.20.2",
- "@babel/template": "^7.20.7"
- }
- },
- "@babel/plugin-transform-destructuring": {
- "version": "7.20.7",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.20.7.tgz",
- "integrity": "sha512-Xwg403sRrZb81IVB79ZPqNQME23yhugYVqgTxAhT99h485F4f+GMELFhhOsscDUB7HCswepKeCKLn/GZvUKoBA==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.20.2"
- }
- },
- "@babel/plugin-transform-dotall-regex": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz",
- "integrity": "sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==",
- "dev": true,
- "requires": {
- "@babel/helper-create-regexp-features-plugin": "^7.18.6",
- "@babel/helper-plugin-utils": "^7.18.6"
- }
- },
- "@babel/plugin-transform-duplicate-keys": {
- "version": "7.18.9",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz",
- "integrity": "sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.18.9"
- }
- },
- "@babel/plugin-transform-exponentiation-operator": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz",
- "integrity": "sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==",
- "dev": true,
- "requires": {
- "@babel/helper-builder-binary-assignment-operator-visitor": "^7.18.6",
- "@babel/helper-plugin-utils": "^7.18.6"
- }
- },
- "@babel/plugin-transform-for-of": {
- "version": "7.18.8",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz",
- "integrity": "sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.18.6"
- }
- },
- "@babel/plugin-transform-function-name": {
- "version": "7.18.9",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz",
- "integrity": "sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==",
- "dev": true,
- "requires": {
- "@babel/helper-compilation-targets": "^7.18.9",
- "@babel/helper-function-name": "^7.18.9",
- "@babel/helper-plugin-utils": "^7.18.9"
- }
- },
- "@babel/plugin-transform-literals": {
- "version": "7.18.9",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz",
- "integrity": "sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.18.9"
- }
- },
- "@babel/plugin-transform-member-expression-literals": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz",
- "integrity": "sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.18.6"
- }
- },
- "@babel/plugin-transform-modules-amd": {
- "version": "7.20.11",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.20.11.tgz",
- "integrity": "sha512-NuzCt5IIYOW0O30UvqktzHYR2ud5bOWbY0yaxWZ6G+aFzOMJvrs5YHNikrbdaT15+KNO31nPOy5Fim3ku6Zb5g==",
- "dev": true,
- "requires": {
- "@babel/helper-module-transforms": "^7.20.11",
- "@babel/helper-plugin-utils": "^7.20.2"
- }
- },
- "@babel/plugin-transform-modules-commonjs": {
- "version": "7.20.11",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.20.11.tgz",
- "integrity": "sha512-S8e1f7WQ7cimJQ51JkAaDrEtohVEitXjgCGAS2N8S31Y42E+kWwfSz83LYz57QdBm7q9diARVqanIaH2oVgQnw==",
- "dev": true,
- "requires": {
- "@babel/helper-module-transforms": "^7.20.11",
- "@babel/helper-plugin-utils": "^7.20.2",
- "@babel/helper-simple-access": "^7.20.2"
- }
- },
- "@babel/plugin-transform-modules-systemjs": {
- "version": "7.20.11",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.20.11.tgz",
- "integrity": "sha512-vVu5g9BPQKSFEmvt2TA4Da5N+QVS66EX21d8uoOihC+OCpUoGvzVsXeqFdtAEfVa5BILAeFt+U7yVmLbQnAJmw==",
- "dev": true,
- "requires": {
- "@babel/helper-hoist-variables": "^7.18.6",
- "@babel/helper-module-transforms": "^7.20.11",
- "@babel/helper-plugin-utils": "^7.20.2",
- "@babel/helper-validator-identifier": "^7.19.1"
- }
- },
- "@babel/plugin-transform-modules-umd": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz",
- "integrity": "sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==",
- "dev": true,
- "requires": {
- "@babel/helper-module-transforms": "^7.18.6",
- "@babel/helper-plugin-utils": "^7.18.6"
- }
- },
- "@babel/plugin-transform-named-capturing-groups-regex": {
- "version": "7.20.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.20.5.tgz",
- "integrity": "sha512-mOW4tTzi5iTLnw+78iEq3gr8Aoq4WNRGpmSlrogqaiCBoR1HFhpU4JkpQFOHfeYx3ReVIFWOQJS4aZBRvuZ6mA==",
- "dev": true,
- "requires": {
- "@babel/helper-create-regexp-features-plugin": "^7.20.5",
- "@babel/helper-plugin-utils": "^7.20.2"
- }
- },
- "@babel/plugin-transform-new-target": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz",
- "integrity": "sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.18.6"
- }
- },
- "@babel/plugin-transform-object-super": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz",
- "integrity": "sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.18.6",
- "@babel/helper-replace-supers": "^7.18.6"
- }
- },
- "@babel/plugin-transform-parameters": {
- "version": "7.20.7",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.20.7.tgz",
- "integrity": "sha512-WiWBIkeHKVOSYPO0pWkxGPfKeWrCJyD3NJ53+Lrp/QMSZbsVPovrVl2aWZ19D/LTVnaDv5Ap7GJ/B2CTOZdrfA==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.20.2"
- }
- },
- "@babel/plugin-transform-property-literals": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz",
- "integrity": "sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.18.6"
- }
- },
- "@babel/plugin-transform-regenerator": {
- "version": "7.20.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.20.5.tgz",
- "integrity": "sha512-kW/oO7HPBtntbsahzQ0qSE3tFvkFwnbozz3NWFhLGqH75vLEg+sCGngLlhVkePlCs3Jv0dBBHDzCHxNiFAQKCQ==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.20.2",
- "regenerator-transform": "^0.15.1"
- }
- },
- "@babel/plugin-transform-reserved-words": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz",
- "integrity": "sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.18.6"
- }
- },
- "@babel/plugin-transform-runtime": {
- "version": "7.19.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.19.6.tgz",
- "integrity": "sha512-PRH37lz4JU156lYFW1p8OxE5i7d6Sl/zV58ooyr+q1J1lnQPyg5tIiXlIwNVhJaY4W3TmOtdc8jqdXQcB1v5Yw==",
- "dev": true,
- "requires": {
- "@babel/helper-module-imports": "^7.18.6",
- "@babel/helper-plugin-utils": "^7.19.0",
- "babel-plugin-polyfill-corejs2": "^0.3.3",
- "babel-plugin-polyfill-corejs3": "^0.6.0",
- "babel-plugin-polyfill-regenerator": "^0.4.1",
- "semver": "^6.3.0"
- }
- },
- "@babel/plugin-transform-shorthand-properties": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz",
- "integrity": "sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.18.6"
- }
- },
- "@babel/plugin-transform-spread": {
- "version": "7.20.7",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.20.7.tgz",
- "integrity": "sha512-ewBbHQ+1U/VnH1fxltbJqDeWBU1oNLG8Dj11uIv3xVf7nrQu0bPGe5Rf716r7K5Qz+SqtAOVswoVunoiBtGhxw==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.20.2",
- "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0"
- }
- },
- "@babel/plugin-transform-sticky-regex": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz",
- "integrity": "sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.18.6"
- }
- },
- "@babel/plugin-transform-template-literals": {
- "version": "7.18.9",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz",
- "integrity": "sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.18.9"
- }
- },
- "@babel/plugin-transform-typeof-symbol": {
- "version": "7.18.9",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz",
- "integrity": "sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.18.9"
- }
- },
- "@babel/plugin-transform-typescript": {
- "version": "7.20.7",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.20.7.tgz",
- "integrity": "sha512-m3wVKEvf6SoszD8pu4NZz3PvfKRCMgk6D6d0Qi9hNnlM5M6CFS92EgF4EiHVLKbU0r/r7ty1hg7NPZwE7WRbYw==",
- "dev": true,
- "requires": {
- "@babel/helper-create-class-features-plugin": "^7.20.7",
- "@babel/helper-plugin-utils": "^7.20.2",
- "@babel/plugin-syntax-typescript": "^7.20.0"
- }
- },
- "@babel/plugin-transform-unicode-escapes": {
- "version": "7.18.10",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz",
- "integrity": "sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.18.9"
- }
- },
- "@babel/plugin-transform-unicode-regex": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz",
- "integrity": "sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==",
- "dev": true,
- "requires": {
- "@babel/helper-create-regexp-features-plugin": "^7.18.6",
- "@babel/helper-plugin-utils": "^7.18.6"
- }
- },
- "@babel/preset-env": {
- "version": "7.20.2",
- "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.20.2.tgz",
- "integrity": "sha512-1G0efQEWR1EHkKvKHqbG+IN/QdgwfByUpM5V5QroDzGV2t3S/WXNQd693cHiHTlCFMpr9B6FkPFXDA2lQcKoDg==",
- "dev": true,
- "requires": {
- "@babel/compat-data": "^7.20.1",
- "@babel/helper-compilation-targets": "^7.20.0",
- "@babel/helper-plugin-utils": "^7.20.2",
- "@babel/helper-validator-option": "^7.18.6",
- "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6",
- "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.9",
- "@babel/plugin-proposal-async-generator-functions": "^7.20.1",
- "@babel/plugin-proposal-class-properties": "^7.18.6",
- "@babel/plugin-proposal-class-static-block": "^7.18.6",
- "@babel/plugin-proposal-dynamic-import": "^7.18.6",
- "@babel/plugin-proposal-export-namespace-from": "^7.18.9",
- "@babel/plugin-proposal-json-strings": "^7.18.6",
- "@babel/plugin-proposal-logical-assignment-operators": "^7.18.9",
- "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6",
- "@babel/plugin-proposal-numeric-separator": "^7.18.6",
- "@babel/plugin-proposal-object-rest-spread": "^7.20.2",
- "@babel/plugin-proposal-optional-catch-binding": "^7.18.6",
- "@babel/plugin-proposal-optional-chaining": "^7.18.9",
- "@babel/plugin-proposal-private-methods": "^7.18.6",
- "@babel/plugin-proposal-private-property-in-object": "^7.18.6",
- "@babel/plugin-proposal-unicode-property-regex": "^7.18.6",
- "@babel/plugin-syntax-async-generators": "^7.8.4",
- "@babel/plugin-syntax-class-properties": "^7.12.13",
- "@babel/plugin-syntax-class-static-block": "^7.14.5",
- "@babel/plugin-syntax-dynamic-import": "^7.8.3",
- "@babel/plugin-syntax-export-namespace-from": "^7.8.3",
- "@babel/plugin-syntax-import-assertions": "^7.20.0",
- "@babel/plugin-syntax-json-strings": "^7.8.3",
- "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4",
- "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3",
- "@babel/plugin-syntax-numeric-separator": "^7.10.4",
- "@babel/plugin-syntax-object-rest-spread": "^7.8.3",
- "@babel/plugin-syntax-optional-catch-binding": "^7.8.3",
- "@babel/plugin-syntax-optional-chaining": "^7.8.3",
- "@babel/plugin-syntax-private-property-in-object": "^7.14.5",
- "@babel/plugin-syntax-top-level-await": "^7.14.5",
- "@babel/plugin-transform-arrow-functions": "^7.18.6",
- "@babel/plugin-transform-async-to-generator": "^7.18.6",
- "@babel/plugin-transform-block-scoped-functions": "^7.18.6",
- "@babel/plugin-transform-block-scoping": "^7.20.2",
- "@babel/plugin-transform-classes": "^7.20.2",
- "@babel/plugin-transform-computed-properties": "^7.18.9",
- "@babel/plugin-transform-destructuring": "^7.20.2",
- "@babel/plugin-transform-dotall-regex": "^7.18.6",
- "@babel/plugin-transform-duplicate-keys": "^7.18.9",
- "@babel/plugin-transform-exponentiation-operator": "^7.18.6",
- "@babel/plugin-transform-for-of": "^7.18.8",
- "@babel/plugin-transform-function-name": "^7.18.9",
- "@babel/plugin-transform-literals": "^7.18.9",
- "@babel/plugin-transform-member-expression-literals": "^7.18.6",
- "@babel/plugin-transform-modules-amd": "^7.19.6",
- "@babel/plugin-transform-modules-commonjs": "^7.19.6",
- "@babel/plugin-transform-modules-systemjs": "^7.19.6",
- "@babel/plugin-transform-modules-umd": "^7.18.6",
- "@babel/plugin-transform-named-capturing-groups-regex": "^7.19.1",
- "@babel/plugin-transform-new-target": "^7.18.6",
- "@babel/plugin-transform-object-super": "^7.18.6",
- "@babel/plugin-transform-parameters": "^7.20.1",
- "@babel/plugin-transform-property-literals": "^7.18.6",
- "@babel/plugin-transform-regenerator": "^7.18.6",
- "@babel/plugin-transform-reserved-words": "^7.18.6",
- "@babel/plugin-transform-shorthand-properties": "^7.18.6",
- "@babel/plugin-transform-spread": "^7.19.0",
- "@babel/plugin-transform-sticky-regex": "^7.18.6",
- "@babel/plugin-transform-template-literals": "^7.18.9",
- "@babel/plugin-transform-typeof-symbol": "^7.18.9",
- "@babel/plugin-transform-unicode-escapes": "^7.18.10",
- "@babel/plugin-transform-unicode-regex": "^7.18.6",
- "@babel/preset-modules": "^0.1.5",
- "@babel/types": "^7.20.2",
- "babel-plugin-polyfill-corejs2": "^0.3.3",
- "babel-plugin-polyfill-corejs3": "^0.6.0",
- "babel-plugin-polyfill-regenerator": "^0.4.1",
- "core-js-compat": "^3.25.1",
- "semver": "^6.3.0"
- }
- },
- "@babel/preset-modules": {
- "version": "0.1.5",
- "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz",
- "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.0.0",
- "@babel/plugin-proposal-unicode-property-regex": "^7.4.4",
- "@babel/plugin-transform-dotall-regex": "^7.4.4",
- "@babel/types": "^7.4.4",
- "esutils": "^2.0.2"
- }
- },
- "@babel/preset-typescript": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.18.6.tgz",
- "integrity": "sha512-s9ik86kXBAnD760aybBucdpnLsAt0jK1xqJn2juOn9lkOvSHV60os5hxoVJsPzMQxvnUJFAlkont2DvvaYEBtQ==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.18.6",
- "@babel/helper-validator-option": "^7.18.6",
- "@babel/plugin-transform-typescript": "^7.18.6"
- }
- },
- "@babel/register": {
- "version": "7.18.9",
- "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.18.9.tgz",
- "integrity": "sha512-ZlbnXDcNYHMR25ITwwNKT88JiaukkdVj/nG7r3wnuXkOTHc60Uy05PwMCPre0hSkY68E6zK3xz+vUJSP2jWmcw==",
- "dev": true,
- "requires": {
- "clone-deep": "^4.0.1",
- "find-cache-dir": "^2.0.0",
- "make-dir": "^2.1.0",
- "pirates": "^4.0.5",
- "source-map-support": "^0.5.16"
- }
- },
- "@babel/runtime": {
- "version": "7.20.7",
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.7.tgz",
- "integrity": "sha512-UF0tvkUtxwAgZ5W/KrkHf0Rn0fdnLDU9ScxBrEVNUprE/MzirjK4MJUX1/BVDv00Sv8cljtukVK1aky++X1SjQ==",
- "dev": true,
- "requires": {
- "regenerator-runtime": "^0.13.11"
- }
- },
- "@babel/template": {
- "version": "7.22.15",
- "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz",
- "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==",
- "dev": true,
- "requires": {
- "@babel/code-frame": "^7.22.13",
- "@babel/parser": "^7.22.15",
- "@babel/types": "^7.22.15"
- }
- },
- "@babel/traverse": {
- "version": "7.23.4",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.4.tgz",
- "integrity": "sha512-IYM8wSUwunWTB6tFC2dkKZhxbIjHoWemdK+3f8/wq8aKhbUscxD5MX72ubd90fxvFknaLPeGw5ycU84V1obHJg==",
- "dev": true,
- "requires": {
- "@babel/code-frame": "^7.23.4",
- "@babel/generator": "^7.23.4",
- "@babel/helper-environment-visitor": "^7.22.20",
- "@babel/helper-function-name": "^7.23.0",
- "@babel/helper-hoist-variables": "^7.22.5",
- "@babel/helper-split-export-declaration": "^7.22.6",
- "@babel/parser": "^7.23.4",
- "@babel/types": "^7.23.4",
- "debug": "^4.1.0",
- "globals": "^11.1.0"
- }
- },
- "@babel/types": {
- "version": "7.23.4",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.4.tgz",
- "integrity": "sha512-7uIFwVYpoplT5jp/kVv6EF93VaJ8H+Yn5IczYiaAi98ajzjfoZfslet/e0sLh+wVBjb2qqIut1b0S26VSafsSQ==",
- "dev": true,
- "requires": {
- "@babel/helper-string-parser": "^7.23.4",
- "@babel/helper-validator-identifier": "^7.22.20",
- "to-fast-properties": "^2.0.0"
- }
- },
- "@bcoe/v8-coverage": {
- "version": "0.2.3",
- "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz",
- "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
- "dev": true
- },
- "@discoveryjs/json-ext": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz",
- "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==",
- "dev": true
- },
- "@eslint/eslintrc": {
- "version": "0.4.3",
- "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz",
- "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==",
- "dev": true,
- "requires": {
- "ajv": "^6.12.4",
- "debug": "^4.1.1",
- "espree": "^7.3.0",
- "globals": "^13.9.0",
- "ignore": "^4.0.6",
- "import-fresh": "^3.2.1",
- "js-yaml": "^3.13.1",
- "minimatch": "^3.0.4",
- "strip-json-comments": "^3.1.1"
- },
- "dependencies": {
- "globals": {
- "version": "13.19.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz",
- "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==",
- "dev": true,
- "requires": {
- "type-fest": "^0.20.2"
- }
- },
- "ignore": {
- "version": "4.0.6",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
- "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
- "dev": true
- },
- "type-fest": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
- "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
- "dev": true
- }
- }
- },
- "@humanwhocodes/config-array": {
- "version": "0.5.0",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz",
- "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==",
- "dev": true,
- "requires": {
- "@humanwhocodes/object-schema": "^1.2.0",
- "debug": "^4.1.1",
- "minimatch": "^3.0.4"
- }
- },
- "@humanwhocodes/object-schema": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
- "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
- "dev": true
- },
- "@istanbuljs/load-nyc-config": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
- "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==",
- "dev": true,
- "requires": {
- "camelcase": "^5.3.1",
- "find-up": "^4.1.0",
- "get-package-type": "^0.1.0",
- "js-yaml": "^3.13.1",
- "resolve-from": "^5.0.0"
- }
- },
- "@istanbuljs/schema": {
- "version": "0.1.3",
- "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz",
- "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==",
- "dev": true
- },
- "@jest/console": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.3.1.tgz",
- "integrity": "sha512-IRE6GD47KwcqA09RIWrabKdHPiKDGgtAL31xDxbi/RjQMsr+lY+ppxmHwY0dUEV3qvvxZzoe5Hl0RXZJOjQNUg==",
- "dev": true,
- "requires": {
- "@jest/types": "^29.3.1",
- "@types/node": "*",
- "chalk": "^4.0.0",
- "jest-message-util": "^29.3.1",
- "jest-util": "^29.3.1",
- "slash": "^3.0.0"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true
- },
- "slash": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
- "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
- "dev": true
- },
- "supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "requires": {
- "has-flag": "^4.0.0"
- }
- }
- }
- },
- "@jest/core": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.3.1.tgz",
- "integrity": "sha512-0ohVjjRex985w5MmO5L3u5GR1O30DexhBSpuwx2P+9ftyqHdJXnk7IUWiP80oHMvt7ubHCJHxV0a0vlKVuZirw==",
- "dev": true,
- "requires": {
- "@jest/console": "^29.3.1",
- "@jest/reporters": "^29.3.1",
- "@jest/test-result": "^29.3.1",
- "@jest/transform": "^29.3.1",
- "@jest/types": "^29.3.1",
- "@types/node": "*",
- "ansi-escapes": "^4.2.1",
- "chalk": "^4.0.0",
- "ci-info": "^3.2.0",
- "exit": "^0.1.2",
- "graceful-fs": "^4.2.9",
- "jest-changed-files": "^29.2.0",
- "jest-config": "^29.3.1",
- "jest-haste-map": "^29.3.1",
- "jest-message-util": "^29.3.1",
- "jest-regex-util": "^29.2.0",
- "jest-resolve": "^29.3.1",
- "jest-resolve-dependencies": "^29.3.1",
- "jest-runner": "^29.3.1",
- "jest-runtime": "^29.3.1",
- "jest-snapshot": "^29.3.1",
- "jest-util": "^29.3.1",
- "jest-validate": "^29.3.1",
- "jest-watcher": "^29.3.1",
- "micromatch": "^4.0.4",
- "pretty-format": "^29.3.1",
- "slash": "^3.0.0",
- "strip-ansi": "^6.0.0"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true
- },
- "slash": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
- "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
- "dev": true
- },
- "supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "requires": {
- "has-flag": "^4.0.0"
- }
- }
- }
- },
- "@jest/environment": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.3.1.tgz",
- "integrity": "sha512-pMmvfOPmoa1c1QpfFW0nXYtNLpofqo4BrCIk6f2kW4JFeNlHV2t3vd+3iDLf31e2ot2Mec0uqZfmI+U0K2CFag==",
- "dev": true,
- "requires": {
- "@jest/fake-timers": "^29.3.1",
- "@jest/types": "^29.3.1",
- "@types/node": "*",
- "jest-mock": "^29.3.1"
- }
- },
- "@jest/expect": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.3.1.tgz",
- "integrity": "sha512-QivM7GlSHSsIAWzgfyP8dgeExPRZ9BIe2LsdPyEhCGkZkoyA+kGsoIzbKAfZCvvRzfZioKwPtCZIt5SaoxYCvg==",
- "dev": true,
- "requires": {
- "expect": "^29.3.1",
- "jest-snapshot": "^29.3.1"
- }
- },
- "@jest/expect-utils": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.3.1.tgz",
- "integrity": "sha512-wlrznINZI5sMjwvUoLVk617ll/UYfGIZNxmbU+Pa7wmkL4vYzhV9R2pwVqUh4NWWuLQWkI8+8mOkxs//prKQ3g==",
- "dev": true,
- "requires": {
- "jest-get-type": "^29.2.0"
- }
- },
- "@jest/fake-timers": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.3.1.tgz",
- "integrity": "sha512-iHTL/XpnDlFki9Tq0Q1GGuVeQ8BHZGIYsvCO5eN/O/oJaRzofG9Xndd9HuSDBI/0ZS79pg0iwn07OMTQ7ngF2A==",
- "dev": true,
- "requires": {
- "@jest/types": "^29.3.1",
- "@sinonjs/fake-timers": "^9.1.2",
- "@types/node": "*",
- "jest-message-util": "^29.3.1",
- "jest-mock": "^29.3.1",
- "jest-util": "^29.3.1"
- }
- },
- "@jest/globals": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.3.1.tgz",
- "integrity": "sha512-cTicd134vOcwO59OPaB6AmdHQMCtWOe+/DitpTZVxWgMJ+YvXL1HNAmPyiGbSHmF/mXVBkvlm8YYtQhyHPnV6Q==",
- "dev": true,
- "requires": {
- "@jest/environment": "^29.3.1",
- "@jest/expect": "^29.3.1",
- "@jest/types": "^29.3.1",
- "jest-mock": "^29.3.1"
- }
- },
- "@jest/reporters": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.3.1.tgz",
- "integrity": "sha512-GhBu3YFuDrcAYW/UESz1JphEAbvUjaY2vShRZRoRY1mxpCMB3yGSJ4j9n0GxVlEOdCf7qjvUfBCrTUUqhVfbRA==",
- "dev": true,
- "requires": {
- "@bcoe/v8-coverage": "^0.2.3",
- "@jest/console": "^29.3.1",
- "@jest/test-result": "^29.3.1",
- "@jest/transform": "^29.3.1",
- "@jest/types": "^29.3.1",
- "@jridgewell/trace-mapping": "^0.3.15",
- "@types/node": "*",
- "chalk": "^4.0.0",
- "collect-v8-coverage": "^1.0.0",
- "exit": "^0.1.2",
- "glob": "^7.1.3",
- "graceful-fs": "^4.2.9",
- "istanbul-lib-coverage": "^3.0.0",
- "istanbul-lib-instrument": "^5.1.0",
- "istanbul-lib-report": "^3.0.0",
- "istanbul-lib-source-maps": "^4.0.0",
- "istanbul-reports": "^3.1.3",
- "jest-message-util": "^29.3.1",
- "jest-util": "^29.3.1",
- "jest-worker": "^29.3.1",
- "slash": "^3.0.0",
- "string-length": "^4.0.1",
- "strip-ansi": "^6.0.0",
- "v8-to-istanbul": "^9.0.1"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true
- },
- "slash": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
- "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
- "dev": true
- },
- "supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "requires": {
- "has-flag": "^4.0.0"
- }
- }
- }
- },
- "@jest/schemas": {
- "version": "29.0.0",
- "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.0.0.tgz",
- "integrity": "sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA==",
- "dev": true,
- "requires": {
- "@sinclair/typebox": "^0.24.1"
- }
- },
- "@jest/source-map": {
- "version": "29.2.0",
- "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.2.0.tgz",
- "integrity": "sha512-1NX9/7zzI0nqa6+kgpSdKPK+WU1p+SJk3TloWZf5MzPbxri9UEeXX5bWZAPCzbQcyuAzubcdUHA7hcNznmRqWQ==",
- "dev": true,
- "requires": {
- "@jridgewell/trace-mapping": "^0.3.15",
- "callsites": "^3.0.0",
- "graceful-fs": "^4.2.9"
- }
- },
- "@jest/test-result": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.3.1.tgz",
- "integrity": "sha512-qeLa6qc0ddB0kuOZyZIhfN5q0e2htngokyTWsGriedsDhItisW7SDYZ7ceOe57Ii03sL988/03wAcBh3TChMGw==",
- "dev": true,
- "requires": {
- "@jest/console": "^29.3.1",
- "@jest/types": "^29.3.1",
- "@types/istanbul-lib-coverage": "^2.0.0",
- "collect-v8-coverage": "^1.0.0"
- }
- },
- "@jest/test-sequencer": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.3.1.tgz",
- "integrity": "sha512-IqYvLbieTv20ArgKoAMyhLHNrVHJfzO6ARZAbQRlY4UGWfdDnLlZEF0BvKOMd77uIiIjSZRwq3Jb3Fa3I8+2UA==",
- "dev": true,
- "requires": {
- "@jest/test-result": "^29.3.1",
- "graceful-fs": "^4.2.9",
- "jest-haste-map": "^29.3.1",
- "slash": "^3.0.0"
- },
- "dependencies": {
- "slash": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
- "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
- "dev": true
- }
- }
- },
- "@jest/transform": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.3.1.tgz",
- "integrity": "sha512-8wmCFBTVGYqFNLWfcOWoVuMuKYPUBTnTMDkdvFtAYELwDOl9RGwOsvQWGPFxDJ8AWY9xM/8xCXdqmPK3+Q5Lug==",
- "dev": true,
- "requires": {
- "@babel/core": "^7.11.6",
- "@jest/types": "^29.3.1",
- "@jridgewell/trace-mapping": "^0.3.15",
- "babel-plugin-istanbul": "^6.1.1",
- "chalk": "^4.0.0",
- "convert-source-map": "^2.0.0",
- "fast-json-stable-stringify": "^2.1.0",
- "graceful-fs": "^4.2.9",
- "jest-haste-map": "^29.3.1",
- "jest-regex-util": "^29.2.0",
- "jest-util": "^29.3.1",
- "micromatch": "^4.0.4",
- "pirates": "^4.0.4",
- "slash": "^3.0.0",
- "write-file-atomic": "^4.0.1"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "convert-source-map": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
- "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
- "dev": true
- },
- "has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true
- },
- "slash": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
- "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
- "dev": true
- },
- "supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "requires": {
- "has-flag": "^4.0.0"
- }
- }
- }
- },
- "@jest/types": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.3.1.tgz",
- "integrity": "sha512-d0S0jmmTpjnhCmNpApgX3jrUZgZ22ivKJRvL2lli5hpCRoNnp1f85r2/wpKfXuYu8E7Jjh1hGfhPyup1NM5AmA==",
- "dev": true,
- "requires": {
- "@jest/schemas": "^29.0.0",
- "@types/istanbul-lib-coverage": "^2.0.0",
- "@types/istanbul-reports": "^3.0.0",
- "@types/node": "*",
- "@types/yargs": "^17.0.8",
- "chalk": "^4.0.0"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true
- },
- "supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "requires": {
- "has-flag": "^4.0.0"
- }
- }
- }
- },
- "@jridgewell/gen-mapping": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz",
- "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==",
- "dev": true,
- "requires": {
- "@jridgewell/set-array": "^1.0.0",
- "@jridgewell/sourcemap-codec": "^1.4.10"
- }
- },
- "@jridgewell/resolve-uri": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
- "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
- "dev": true
- },
- "@jridgewell/set-array": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
- "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
- "dev": true
- },
- "@jridgewell/source-map": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz",
- "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==",
- "dev": true,
- "requires": {
- "@jridgewell/gen-mapping": "^0.3.0",
- "@jridgewell/trace-mapping": "^0.3.9"
- },
- "dependencies": {
- "@jridgewell/gen-mapping": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz",
- "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==",
- "dev": true,
- "requires": {
- "@jridgewell/set-array": "^1.0.1",
- "@jridgewell/sourcemap-codec": "^1.4.10",
- "@jridgewell/trace-mapping": "^0.3.9"
- }
- }
- }
- },
- "@jridgewell/sourcemap-codec": {
- "version": "1.4.14",
- "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
- "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
- "dev": true
- },
- "@jridgewell/trace-mapping": {
- "version": "0.3.17",
- "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz",
- "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==",
- "dev": true,
- "requires": {
- "@jridgewell/resolve-uri": "3.1.0",
- "@jridgewell/sourcemap-codec": "1.4.14"
- }
- },
- "@nicolo-ribaudo/chokidar-2": {
- "version": "2.1.8-no-fsevents.3",
- "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz",
- "integrity": "sha512-s88O1aVtXftvp5bCPB7WnmXc5IwOZZ7YPuwNPt+GtOOXpPvad1LfbmjYv+qII7zP6RU2QGnqve27dnLycEnyEQ==",
- "dev": true,
- "optional": true
- },
- "@nicolo-ribaudo/eslint-scope-5-internals": {
- "version": "5.1.1-v1",
- "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz",
- "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==",
- "dev": true,
- "requires": {
- "eslint-scope": "5.1.1"
- }
- },
- "@nodelib/fs.scandir": {
- "version": "2.1.5",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
- "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
- "dev": true,
- "requires": {
- "@nodelib/fs.stat": "2.0.5",
- "run-parallel": "^1.1.9"
- }
- },
- "@nodelib/fs.stat": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
- "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
- "dev": true
- },
- "@nodelib/fs.walk": {
- "version": "1.2.8",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
- "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
- "dev": true,
- "requires": {
- "@nodelib/fs.scandir": "2.1.5",
- "fastq": "^1.6.0"
- }
- },
- "@polka/url": {
- "version": "1.0.0-next.21",
- "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz",
- "integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==",
- "dev": true
- },
- "@sinclair/typebox": {
- "version": "0.24.51",
- "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz",
- "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==",
- "dev": true
- },
- "@sinonjs/commons": {
- "version": "1.8.6",
- "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz",
- "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==",
- "dev": true,
- "requires": {
- "type-detect": "4.0.8"
- }
- },
- "@sinonjs/fake-timers": {
- "version": "9.1.2",
- "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz",
- "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==",
- "dev": true,
- "requires": {
- "@sinonjs/commons": "^1.7.0"
- }
- },
- "@types/babel__core": {
- "version": "7.1.20",
- "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.20.tgz",
- "integrity": "sha512-PVb6Bg2QuscZ30FvOU7z4guG6c926D9YRvOxEaelzndpMsvP+YM74Q/dAFASpg2l6+XLalxSGxcq/lrgYWZtyQ==",
- "dev": true,
- "requires": {
- "@babel/parser": "^7.1.0",
- "@babel/types": "^7.0.0",
- "@types/babel__generator": "*",
- "@types/babel__template": "*",
- "@types/babel__traverse": "*"
- }
- },
- "@types/babel__generator": {
- "version": "7.6.4",
- "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz",
- "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.0.0"
- }
- },
- "@types/babel__template": {
- "version": "7.4.1",
- "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz",
- "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==",
- "dev": true,
- "requires": {
- "@babel/parser": "^7.1.0",
- "@babel/types": "^7.0.0"
- }
- },
- "@types/babel__traverse": {
- "version": "7.18.3",
- "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.3.tgz",
- "integrity": "sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.3.0"
- }
- },
- "@types/eslint": {
- "version": "8.4.10",
- "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.10.tgz",
- "integrity": "sha512-Sl/HOqN8NKPmhWo2VBEPm0nvHnu2LL3v9vKo8MEq0EtbJ4eVzGPl41VNPvn5E1i5poMk4/XD8UriLHpJvEP/Nw==",
- "dev": true,
- "requires": {
- "@types/estree": "*",
- "@types/json-schema": "*"
- }
- },
- "@types/eslint-scope": {
- "version": "3.7.4",
- "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz",
- "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==",
- "dev": true,
- "requires": {
- "@types/eslint": "*",
- "@types/estree": "*"
- }
- },
- "@types/estree": {
- "version": "0.0.51",
- "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz",
- "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==",
- "dev": true
- },
- "@types/graceful-fs": {
- "version": "4.1.6",
- "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz",
- "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==",
- "dev": true,
- "requires": {
- "@types/node": "*"
- }
- },
- "@types/istanbul-lib-coverage": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz",
- "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==",
- "dev": true
- },
- "@types/istanbul-lib-report": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz",
- "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==",
- "dev": true,
- "requires": {
- "@types/istanbul-lib-coverage": "*"
- }
- },
- "@types/istanbul-reports": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz",
- "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==",
- "dev": true,
- "requires": {
- "@types/istanbul-lib-report": "*"
- }
- },
- "@types/jest": {
- "version": "29.2.5",
- "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.2.5.tgz",
- "integrity": "sha512-H2cSxkKgVmqNHXP7TC2L/WUorrZu8ZigyRywfVzv6EyBlxj39n4C00hjXYQWsbwqgElaj/CiAeSRmk5GoaKTgw==",
- "dev": true,
- "requires": {
- "expect": "^29.0.0",
- "pretty-format": "^29.0.0"
- }
- },
- "@types/json-schema": {
- "version": "7.0.11",
- "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz",
- "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==",
- "dev": true
- },
- "@types/node": {
- "version": "18.11.18",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz",
- "integrity": "sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==",
- "dev": true
- },
- "@types/node-fetch": {
- "version": "2.6.2",
- "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.2.tgz",
- "integrity": "sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==",
- "dev": true,
- "requires": {
- "@types/node": "*",
- "form-data": "^3.0.0"
- }
- },
- "@types/prettier": {
- "version": "2.7.2",
- "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.2.tgz",
- "integrity": "sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==",
- "dev": true
- },
- "@types/semver": {
- "version": "7.3.13",
- "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz",
- "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==",
- "dev": true
- },
- "@types/stack-utils": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz",
- "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==",
- "dev": true
- },
- "@types/yargs": {
- "version": "17.0.19",
- "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.19.tgz",
- "integrity": "sha512-cAx3qamwaYX9R0fzOIZAlFpo4A+1uBVCxqpKz9D26uTF4srRXaGTTsikQmaotCtNdbhzyUH7ft6p9ktz9s6UNQ==",
- "dev": true,
- "requires": {
- "@types/yargs-parser": "*"
- }
- },
- "@types/yargs-parser": {
- "version": "21.0.0",
- "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz",
- "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==",
- "dev": true
- },
- "@typescript-eslint/eslint-plugin": {
- "version": "5.48.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.48.2.tgz",
- "integrity": "sha512-sR0Gja9Ky1teIq4qJOl0nC+Tk64/uYdX+mi+5iB//MH8gwyx8e3SOyhEzeLZEFEEfCaLf8KJq+Bd/6je1t+CAg==",
- "dev": true,
- "requires": {
- "@typescript-eslint/scope-manager": "5.48.2",
- "@typescript-eslint/type-utils": "5.48.2",
- "@typescript-eslint/utils": "5.48.2",
- "debug": "^4.3.4",
- "ignore": "^5.2.0",
- "natural-compare-lite": "^1.4.0",
- "regexpp": "^3.2.0",
- "semver": "^7.3.7",
- "tsutils": "^3.21.0"
- },
- "dependencies": {
- "lru-cache": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
- "dev": true,
- "requires": {
- "yallist": "^4.0.0"
- }
- },
- "semver": {
- "version": "7.3.8",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
- "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
- "dev": true,
- "requires": {
- "lru-cache": "^6.0.0"
- }
- },
- "yallist": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
- "dev": true
- }
- }
- },
- "@typescript-eslint/parser": {
- "version": "5.48.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.48.2.tgz",
- "integrity": "sha512-38zMsKsG2sIuM5Oi/olurGwYJXzmtdsHhn5mI/pQogP+BjYVkK5iRazCQ8RGS0V+YLk282uWElN70zAAUmaYHw==",
- "dev": true,
- "requires": {
- "@typescript-eslint/scope-manager": "5.48.2",
- "@typescript-eslint/types": "5.48.2",
- "@typescript-eslint/typescript-estree": "5.48.2",
- "debug": "^4.3.4"
- }
- },
- "@typescript-eslint/scope-manager": {
- "version": "5.48.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.2.tgz",
- "integrity": "sha512-zEUFfonQid5KRDKoI3O+uP1GnrFd4tIHlvs+sTJXiWuypUWMuDaottkJuR612wQfOkjYbsaskSIURV9xo4f+Fw==",
- "dev": true,
- "requires": {
- "@typescript-eslint/types": "5.48.2",
- "@typescript-eslint/visitor-keys": "5.48.2"
- }
- },
- "@typescript-eslint/type-utils": {
- "version": "5.48.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.48.2.tgz",
- "integrity": "sha512-QVWx7J5sPMRiOMJp5dYshPxABRoZV1xbRirqSk8yuIIsu0nvMTZesKErEA3Oix1k+uvsk8Cs8TGJ6kQ0ndAcew==",
- "dev": true,
- "requires": {
- "@typescript-eslint/typescript-estree": "5.48.2",
- "@typescript-eslint/utils": "5.48.2",
- "debug": "^4.3.4",
- "tsutils": "^3.21.0"
- }
- },
- "@typescript-eslint/types": {
- "version": "5.48.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.2.tgz",
- "integrity": "sha512-hE7dA77xxu7ByBc6KCzikgfRyBCTst6dZQpwaTy25iMYOnbNljDT4hjhrGEJJ0QoMjrfqrx+j1l1B9/LtKeuqA==",
- "dev": true
- },
- "@typescript-eslint/typescript-estree": {
- "version": "5.48.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.2.tgz",
- "integrity": "sha512-bibvD3z6ilnoVxUBFEgkO0k0aFvUc4Cttt0dAreEr+nrAHhWzkO83PEVVuieK3DqcgL6VAK5dkzK8XUVja5Zcg==",
- "dev": true,
- "requires": {
- "@typescript-eslint/types": "5.48.2",
- "@typescript-eslint/visitor-keys": "5.48.2",
- "debug": "^4.3.4",
- "globby": "^11.1.0",
- "is-glob": "^4.0.3",
- "semver": "^7.3.7",
- "tsutils": "^3.21.0"
- },
- "dependencies": {
- "lru-cache": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
- "dev": true,
- "requires": {
- "yallist": "^4.0.0"
- }
- },
- "semver": {
- "version": "7.3.8",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
- "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
- "dev": true,
- "requires": {
- "lru-cache": "^6.0.0"
- }
- },
- "yallist": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
- "dev": true
- }
- }
- },
- "@typescript-eslint/utils": {
- "version": "5.48.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.2.tgz",
- "integrity": "sha512-2h18c0d7jgkw6tdKTlNaM7wyopbLRBiit8oAxoP89YnuBOzCZ8g8aBCaCqq7h208qUTroL7Whgzam7UY3HVLow==",
- "dev": true,
- "requires": {
- "@types/json-schema": "^7.0.9",
- "@types/semver": "^7.3.12",
- "@typescript-eslint/scope-manager": "5.48.2",
- "@typescript-eslint/types": "5.48.2",
- "@typescript-eslint/typescript-estree": "5.48.2",
- "eslint-scope": "^5.1.1",
- "eslint-utils": "^3.0.0",
- "semver": "^7.3.7"
- },
- "dependencies": {
- "lru-cache": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
- "dev": true,
- "requires": {
- "yallist": "^4.0.0"
- }
- },
- "semver": {
- "version": "7.3.8",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
- "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
- "dev": true,
- "requires": {
- "lru-cache": "^6.0.0"
- }
- },
- "yallist": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
- "dev": true
- }
- }
- },
- "@typescript-eslint/visitor-keys": {
- "version": "5.48.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.2.tgz",
- "integrity": "sha512-z9njZLSkwmjFWUelGEwEbdf4NwKvfHxvGC0OcGN1Hp/XNDIcJ7D5DpPNPv6x6/mFvc1tQHsaWmpD/a4gOvvCJQ==",
- "dev": true,
- "requires": {
- "@typescript-eslint/types": "5.48.2",
- "eslint-visitor-keys": "^3.3.0"
- },
- "dependencies": {
- "eslint-visitor-keys": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz",
- "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==",
- "dev": true
- }
- }
- },
- "@webassemblyjs/ast": {
- "version": "1.11.1",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz",
- "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==",
- "dev": true,
- "requires": {
- "@webassemblyjs/helper-numbers": "1.11.1",
- "@webassemblyjs/helper-wasm-bytecode": "1.11.1"
- }
- },
- "@webassemblyjs/floating-point-hex-parser": {
- "version": "1.11.1",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz",
- "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==",
- "dev": true
- },
- "@webassemblyjs/helper-api-error": {
- "version": "1.11.1",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz",
- "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==",
- "dev": true
- },
- "@webassemblyjs/helper-buffer": {
- "version": "1.11.1",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz",
- "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==",
- "dev": true
- },
- "@webassemblyjs/helper-numbers": {
- "version": "1.11.1",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz",
- "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==",
- "dev": true,
- "requires": {
- "@webassemblyjs/floating-point-hex-parser": "1.11.1",
- "@webassemblyjs/helper-api-error": "1.11.1",
- "@xtuc/long": "4.2.2"
- }
- },
- "@webassemblyjs/helper-wasm-bytecode": {
- "version": "1.11.1",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz",
- "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==",
- "dev": true
- },
- "@webassemblyjs/helper-wasm-section": {
- "version": "1.11.1",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz",
- "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==",
- "dev": true,
- "requires": {
- "@webassemblyjs/ast": "1.11.1",
- "@webassemblyjs/helper-buffer": "1.11.1",
- "@webassemblyjs/helper-wasm-bytecode": "1.11.1",
- "@webassemblyjs/wasm-gen": "1.11.1"
- }
- },
- "@webassemblyjs/ieee754": {
- "version": "1.11.1",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz",
- "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==",
- "dev": true,
- "requires": {
- "@xtuc/ieee754": "^1.2.0"
- }
- },
- "@webassemblyjs/leb128": {
- "version": "1.11.1",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz",
- "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==",
- "dev": true,
- "requires": {
- "@xtuc/long": "4.2.2"
- }
- },
- "@webassemblyjs/utf8": {
- "version": "1.11.1",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz",
- "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==",
- "dev": true
- },
- "@webassemblyjs/wasm-edit": {
- "version": "1.11.1",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz",
- "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==",
- "dev": true,
- "requires": {
- "@webassemblyjs/ast": "1.11.1",
- "@webassemblyjs/helper-buffer": "1.11.1",
- "@webassemblyjs/helper-wasm-bytecode": "1.11.1",
- "@webassemblyjs/helper-wasm-section": "1.11.1",
- "@webassemblyjs/wasm-gen": "1.11.1",
- "@webassemblyjs/wasm-opt": "1.11.1",
- "@webassemblyjs/wasm-parser": "1.11.1",
- "@webassemblyjs/wast-printer": "1.11.1"
- }
- },
- "@webassemblyjs/wasm-gen": {
- "version": "1.11.1",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz",
- "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==",
- "dev": true,
- "requires": {
- "@webassemblyjs/ast": "1.11.1",
- "@webassemblyjs/helper-wasm-bytecode": "1.11.1",
- "@webassemblyjs/ieee754": "1.11.1",
- "@webassemblyjs/leb128": "1.11.1",
- "@webassemblyjs/utf8": "1.11.1"
- }
- },
- "@webassemblyjs/wasm-opt": {
- "version": "1.11.1",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz",
- "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==",
- "dev": true,
- "requires": {
- "@webassemblyjs/ast": "1.11.1",
- "@webassemblyjs/helper-buffer": "1.11.1",
- "@webassemblyjs/wasm-gen": "1.11.1",
- "@webassemblyjs/wasm-parser": "1.11.1"
- }
- },
- "@webassemblyjs/wasm-parser": {
- "version": "1.11.1",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz",
- "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==",
- "dev": true,
- "requires": {
- "@webassemblyjs/ast": "1.11.1",
- "@webassemblyjs/helper-api-error": "1.11.1",
- "@webassemblyjs/helper-wasm-bytecode": "1.11.1",
- "@webassemblyjs/ieee754": "1.11.1",
- "@webassemblyjs/leb128": "1.11.1",
- "@webassemblyjs/utf8": "1.11.1"
- }
- },
- "@webassemblyjs/wast-printer": {
- "version": "1.11.1",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz",
- "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==",
- "dev": true,
- "requires": {
- "@webassemblyjs/ast": "1.11.1",
- "@xtuc/long": "4.2.2"
- }
- },
- "@webpack-cli/configtest": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.2.0.tgz",
- "integrity": "sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==",
- "dev": true,
- "requires": {}
- },
- "@webpack-cli/info": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.5.0.tgz",
- "integrity": "sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ==",
- "dev": true,
- "requires": {
- "envinfo": "^7.7.3"
- }
- },
- "@webpack-cli/serve": {
- "version": "1.7.0",
- "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.7.0.tgz",
- "integrity": "sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==",
- "dev": true,
- "requires": {}
- },
- "@xtuc/ieee754": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
- "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==",
- "dev": true
- },
- "@xtuc/long": {
- "version": "4.2.2",
- "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz",
- "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==",
- "dev": true
- },
- "acorn": {
- "version": "8.8.1",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz",
- "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==",
- "dev": true
- },
- "acorn-jsx": {
- "version": "5.3.2",
- "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
- "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
- "dev": true,
- "requires": {}
- },
- "ajv": {
- "version": "6.12.6",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
- "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
- "dev": true,
- "requires": {
- "fast-deep-equal": "^3.1.1",
- "fast-json-stable-stringify": "^2.0.0",
- "json-schema-traverse": "^0.4.1",
- "uri-js": "^4.2.2"
- }
- },
- "ajv-keywords": {
- "version": "3.5.2",
- "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
- "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
- "dev": true,
- "requires": {}
- },
- "ansi-colors": {
- "version": "4.1.3",
- "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz",
- "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==",
- "dev": true
- },
- "ansi-escapes": {
- "version": "4.3.2",
- "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
- "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==",
- "dev": true,
- "requires": {
- "type-fest": "^0.21.3"
- }
- },
- "ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "dev": true
- },
- "ansi-styles": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
- "dev": true,
- "requires": {
- "color-convert": "^1.9.0"
- }
- },
- "anymatch": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
- "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
- "dev": true,
- "requires": {
- "normalize-path": "^3.0.0",
- "picomatch": "^2.0.4"
- }
- },
- "argparse": {
- "version": "1.0.10",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
- "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
- "dev": true,
- "requires": {
- "sprintf-js": "~1.0.2"
- }
- },
- "array-union": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
- "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
- "dev": true
- },
- "astral-regex": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
- "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==",
- "dev": true
- },
- "asynckit": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
- "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
- "dev": true
- },
- "babel-jest": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.3.1.tgz",
- "integrity": "sha512-aard+xnMoxgjwV70t0L6wkW/3HQQtV+O0PEimxKgzNqCJnbYmroPojdP2tqKSOAt8QAKV/uSZU8851M7B5+fcA==",
- "dev": true,
- "requires": {
- "@jest/transform": "^29.3.1",
- "@types/babel__core": "^7.1.14",
- "babel-plugin-istanbul": "^6.1.1",
- "babel-preset-jest": "^29.2.0",
- "chalk": "^4.0.0",
- "graceful-fs": "^4.2.9",
- "slash": "^3.0.0"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true
- },
- "slash": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
- "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
- "dev": true
- },
- "supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "requires": {
- "has-flag": "^4.0.0"
- }
- }
- }
- },
- "babel-loader": {
- "version": "8.3.0",
- "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.3.0.tgz",
- "integrity": "sha512-H8SvsMF+m9t15HNLMipppzkC+Y2Yq+v3SonZyU70RBL/h1gxPkH08Ot8pEE9Z4Kd+czyWJClmFS8qzIP9OZ04Q==",
- "dev": true,
- "requires": {
- "find-cache-dir": "^3.3.1",
- "loader-utils": "^2.0.0",
- "make-dir": "^3.1.0",
- "schema-utils": "^2.6.5"
- },
- "dependencies": {
- "find-cache-dir": {
- "version": "3.3.2",
- "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz",
- "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==",
- "dev": true,
- "requires": {
- "commondir": "^1.0.1",
- "make-dir": "^3.0.2",
- "pkg-dir": "^4.1.0"
- }
- },
- "make-dir": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
- "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
- "dev": true,
- "requires": {
- "semver": "^6.0.0"
- }
- },
- "pkg-dir": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
- "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
- "dev": true,
- "requires": {
- "find-up": "^4.0.0"
- }
- }
- }
- },
- "babel-plugin-istanbul": {
- "version": "6.1.1",
- "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz",
- "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.0.0",
- "@istanbuljs/load-nyc-config": "^1.0.0",
- "@istanbuljs/schema": "^0.1.2",
- "istanbul-lib-instrument": "^5.0.4",
- "test-exclude": "^6.0.0"
- }
- },
- "babel-plugin-jest-hoist": {
- "version": "29.2.0",
- "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.2.0.tgz",
- "integrity": "sha512-TnspP2WNiR3GLfCsUNHqeXw0RoQ2f9U5hQ5L3XFpwuO8htQmSrhh8qsB6vi5Yi8+kuynN1yjDjQsPfkebmB6ZA==",
- "dev": true,
- "requires": {
- "@babel/template": "^7.3.3",
- "@babel/types": "^7.3.3",
- "@types/babel__core": "^7.1.14",
- "@types/babel__traverse": "^7.0.6"
- }
- },
- "babel-plugin-polyfill-corejs2": {
- "version": "0.3.3",
- "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz",
- "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==",
- "dev": true,
- "requires": {
- "@babel/compat-data": "^7.17.7",
- "@babel/helper-define-polyfill-provider": "^0.3.3",
- "semver": "^6.1.1"
- }
- },
- "babel-plugin-polyfill-corejs3": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz",
- "integrity": "sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==",
- "dev": true,
- "requires": {
- "@babel/helper-define-polyfill-provider": "^0.3.3",
- "core-js-compat": "^3.25.1"
- }
- },
- "babel-plugin-polyfill-regenerator": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz",
- "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==",
- "dev": true,
- "requires": {
- "@babel/helper-define-polyfill-provider": "^0.3.3"
- }
- },
- "babel-preset-current-node-syntax": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz",
- "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==",
- "dev": true,
- "requires": {
- "@babel/plugin-syntax-async-generators": "^7.8.4",
- "@babel/plugin-syntax-bigint": "^7.8.3",
- "@babel/plugin-syntax-class-properties": "^7.8.3",
- "@babel/plugin-syntax-import-meta": "^7.8.3",
- "@babel/plugin-syntax-json-strings": "^7.8.3",
- "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3",
- "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3",
- "@babel/plugin-syntax-numeric-separator": "^7.8.3",
- "@babel/plugin-syntax-object-rest-spread": "^7.8.3",
- "@babel/plugin-syntax-optional-catch-binding": "^7.8.3",
- "@babel/plugin-syntax-optional-chaining": "^7.8.3",
- "@babel/plugin-syntax-top-level-await": "^7.8.3"
- }
- },
- "babel-preset-jest": {
- "version": "29.2.0",
- "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.2.0.tgz",
- "integrity": "sha512-z9JmMJppMxNv8N7fNRHvhMg9cvIkMxQBXgFkane3yKVEvEOP+kB50lk8DFRvF9PGqbyXxlmebKWhuDORO8RgdA==",
- "dev": true,
- "requires": {
- "babel-plugin-jest-hoist": "^29.2.0",
- "babel-preset-current-node-syntax": "^1.0.0"
- }
- },
- "balanced-match": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
- "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
- "dev": true
- },
- "big.js": {
- "version": "5.2.2",
- "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
- "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==",
- "dev": true
- },
- "binary-extensions": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
- "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
- "dev": true,
- "optional": true
- },
- "brace-expansion": {
- "version": "1.1.11",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
- "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
- "dev": true,
- "requires": {
- "balanced-match": "^1.0.0",
- "concat-map": "0.0.1"
- }
- },
- "braces": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
- "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
- "dev": true,
- "requires": {
- "fill-range": "^7.0.1"
- }
- },
- "browserslist": {
- "version": "4.21.4",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz",
- "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==",
- "dev": true,
- "requires": {
- "caniuse-lite": "^1.0.30001400",
- "electron-to-chromium": "^1.4.251",
- "node-releases": "^2.0.6",
- "update-browserslist-db": "^1.0.9"
- }
- },
- "bs-logger": {
- "version": "0.2.6",
- "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz",
- "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==",
- "dev": true,
- "requires": {
- "fast-json-stable-stringify": "2.x"
- }
- },
- "bser": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz",
- "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==",
- "dev": true,
- "requires": {
- "node-int64": "^0.4.0"
- }
- },
- "buffer-from": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
- "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
- "dev": true
- },
- "callsites": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
- "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
- "dev": true
- },
- "camelcase": {
- "version": "5.3.1",
- "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
- "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
- "dev": true
- },
- "caniuse-lite": {
- "version": "1.0.30001535",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001535.tgz",
- "integrity": "sha512-48jLyUkiWFfhm/afF7cQPqPjaUmSraEhK4j+FCTJpgnGGEZHqyLe3hmWH7lIooZdSzXL0ReMvHz0vKDoTBsrwg==",
- "dev": true
- },
- "chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
- "dev": true,
- "requires": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- }
- },
- "char-regex": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz",
- "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==",
- "dev": true
- },
- "chokidar": {
- "version": "3.5.3",
- "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
- "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
- "dev": true,
- "optional": true,
- "requires": {
- "anymatch": "~3.1.2",
- "braces": "~3.0.2",
- "fsevents": "~2.3.2",
- "glob-parent": "~5.1.2",
- "is-binary-path": "~2.1.0",
- "is-glob": "~4.0.1",
- "normalize-path": "~3.0.0",
- "readdirp": "~3.6.0"
- }
- },
- "chrome-trace-event": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz",
- "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==",
- "dev": true
- },
- "ci-info": {
- "version": "3.7.1",
- "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.7.1.tgz",
- "integrity": "sha512-4jYS4MOAaCIStSRwiuxc4B8MYhIe676yO1sYGzARnjXkWpmzZMMYxY6zu8WYWDhSuth5zhrQ1rhNSibyyvv4/w==",
- "dev": true
- },
- "cjs-module-lexer": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz",
- "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==",
- "dev": true
- },
- "cliui": {
- "version": "8.0.1",
- "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
- "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
- "dev": true,
- "requires": {
- "string-width": "^4.2.0",
- "strip-ansi": "^6.0.1",
- "wrap-ansi": "^7.0.0"
- }
- },
- "clone-deep": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz",
- "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==",
- "dev": true,
- "requires": {
- "is-plain-object": "^2.0.4",
- "kind-of": "^6.0.2",
- "shallow-clone": "^3.0.0"
- }
- },
- "co": {
- "version": "4.6.0",
- "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
- "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==",
- "dev": true
- },
- "collect-v8-coverage": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz",
- "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==",
- "dev": true
- },
- "color-convert": {
- "version": "1.9.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
- "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "dev": true,
- "requires": {
- "color-name": "1.1.3"
- }
- },
- "color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
- "dev": true
- },
- "colorette": {
- "version": "2.0.19",
- "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz",
- "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==",
- "dev": true
- },
- "combined-stream": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
- "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
- "dev": true,
- "requires": {
- "delayed-stream": "~1.0.0"
- }
- },
- "commander": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
- "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==",
- "dev": true
- },
- "commondir": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
- "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==",
- "dev": true
- },
- "concat-map": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
- "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
- "dev": true
- },
- "convert-source-map": {
- "version": "1.9.0",
- "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
- "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
- "dev": true
- },
- "core-js": {
- "version": "3.27.1",
- "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.27.1.tgz",
- "integrity": "sha512-GutwJLBChfGCpwwhbYoqfv03LAfmiz7e7D/BNxzeMxwQf10GRSzqiOjx7AmtEk+heiD/JWmBuyBPgFtx0Sg1ww=="
- },
- "core-js-compat": {
- "version": "3.27.1",
- "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.27.1.tgz",
- "integrity": "sha512-Dg91JFeCDA17FKnneN7oCMz4BkQ4TcffkgHP4OWwp9yx3pi7ubqMDXXSacfNak1PQqjc95skyt+YBLHQJnkJwA==",
- "dev": true,
- "requires": {
- "browserslist": "^4.21.4"
- }
- },
- "cross-spawn": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
- "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
- "dev": true,
- "requires": {
- "path-key": "^3.1.0",
- "shebang-command": "^2.0.0",
- "which": "^2.0.1"
- }
- },
- "debug": {
- "version": "4.3.4",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
- "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
- "dev": true,
- "requires": {
- "ms": "2.1.2"
- }
- },
- "dedent": {
- "version": "0.7.0",
- "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz",
- "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==",
- "dev": true
- },
- "deep-is": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
- "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
- "dev": true
- },
- "deepmerge": {
- "version": "4.2.2",
- "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz",
- "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==",
- "dev": true
- },
- "delayed-stream": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
- "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
- "dev": true
- },
- "detect-newline": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz",
- "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==",
- "dev": true
- },
- "diff-sequences": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.3.1.tgz",
- "integrity": "sha512-hlM3QR272NXCi4pq+N4Kok4kOp6EsgOM3ZSpJI7Da3UAs+Ttsi8MRmB6trM/lhyzUxGfOgnpkHtgqm5Q/CTcfQ==",
- "dev": true
- },
- "dir-glob": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
- "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
- "dev": true,
- "requires": {
- "path-type": "^4.0.0"
- }
- },
- "doctrine": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
- "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
- "dev": true,
- "requires": {
- "esutils": "^2.0.2"
- }
- },
- "duplexer": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz",
- "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==",
- "dev": true
- },
- "electron-to-chromium": {
- "version": "1.4.284",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz",
- "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==",
- "dev": true
- },
- "emittery": {
- "version": "0.13.1",
- "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz",
- "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==",
- "dev": true
- },
- "emoji-regex": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
- "dev": true
- },
- "emojis-list": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz",
- "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==",
- "dev": true
- },
- "enhanced-resolve": {
- "version": "5.12.0",
- "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz",
- "integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==",
- "dev": true,
- "requires": {
- "graceful-fs": "^4.2.4",
- "tapable": "^2.2.0"
- }
- },
- "enquirer": {
- "version": "2.3.6",
- "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz",
- "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==",
- "dev": true,
- "requires": {
- "ansi-colors": "^4.1.1"
- }
- },
- "envinfo": {
- "version": "7.8.1",
- "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz",
- "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==",
- "dev": true
- },
- "error-ex": {
- "version": "1.3.2",
- "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
- "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
- "dev": true,
- "requires": {
- "is-arrayish": "^0.2.1"
- }
- },
- "es-module-lexer": {
- "version": "0.9.3",
- "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz",
- "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==",
- "dev": true
- },
- "escalade": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
- "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
- "dev": true
- },
- "escape-string-regexp": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
- "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
- "dev": true
- },
- "eslint": {
- "version": "7.32.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz",
- "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==",
- "dev": true,
- "requires": {
- "@babel/code-frame": "7.12.11",
- "@eslint/eslintrc": "^0.4.3",
- "@humanwhocodes/config-array": "^0.5.0",
- "ajv": "^6.10.0",
- "chalk": "^4.0.0",
- "cross-spawn": "^7.0.2",
- "debug": "^4.0.1",
- "doctrine": "^3.0.0",
- "enquirer": "^2.3.5",
- "escape-string-regexp": "^4.0.0",
- "eslint-scope": "^5.1.1",
- "eslint-utils": "^2.1.0",
- "eslint-visitor-keys": "^2.0.0",
- "espree": "^7.3.1",
- "esquery": "^1.4.0",
- "esutils": "^2.0.2",
- "fast-deep-equal": "^3.1.3",
- "file-entry-cache": "^6.0.1",
- "functional-red-black-tree": "^1.0.1",
- "glob-parent": "^5.1.2",
- "globals": "^13.6.0",
- "ignore": "^4.0.6",
- "import-fresh": "^3.0.0",
- "imurmurhash": "^0.1.4",
- "is-glob": "^4.0.0",
- "js-yaml": "^3.13.1",
- "json-stable-stringify-without-jsonify": "^1.0.1",
- "levn": "^0.4.1",
- "lodash.merge": "^4.6.2",
- "minimatch": "^3.0.4",
- "natural-compare": "^1.4.0",
- "optionator": "^0.9.1",
- "progress": "^2.0.0",
- "regexpp": "^3.1.0",
- "semver": "^7.2.1",
- "strip-ansi": "^6.0.0",
- "strip-json-comments": "^3.1.0",
- "table": "^6.0.9",
- "text-table": "^0.2.0",
- "v8-compile-cache": "^2.0.3"
- },
- "dependencies": {
- "@babel/code-frame": {
- "version": "7.12.11",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz",
- "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==",
- "dev": true,
- "requires": {
- "@babel/highlight": "^7.10.4"
- }
- },
- "ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "escape-string-regexp": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
- "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
- "dev": true
- },
- "eslint-utils": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz",
- "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==",
- "dev": true,
- "requires": {
- "eslint-visitor-keys": "^1.1.0"
- },
- "dependencies": {
- "eslint-visitor-keys": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
- "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
- "dev": true
- }
- }
- },
- "globals": {
- "version": "13.19.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz",
- "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==",
- "dev": true,
- "requires": {
- "type-fest": "^0.20.2"
- }
- },
- "has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true
- },
- "ignore": {
- "version": "4.0.6",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
- "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
- "dev": true
- },
- "lru-cache": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
- "dev": true,
- "requires": {
- "yallist": "^4.0.0"
- }
- },
- "semver": {
- "version": "7.3.8",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
- "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
- "dev": true,
- "requires": {
- "lru-cache": "^6.0.0"
- }
- },
- "supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "requires": {
- "has-flag": "^4.0.0"
- }
- },
- "type-fest": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
- "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
- "dev": true
- },
- "yallist": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
- "dev": true
- }
- }
- },
- "eslint-config-prettier": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-7.2.0.tgz",
- "integrity": "sha512-rV4Qu0C3nfJKPOAhFujFxB7RMP+URFyQqqOZW9DMRD7ZDTFyjaIlETU3xzHELt++4ugC0+Jm084HQYkkJe+Ivg==",
- "dev": true,
- "requires": {}
- },
- "eslint-scope": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
- "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
- "dev": true,
- "requires": {
- "esrecurse": "^4.3.0",
- "estraverse": "^4.1.1"
- }
- },
- "eslint-utils": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz",
- "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==",
- "dev": true,
- "requires": {
- "eslint-visitor-keys": "^2.0.0"
- }
- },
- "eslint-visitor-keys": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
- "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
- "dev": true
- },
- "espree": {
- "version": "7.3.1",
- "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz",
- "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==",
- "dev": true,
- "requires": {
- "acorn": "^7.4.0",
- "acorn-jsx": "^5.3.1",
- "eslint-visitor-keys": "^1.3.0"
- },
- "dependencies": {
- "acorn": {
- "version": "7.4.1",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
- "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
- "dev": true
- },
- "eslint-visitor-keys": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
- "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
- "dev": true
- }
- }
- },
- "esprima": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
- "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
- "dev": true
- },
- "esquery": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz",
- "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==",
- "dev": true,
- "requires": {
- "estraverse": "^5.1.0"
- },
- "dependencies": {
- "estraverse": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
- "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
- "dev": true
- }
- }
- },
- "esrecurse": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
- "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
- "dev": true,
- "requires": {
- "estraverse": "^5.2.0"
- },
- "dependencies": {
- "estraverse": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
- "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
- "dev": true
- }
- }
- },
- "estraverse": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
- "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
- "dev": true
- },
- "esutils": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
- "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
- "dev": true
- },
- "events": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
- "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
- "dev": true
- },
- "execa": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
- "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==",
- "dev": true,
- "requires": {
- "cross-spawn": "^7.0.3",
- "get-stream": "^6.0.0",
- "human-signals": "^2.1.0",
- "is-stream": "^2.0.0",
- "merge-stream": "^2.0.0",
- "npm-run-path": "^4.0.1",
- "onetime": "^5.1.2",
- "signal-exit": "^3.0.3",
- "strip-final-newline": "^2.0.0"
- }
- },
- "exit": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
- "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==",
- "dev": true
- },
- "expect": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/expect/-/expect-29.3.1.tgz",
- "integrity": "sha512-gGb1yTgU30Q0O/tQq+z30KBWv24ApkMgFUpvKBkyLUBL68Wv8dHdJxTBZFl/iT8K/bqDHvUYRH6IIN3rToopPA==",
- "dev": true,
- "requires": {
- "@jest/expect-utils": "^29.3.1",
- "jest-get-type": "^29.2.0",
- "jest-matcher-utils": "^29.3.1",
- "jest-message-util": "^29.3.1",
- "jest-util": "^29.3.1"
- }
- },
- "fast-deep-equal": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
- "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
- "dev": true
- },
- "fast-glob": {
- "version": "3.2.12",
- "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz",
- "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==",
- "dev": true,
- "requires": {
- "@nodelib/fs.stat": "^2.0.2",
- "@nodelib/fs.walk": "^1.2.3",
- "glob-parent": "^5.1.2",
- "merge2": "^1.3.0",
- "micromatch": "^4.0.4"
- }
- },
- "fast-json-stable-stringify": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
- "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
- "dev": true
- },
- "fast-levenshtein": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
- "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
- "dev": true
- },
- "fastest-levenshtein": {
- "version": "1.0.16",
- "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz",
- "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==",
- "dev": true
- },
- "fastq": {
- "version": "1.15.0",
- "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz",
- "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==",
- "dev": true,
- "requires": {
- "reusify": "^1.0.4"
- }
- },
- "fb-watchman": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz",
- "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==",
- "dev": true,
- "requires": {
- "bser": "2.1.1"
- }
- },
- "file-entry-cache": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
- "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
- "dev": true,
- "requires": {
- "flat-cache": "^3.0.4"
- }
- },
- "fill-range": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
- "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
- "dev": true,
- "requires": {
- "to-regex-range": "^5.0.1"
- }
- },
- "find-cache-dir": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz",
- "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==",
- "dev": true,
- "requires": {
- "commondir": "^1.0.1",
- "make-dir": "^2.0.0",
- "pkg-dir": "^3.0.0"
- }
- },
- "find-up": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
- "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
- "dev": true,
- "requires": {
- "locate-path": "^5.0.0",
- "path-exists": "^4.0.0"
- }
- },
- "flat-cache": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
- "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==",
- "dev": true,
- "requires": {
- "flatted": "^3.1.0",
- "rimraf": "^3.0.2"
- }
- },
- "flatted": {
- "version": "3.2.7",
- "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz",
- "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==",
- "dev": true
- },
- "form-data": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz",
- "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==",
- "dev": true,
- "requires": {
- "asynckit": "^0.4.0",
- "combined-stream": "^1.0.8",
- "mime-types": "^2.1.12"
- }
- },
- "fs-readdir-recursive": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz",
- "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==",
- "dev": true
- },
- "fs.realpath": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
- "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
- "dev": true
- },
- "fsevents": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
- "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
- "dev": true,
- "optional": true
- },
- "function-bind": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
- "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
- "dev": true
- },
- "functional-red-black-tree": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
- "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==",
- "dev": true
- },
- "gensync": {
- "version": "1.0.0-beta.2",
- "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
- "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
- "dev": true
- },
- "get-caller-file": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
- "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
- "dev": true
- },
- "get-package-type": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz",
- "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==",
- "dev": true
- },
- "get-stream": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
- "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
- "dev": true
- },
- "glob": {
- "version": "7.2.3",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
- "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
- "dev": true,
- "requires": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.1.1",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
- }
- },
- "glob-parent": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
- "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
- "dev": true,
- "requires": {
- "is-glob": "^4.0.1"
- }
- },
- "glob-to-regexp": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
- "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==",
- "dev": true
- },
- "globals": {
- "version": "11.12.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
- "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
- "dev": true
- },
- "globby": {
- "version": "11.1.0",
- "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
- "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
- "dev": true,
- "requires": {
- "array-union": "^2.1.0",
- "dir-glob": "^3.0.1",
- "fast-glob": "^3.2.9",
- "ignore": "^5.2.0",
- "merge2": "^1.4.1",
- "slash": "^3.0.0"
- },
- "dependencies": {
- "slash": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
- "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
- "dev": true
- }
- }
- },
- "graceful-fs": {
- "version": "4.2.10",
- "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
- "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==",
- "dev": true
- },
- "gzip-size": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz",
- "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==",
- "dev": true,
- "requires": {
- "duplexer": "^0.1.2"
- }
- },
- "has": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
- "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
- "dev": true,
- "requires": {
- "function-bind": "^1.1.1"
- }
- },
- "has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
- "dev": true
- },
- "html-escaper": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
- "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
- "dev": true
- },
- "human-signals": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
- "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==",
- "dev": true
- },
- "ignore": {
- "version": "5.2.4",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
- "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==",
- "dev": true
- },
- "import-fresh": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
- "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
- "dev": true,
- "requires": {
- "parent-module": "^1.0.0",
- "resolve-from": "^4.0.0"
- },
- "dependencies": {
- "resolve-from": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
- "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
- "dev": true
- }
- }
- },
- "import-local": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz",
- "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==",
- "dev": true,
- "requires": {
- "pkg-dir": "^4.2.0",
- "resolve-cwd": "^3.0.0"
- },
- "dependencies": {
- "pkg-dir": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
- "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
- "dev": true,
- "requires": {
- "find-up": "^4.0.0"
- }
- }
- }
- },
- "imurmurhash": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
- "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
- "dev": true
- },
- "inflight": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
- "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
- "dev": true,
- "requires": {
- "once": "^1.3.0",
- "wrappy": "1"
- }
- },
- "inherits": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
- "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
- "dev": true
- },
- "interpret": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz",
- "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==",
- "dev": true
- },
- "is-arrayish": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
- "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
- "dev": true
- },
- "is-binary-path": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
- "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
- "dev": true,
- "optional": true,
- "requires": {
- "binary-extensions": "^2.0.0"
- }
- },
- "is-core-module": {
- "version": "2.11.0",
- "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz",
- "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==",
- "dev": true,
- "requires": {
- "has": "^1.0.3"
- }
- },
- "is-extglob": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
- "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
- "dev": true
- },
- "is-fullwidth-code-point": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
- "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
- "dev": true
- },
- "is-generator-fn": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz",
- "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==",
- "dev": true
- },
- "is-glob": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
- "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
- "dev": true,
- "requires": {
- "is-extglob": "^2.1.1"
- }
- },
- "is-number": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
- "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
- "dev": true
- },
- "is-plain-object": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
- "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
- "dev": true,
- "requires": {
- "isobject": "^3.0.1"
- }
- },
- "is-stream": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
- "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
- "dev": true
- },
- "isexe": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
- "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
- "dev": true
- },
- "isobject": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
- "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==",
- "dev": true
- },
- "istanbul-lib-coverage": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz",
- "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==",
- "dev": true
- },
- "istanbul-lib-instrument": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz",
- "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==",
- "dev": true,
- "requires": {
- "@babel/core": "^7.12.3",
- "@babel/parser": "^7.14.7",
- "@istanbuljs/schema": "^0.1.2",
- "istanbul-lib-coverage": "^3.2.0",
- "semver": "^6.3.0"
- }
- },
- "istanbul-lib-report": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz",
- "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==",
- "dev": true,
- "requires": {
- "istanbul-lib-coverage": "^3.0.0",
- "make-dir": "^3.0.0",
- "supports-color": "^7.1.0"
- },
- "dependencies": {
- "has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true
- },
- "make-dir": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
- "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
- "dev": true,
- "requires": {
- "semver": "^6.0.0"
- }
- },
- "supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "requires": {
- "has-flag": "^4.0.0"
- }
- }
- }
- },
- "istanbul-lib-source-maps": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz",
- "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==",
- "dev": true,
- "requires": {
- "debug": "^4.1.1",
- "istanbul-lib-coverage": "^3.0.0",
- "source-map": "^0.6.1"
- }
- },
- "istanbul-reports": {
- "version": "3.1.5",
- "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz",
- "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==",
- "dev": true,
- "requires": {
- "html-escaper": "^2.0.0",
- "istanbul-lib-report": "^3.0.0"
- }
- },
- "jest": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/jest/-/jest-29.3.1.tgz",
- "integrity": "sha512-6iWfL5DTT0Np6UYs/y5Niu7WIfNv/wRTtN5RSXt2DIEft3dx3zPuw/3WJQBCJfmEzvDiEKwoqMbGD9n49+qLSA==",
- "dev": true,
- "requires": {
- "@jest/core": "^29.3.1",
- "@jest/types": "^29.3.1",
- "import-local": "^3.0.2",
- "jest-cli": "^29.3.1"
- }
- },
- "jest-changed-files": {
- "version": "29.2.0",
- "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.2.0.tgz",
- "integrity": "sha512-qPVmLLyBmvF5HJrY7krDisx6Voi8DmlV3GZYX0aFNbaQsZeoz1hfxcCMbqDGuQCxU1dJy9eYc2xscE8QrCCYaA==",
- "dev": true,
- "requires": {
- "execa": "^5.0.0",
- "p-limit": "^3.1.0"
- },
- "dependencies": {
- "p-limit": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
- "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
- "dev": true,
- "requires": {
- "yocto-queue": "^0.1.0"
- }
- }
- }
- },
- "jest-circus": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.3.1.tgz",
- "integrity": "sha512-wpr26sEvwb3qQQbdlmei+gzp6yoSSoSL6GsLPxnuayZSMrSd5Ka7IjAvatpIernBvT2+Ic6RLTg+jSebScmasg==",
- "dev": true,
- "requires": {
- "@jest/environment": "^29.3.1",
- "@jest/expect": "^29.3.1",
- "@jest/test-result": "^29.3.1",
- "@jest/types": "^29.3.1",
- "@types/node": "*",
- "chalk": "^4.0.0",
- "co": "^4.6.0",
- "dedent": "^0.7.0",
- "is-generator-fn": "^2.0.0",
- "jest-each": "^29.3.1",
- "jest-matcher-utils": "^29.3.1",
- "jest-message-util": "^29.3.1",
- "jest-runtime": "^29.3.1",
- "jest-snapshot": "^29.3.1",
- "jest-util": "^29.3.1",
- "p-limit": "^3.1.0",
- "pretty-format": "^29.3.1",
- "slash": "^3.0.0",
- "stack-utils": "^2.0.3"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true
- },
- "p-limit": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
- "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
- "dev": true,
- "requires": {
- "yocto-queue": "^0.1.0"
- }
- },
- "slash": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
- "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
- "dev": true
- },
- "supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "requires": {
- "has-flag": "^4.0.0"
- }
- }
- }
- },
- "jest-cli": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.3.1.tgz",
- "integrity": "sha512-TO/ewvwyvPOiBBuWZ0gm04z3WWP8TIK8acgPzE4IxgsLKQgb377NYGrQLc3Wl/7ndWzIH2CDNNsUjGxwLL43VQ==",
- "dev": true,
- "requires": {
- "@jest/core": "^29.3.1",
- "@jest/test-result": "^29.3.1",
- "@jest/types": "^29.3.1",
- "chalk": "^4.0.0",
- "exit": "^0.1.2",
- "graceful-fs": "^4.2.9",
- "import-local": "^3.0.2",
- "jest-config": "^29.3.1",
- "jest-util": "^29.3.1",
- "jest-validate": "^29.3.1",
- "prompts": "^2.0.1",
- "yargs": "^17.3.1"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true
- },
- "supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "requires": {
- "has-flag": "^4.0.0"
- }
- }
- }
- },
- "jest-config": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.3.1.tgz",
- "integrity": "sha512-y0tFHdj2WnTEhxmGUK1T7fgLen7YK4RtfvpLFBXfQkh2eMJAQq24Vx9472lvn5wg0MAO6B+iPfJfzdR9hJYalg==",
- "dev": true,
- "requires": {
- "@babel/core": "^7.11.6",
- "@jest/test-sequencer": "^29.3.1",
- "@jest/types": "^29.3.1",
- "babel-jest": "^29.3.1",
- "chalk": "^4.0.0",
- "ci-info": "^3.2.0",
- "deepmerge": "^4.2.2",
- "glob": "^7.1.3",
- "graceful-fs": "^4.2.9",
- "jest-circus": "^29.3.1",
- "jest-environment-node": "^29.3.1",
- "jest-get-type": "^29.2.0",
- "jest-regex-util": "^29.2.0",
- "jest-resolve": "^29.3.1",
- "jest-runner": "^29.3.1",
- "jest-util": "^29.3.1",
- "jest-validate": "^29.3.1",
- "micromatch": "^4.0.4",
- "parse-json": "^5.2.0",
- "pretty-format": "^29.3.1",
- "slash": "^3.0.0",
- "strip-json-comments": "^3.1.1"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true
- },
- "slash": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
- "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
- "dev": true
- },
- "supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "requires": {
- "has-flag": "^4.0.0"
- }
- }
- }
- },
- "jest-diff": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.3.1.tgz",
- "integrity": "sha512-vU8vyiO7568tmin2lA3r2DP8oRvzhvRcD4DjpXc6uGveQodyk7CKLhQlCSiwgx3g0pFaE88/KLZ0yaTWMc4Uiw==",
- "dev": true,
- "requires": {
- "chalk": "^4.0.0",
- "diff-sequences": "^29.3.1",
- "jest-get-type": "^29.2.0",
- "pretty-format": "^29.3.1"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true
- },
- "supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "requires": {
- "has-flag": "^4.0.0"
- }
- }
- }
- },
- "jest-docblock": {
- "version": "29.2.0",
- "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.2.0.tgz",
- "integrity": "sha512-bkxUsxTgWQGbXV5IENmfiIuqZhJcyvF7tU4zJ/7ioTutdz4ToB5Yx6JOFBpgI+TphRY4lhOyCWGNH/QFQh5T6A==",
- "dev": true,
- "requires": {
- "detect-newline": "^3.0.0"
- }
- },
- "jest-each": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.3.1.tgz",
- "integrity": "sha512-qrZH7PmFB9rEzCSl00BWjZYuS1BSOH8lLuC0azQE9lQrAx3PWGKHTDudQiOSwIy5dGAJh7KA0ScYlCP7JxvFYA==",
- "dev": true,
- "requires": {
- "@jest/types": "^29.3.1",
- "chalk": "^4.0.0",
- "jest-get-type": "^29.2.0",
- "jest-util": "^29.3.1",
- "pretty-format": "^29.3.1"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true
- },
- "supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "requires": {
- "has-flag": "^4.0.0"
- }
- }
- }
- },
- "jest-environment-node": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.3.1.tgz",
- "integrity": "sha512-xm2THL18Xf5sIHoU7OThBPtuH6Lerd+Y1NLYiZJlkE3hbE+7N7r8uvHIl/FkZ5ymKXJe/11SQuf3fv4v6rUMag==",
- "dev": true,
- "requires": {
- "@jest/environment": "^29.3.1",
- "@jest/fake-timers": "^29.3.1",
- "@jest/types": "^29.3.1",
- "@types/node": "*",
- "jest-mock": "^29.3.1",
- "jest-util": "^29.3.1"
- }
- },
- "jest-get-type": {
- "version": "29.2.0",
- "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.2.0.tgz",
- "integrity": "sha512-uXNJlg8hKFEnDgFsrCjznB+sTxdkuqiCL6zMgA75qEbAJjJYTs9XPrvDctrEig2GDow22T/LvHgO57iJhXB/UA==",
- "dev": true
- },
- "jest-haste-map": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.3.1.tgz",
- "integrity": "sha512-/FFtvoG1xjbbPXQLFef+WSU4yrc0fc0Dds6aRPBojUid7qlPqZvxdUBA03HW0fnVHXVCnCdkuoghYItKNzc/0A==",
- "dev": true,
- "requires": {
- "@jest/types": "^29.3.1",
- "@types/graceful-fs": "^4.1.3",
- "@types/node": "*",
- "anymatch": "^3.0.3",
- "fb-watchman": "^2.0.0",
- "fsevents": "^2.3.2",
- "graceful-fs": "^4.2.9",
- "jest-regex-util": "^29.2.0",
- "jest-util": "^29.3.1",
- "jest-worker": "^29.3.1",
- "micromatch": "^4.0.4",
- "walker": "^1.0.8"
- }
- },
- "jest-leak-detector": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.3.1.tgz",
- "integrity": "sha512-3DA/VVXj4zFOPagGkuqHnSQf1GZBmmlagpguxEERO6Pla2g84Q1MaVIB3YMxgUaFIaYag8ZnTyQgiZ35YEqAQA==",
- "dev": true,
- "requires": {
- "jest-get-type": "^29.2.0",
- "pretty-format": "^29.3.1"
- }
- },
- "jest-matcher-utils": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.3.1.tgz",
- "integrity": "sha512-fkRMZUAScup3txIKfMe3AIZZmPEjWEdsPJFK3AIy5qRohWqQFg1qrmKfYXR9qEkNc7OdAu2N4KPHibEmy4HPeQ==",
- "dev": true,
- "requires": {
- "chalk": "^4.0.0",
- "jest-diff": "^29.3.1",
- "jest-get-type": "^29.2.0",
- "pretty-format": "^29.3.1"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true
- },
- "supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "requires": {
- "has-flag": "^4.0.0"
- }
- }
- }
- },
- "jest-message-util": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.3.1.tgz",
- "integrity": "sha512-lMJTbgNcDm5z+6KDxWtqOFWlGQxD6XaYwBqHR8kmpkP+WWWG90I35kdtQHY67Ay5CSuydkTBbJG+tH9JShFCyA==",
- "dev": true,
- "requires": {
- "@babel/code-frame": "^7.12.13",
- "@jest/types": "^29.3.1",
- "@types/stack-utils": "^2.0.0",
- "chalk": "^4.0.0",
- "graceful-fs": "^4.2.9",
- "micromatch": "^4.0.4",
- "pretty-format": "^29.3.1",
- "slash": "^3.0.0",
- "stack-utils": "^2.0.3"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true
- },
- "slash": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
- "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
- "dev": true
- },
- "supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "requires": {
- "has-flag": "^4.0.0"
- }
- }
- }
- },
- "jest-mock": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.3.1.tgz",
- "integrity": "sha512-H8/qFDtDVMFvFP4X8NuOT3XRDzOUTz+FeACjufHzsOIBAxivLqkB1PoLCaJx9iPPQ8dZThHPp/G3WRWyMgA3JA==",
- "dev": true,
- "requires": {
- "@jest/types": "^29.3.1",
- "@types/node": "*",
- "jest-util": "^29.3.1"
- }
- },
- "jest-pnp-resolver": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz",
- "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==",
- "dev": true,
- "requires": {}
- },
- "jest-regex-util": {
- "version": "29.2.0",
- "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.2.0.tgz",
- "integrity": "sha512-6yXn0kg2JXzH30cr2NlThF+70iuO/3irbaB4mh5WyqNIvLLP+B6sFdluO1/1RJmslyh/f9osnefECflHvTbwVA==",
- "dev": true
- },
- "jest-resolve": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.3.1.tgz",
- "integrity": "sha512-amXJgH/Ng712w3Uz5gqzFBBjxV8WFLSmNjoreBGMqxgCz5cH7swmBZzgBaCIOsvb0NbpJ0vgaSFdJqMdT+rADw==",
- "dev": true,
- "requires": {
- "chalk": "^4.0.0",
- "graceful-fs": "^4.2.9",
- "jest-haste-map": "^29.3.1",
- "jest-pnp-resolver": "^1.2.2",
- "jest-util": "^29.3.1",
- "jest-validate": "^29.3.1",
- "resolve": "^1.20.0",
- "resolve.exports": "^1.1.0",
- "slash": "^3.0.0"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true
- },
- "slash": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
- "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
- "dev": true
- },
- "supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "requires": {
- "has-flag": "^4.0.0"
- }
- }
- }
- },
- "jest-resolve-dependencies": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.3.1.tgz",
- "integrity": "sha512-Vk0cYq0byRw2WluNmNWGqPeRnZ3p3hHmjJMp2dyyZeYIfiBskwq4rpiuGFR6QGAdbj58WC7HN4hQHjf2mpvrLA==",
- "dev": true,
- "requires": {
- "jest-regex-util": "^29.2.0",
- "jest-snapshot": "^29.3.1"
- }
- },
- "jest-runner": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.3.1.tgz",
- "integrity": "sha512-oFvcwRNrKMtE6u9+AQPMATxFcTySyKfLhvso7Sdk/rNpbhg4g2GAGCopiInk1OP4q6gz3n6MajW4+fnHWlU3bA==",
- "dev": true,
- "requires": {
- "@jest/console": "^29.3.1",
- "@jest/environment": "^29.3.1",
- "@jest/test-result": "^29.3.1",
- "@jest/transform": "^29.3.1",
- "@jest/types": "^29.3.1",
- "@types/node": "*",
- "chalk": "^4.0.0",
- "emittery": "^0.13.1",
- "graceful-fs": "^4.2.9",
- "jest-docblock": "^29.2.0",
- "jest-environment-node": "^29.3.1",
- "jest-haste-map": "^29.3.1",
- "jest-leak-detector": "^29.3.1",
- "jest-message-util": "^29.3.1",
- "jest-resolve": "^29.3.1",
- "jest-runtime": "^29.3.1",
- "jest-util": "^29.3.1",
- "jest-watcher": "^29.3.1",
- "jest-worker": "^29.3.1",
- "p-limit": "^3.1.0",
- "source-map-support": "0.5.13"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true
- },
- "p-limit": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
- "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
- "dev": true,
- "requires": {
- "yocto-queue": "^0.1.0"
- }
- },
- "source-map-support": {
- "version": "0.5.13",
- "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz",
- "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==",
- "dev": true,
- "requires": {
- "buffer-from": "^1.0.0",
- "source-map": "^0.6.0"
- }
- },
- "supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "requires": {
- "has-flag": "^4.0.0"
- }
- }
- }
- },
- "jest-runtime": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.3.1.tgz",
- "integrity": "sha512-jLzkIxIqXwBEOZx7wx9OO9sxoZmgT2NhmQKzHQm1xwR1kNW/dn0OjxR424VwHHf1SPN6Qwlb5pp1oGCeFTQ62A==",
- "dev": true,
- "requires": {
- "@jest/environment": "^29.3.1",
- "@jest/fake-timers": "^29.3.1",
- "@jest/globals": "^29.3.1",
- "@jest/source-map": "^29.2.0",
- "@jest/test-result": "^29.3.1",
- "@jest/transform": "^29.3.1",
- "@jest/types": "^29.3.1",
- "@types/node": "*",
- "chalk": "^4.0.0",
- "cjs-module-lexer": "^1.0.0",
- "collect-v8-coverage": "^1.0.0",
- "glob": "^7.1.3",
- "graceful-fs": "^4.2.9",
- "jest-haste-map": "^29.3.1",
- "jest-message-util": "^29.3.1",
- "jest-mock": "^29.3.1",
- "jest-regex-util": "^29.2.0",
- "jest-resolve": "^29.3.1",
- "jest-snapshot": "^29.3.1",
- "jest-util": "^29.3.1",
- "slash": "^3.0.0",
- "strip-bom": "^4.0.0"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true
- },
- "slash": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
- "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
- "dev": true
- },
- "supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "requires": {
- "has-flag": "^4.0.0"
- }
- }
- }
- },
- "jest-snapshot": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.3.1.tgz",
- "integrity": "sha512-+3JOc+s28upYLI2OJM4PWRGK9AgpsMs/ekNryUV0yMBClT9B1DF2u2qay8YxcQd338PPYSFNb0lsar1B49sLDA==",
- "dev": true,
- "requires": {
- "@babel/core": "^7.11.6",
- "@babel/generator": "^7.7.2",
- "@babel/plugin-syntax-jsx": "^7.7.2",
- "@babel/plugin-syntax-typescript": "^7.7.2",
- "@babel/traverse": "^7.7.2",
- "@babel/types": "^7.3.3",
- "@jest/expect-utils": "^29.3.1",
- "@jest/transform": "^29.3.1",
- "@jest/types": "^29.3.1",
- "@types/babel__traverse": "^7.0.6",
- "@types/prettier": "^2.1.5",
- "babel-preset-current-node-syntax": "^1.0.0",
- "chalk": "^4.0.0",
- "expect": "^29.3.1",
- "graceful-fs": "^4.2.9",
- "jest-diff": "^29.3.1",
- "jest-get-type": "^29.2.0",
- "jest-haste-map": "^29.3.1",
- "jest-matcher-utils": "^29.3.1",
- "jest-message-util": "^29.3.1",
- "jest-util": "^29.3.1",
- "natural-compare": "^1.4.0",
- "pretty-format": "^29.3.1",
- "semver": "^7.3.5"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true
- },
- "lru-cache": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
- "dev": true,
- "requires": {
- "yallist": "^4.0.0"
- }
- },
- "semver": {
- "version": "7.3.8",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
- "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
- "dev": true,
- "requires": {
- "lru-cache": "^6.0.0"
- }
- },
- "supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "requires": {
- "has-flag": "^4.0.0"
- }
- },
- "yallist": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
- "dev": true
- }
- }
- },
- "jest-util": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.3.1.tgz",
- "integrity": "sha512-7YOVZaiX7RJLv76ZfHt4nbNEzzTRiMW/IiOG7ZOKmTXmoGBxUDefgMAxQubu6WPVqP5zSzAdZG0FfLcC7HOIFQ==",
- "dev": true,
- "requires": {
- "@jest/types": "^29.3.1",
- "@types/node": "*",
- "chalk": "^4.0.0",
- "ci-info": "^3.2.0",
- "graceful-fs": "^4.2.9",
- "picomatch": "^2.2.3"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true
- },
- "supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "requires": {
- "has-flag": "^4.0.0"
- }
- }
- }
- },
- "jest-validate": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.3.1.tgz",
- "integrity": "sha512-N9Lr3oYR2Mpzuelp1F8negJR3YE+L1ebk1rYA5qYo9TTY3f9OWdptLoNSPP9itOCBIRBqjt/S5XHlzYglLN67g==",
- "dev": true,
- "requires": {
- "@jest/types": "^29.3.1",
- "camelcase": "^6.2.0",
- "chalk": "^4.0.0",
- "jest-get-type": "^29.2.0",
- "leven": "^3.1.0",
- "pretty-format": "^29.3.1"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "camelcase": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
- "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
- "dev": true
- },
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true
- },
- "supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "requires": {
- "has-flag": "^4.0.0"
- }
- }
- }
- },
- "jest-watcher": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.3.1.tgz",
- "integrity": "sha512-RspXG2BQFDsZSRKGCT/NiNa8RkQ1iKAjrO0//soTMWx/QUt+OcxMqMSBxz23PYGqUuWm2+m2mNNsmj0eIoOaFg==",
- "dev": true,
- "requires": {
- "@jest/test-result": "^29.3.1",
- "@jest/types": "^29.3.1",
- "@types/node": "*",
- "ansi-escapes": "^4.2.1",
- "chalk": "^4.0.0",
- "emittery": "^0.13.1",
- "jest-util": "^29.3.1",
- "string-length": "^4.0.1"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true
- },
- "supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "requires": {
- "has-flag": "^4.0.0"
- }
- }
- }
- },
- "jest-worker": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.3.1.tgz",
- "integrity": "sha512-lY4AnnmsEWeiXirAIA0c9SDPbuCBq8IYuDVL8PMm0MZ2PEs2yPvRA/J64QBXuZp7CYKrDM/rmNrc9/i3KJQncw==",
- "dev": true,
- "requires": {
- "@types/node": "*",
- "jest-util": "^29.3.1",
- "merge-stream": "^2.0.0",
- "supports-color": "^8.0.0"
- },
- "dependencies": {
- "has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true
- },
- "supports-color": {
- "version": "8.1.1",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
- "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
- "dev": true,
- "requires": {
- "has-flag": "^4.0.0"
- }
- }
- }
- },
- "js-tokens": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
- "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
- "dev": true
- },
- "js-yaml": {
- "version": "3.14.1",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
- "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
- "dev": true,
- "requires": {
- "argparse": "^1.0.7",
- "esprima": "^4.0.0"
- }
- },
- "jsesc": {
- "version": "2.5.2",
- "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
- "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
- "dev": true
- },
- "json-parse-even-better-errors": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
- "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
- "dev": true
- },
- "json-schema-traverse": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
- "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
- "dev": true
- },
- "json-stable-stringify-without-jsonify": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
- "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
- "dev": true
- },
- "json5": {
- "version": "2.2.3",
- "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
- "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
- "dev": true
- },
- "kind-of": {
- "version": "6.0.3",
- "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
- "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
- "dev": true
- },
- "kleur": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
- "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==",
- "dev": true
- },
- "leven": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
- "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==",
- "dev": true
- },
- "levn": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
- "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
- "dev": true,
- "requires": {
- "prelude-ls": "^1.2.1",
- "type-check": "~0.4.0"
- }
- },
- "lines-and-columns": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
- "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
- "dev": true
- },
- "loader-runner": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz",
- "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==",
- "dev": true
- },
- "loader-utils": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz",
- "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==",
- "dev": true,
- "requires": {
- "big.js": "^5.2.2",
- "emojis-list": "^3.0.0",
- "json5": "^2.1.2"
- }
- },
- "locate-path": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
- "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
- "dev": true,
- "requires": {
- "p-locate": "^4.1.0"
- }
- },
- "lodash": {
- "version": "4.17.21",
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
- "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
- "dev": true
- },
- "lodash.debounce": {
- "version": "4.0.8",
- "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
- "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==",
- "dev": true
- },
- "lodash.memoize": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
- "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==",
- "dev": true
- },
- "lodash.merge": {
- "version": "4.6.2",
- "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
- "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
- "dev": true
- },
- "lodash.truncate": {
- "version": "4.4.2",
- "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz",
- "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==",
- "dev": true
- },
- "lru-cache": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
- "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
- "dev": true,
- "requires": {
- "yallist": "^3.0.2"
- }
- },
- "make-dir": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
- "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==",
- "dev": true,
- "requires": {
- "pify": "^4.0.1",
- "semver": "^5.6.0"
- },
- "dependencies": {
- "semver": {
- "version": "5.7.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
- "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
- "dev": true
- }
- }
- },
- "make-error": {
- "version": "1.3.6",
- "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
- "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
- "dev": true
- },
- "makeerror": {
- "version": "1.0.12",
- "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz",
- "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==",
- "dev": true,
- "requires": {
- "tmpl": "1.0.5"
- }
- },
- "merge-stream": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
- "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
- "dev": true
- },
- "merge2": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
- "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
- "dev": true
- },
- "micromatch": {
- "version": "4.0.5",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
- "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
- "dev": true,
- "requires": {
- "braces": "^3.0.2",
- "picomatch": "^2.3.1"
- }
- },
- "mime-db": {
- "version": "1.52.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
- "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
- "dev": true
- },
- "mime-types": {
- "version": "2.1.35",
- "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
- "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
- "dev": true,
- "requires": {
- "mime-db": "1.52.0"
- }
- },
- "mimic-fn": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
- "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
- "dev": true
- },
- "minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
- "dev": true,
- "requires": {
- "brace-expansion": "^1.1.7"
- }
- },
- "mrmime": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz",
- "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==",
- "dev": true
- },
- "ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
- "dev": true
- },
- "natural-compare": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
- "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
- "dev": true
- },
- "natural-compare-lite": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz",
- "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==",
- "dev": true
- },
- "neo-async": {
- "version": "2.6.2",
- "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
- "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
- "dev": true
- },
- "node-fetch": {
- "version": "2.6.8",
- "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.8.tgz",
- "integrity": "sha512-RZ6dBYuj8dRSfxpUSu+NsdF1dpPpluJxwOp+6IoDp/sH2QNDSvurYsAa+F1WxY2RjA1iP93xhcsUoYbF2XBqVg==",
- "requires": {
- "whatwg-url": "^5.0.0"
- },
- "dependencies": {
- "tr46": {
- "version": "0.0.3",
- "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
- "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
- },
- "webidl-conversions": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
- "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
- },
- "whatwg-url": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
- "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
- "requires": {
- "tr46": "~0.0.3",
- "webidl-conversions": "^3.0.0"
- }
- }
- }
- },
- "node-int64": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
- "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==",
- "dev": true
- },
- "node-releases": {
- "version": "2.0.8",
- "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.8.tgz",
- "integrity": "sha512-dFSmB8fFHEH/s81Xi+Y/15DQY6VHW81nXRj86EMSL3lmuTmK1e+aT4wrFCkTbm+gSwkw4KpX+rT/pMM2c1mF+A==",
- "dev": true
- },
- "normalize-path": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
- "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
- "dev": true
- },
- "npm-run-path": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
- "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
- "dev": true,
- "requires": {
- "path-key": "^3.0.0"
- }
- },
- "once": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
- "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
- "dev": true,
- "requires": {
- "wrappy": "1"
- }
- },
- "onetime": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
- "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
- "dev": true,
- "requires": {
- "mimic-fn": "^2.1.0"
- }
- },
- "opener": {
- "version": "1.5.2",
- "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz",
- "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==",
- "dev": true
- },
- "optionator": {
- "version": "0.9.1",
- "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
- "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==",
- "dev": true,
- "requires": {
- "deep-is": "^0.1.3",
- "fast-levenshtein": "^2.0.6",
- "levn": "^0.4.1",
- "prelude-ls": "^1.2.1",
- "type-check": "^0.4.0",
- "word-wrap": "^1.2.3"
- }
- },
- "p-limit": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
- "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
- "dev": true,
- "requires": {
- "p-try": "^2.0.0"
- }
- },
- "p-locate": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
- "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
- "dev": true,
- "requires": {
- "p-limit": "^2.2.0"
- }
- },
- "p-try": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
- "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
- "dev": true
- },
- "parent-module": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
- "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
- "dev": true,
- "requires": {
- "callsites": "^3.0.0"
- }
- },
- "parse-json": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
- "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
- "dev": true,
- "requires": {
- "@babel/code-frame": "^7.0.0",
- "error-ex": "^1.3.1",
- "json-parse-even-better-errors": "^2.3.0",
- "lines-and-columns": "^1.1.6"
- }
- },
- "path-exists": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
- "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
- "dev": true
- },
- "path-is-absolute": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
- "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
- "dev": true
- },
- "path-key": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
- "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
- "dev": true
- },
- "path-parse": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
- "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
- "dev": true
- },
- "path-type": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
- "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
- "dev": true
- },
- "picocolors": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
- "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
- "dev": true
- },
- "picomatch": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
- "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
- "dev": true
- },
- "pify": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
- "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
- "dev": true
- },
- "pirates": {
- "version": "4.0.5",
- "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz",
- "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==",
- "dev": true
- },
- "pkg-dir": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz",
- "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==",
- "dev": true,
- "requires": {
- "find-up": "^3.0.0"
- },
- "dependencies": {
- "find-up": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
- "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
- "dev": true,
- "requires": {
- "locate-path": "^3.0.0"
- }
- },
- "locate-path": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
- "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
- "dev": true,
- "requires": {
- "p-locate": "^3.0.0",
- "path-exists": "^3.0.0"
- }
- },
- "p-locate": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
- "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
- "dev": true,
- "requires": {
- "p-limit": "^2.0.0"
- }
- },
- "path-exists": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
- "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==",
- "dev": true
- }
- }
- },
- "prelude-ls": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
- "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
- "dev": true
- },
- "prettier": {
- "version": "2.8.1",
- "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.1.tgz",
- "integrity": "sha512-lqGoSJBQNJidqCHE80vqZJHWHRFoNYsSpP9AjFhlhi9ODCJA541svILes/+/1GM3VaL/abZi7cpFzOpdR9UPKg==",
- "dev": true
- },
- "pretty-format": {
- "version": "29.3.1",
- "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.3.1.tgz",
- "integrity": "sha512-FyLnmb1cYJV8biEIiRyzRFvs2lry7PPIvOqKVe1GCUEYg4YGmlx1qG9EJNMxArYm7piII4qb8UV1Pncq5dxmcg==",
- "dev": true,
- "requires": {
- "@jest/schemas": "^29.0.0",
- "ansi-styles": "^5.0.0",
- "react-is": "^18.0.0"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
- "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
- "dev": true
- }
- }
- },
- "progress": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
- "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
- "dev": true
- },
- "prompts": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz",
- "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==",
- "dev": true,
- "requires": {
- "kleur": "^3.0.3",
- "sisteransi": "^1.0.5"
- }
- },
- "punycode": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
- "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
- "dev": true
- },
- "queue-microtask": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
- "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
- "dev": true
- },
- "randombytes": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
- "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
- "dev": true,
- "requires": {
- "safe-buffer": "^5.1.0"
- }
- },
- "react-is": {
- "version": "18.2.0",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
- "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==",
- "dev": true
- },
- "readdirp": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
- "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
- "dev": true,
- "optional": true,
- "requires": {
- "picomatch": "^2.2.1"
- }
- },
- "rechoir": {
- "version": "0.7.1",
- "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz",
- "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==",
- "dev": true,
- "requires": {
- "resolve": "^1.9.0"
- }
- },
- "regenerate": {
- "version": "1.4.2",
- "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
- "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==",
- "dev": true
- },
- "regenerate-unicode-properties": {
- "version": "10.1.0",
- "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz",
- "integrity": "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==",
- "dev": true,
- "requires": {
- "regenerate": "^1.4.2"
- }
- },
- "regenerator-runtime": {
- "version": "0.13.11",
- "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
- "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==",
- "dev": true
- },
- "regenerator-transform": {
- "version": "0.15.1",
- "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.1.tgz",
- "integrity": "sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.8.4"
- }
- },
- "regexpp": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
- "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==",
- "dev": true
- },
- "regexpu-core": {
- "version": "5.2.2",
- "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.2.2.tgz",
- "integrity": "sha512-T0+1Zp2wjF/juXMrMxHxidqGYn8U4R+zleSJhX9tQ1PUsS8a9UtYfbsF9LdiVgNX3kiX8RNaKM42nfSgvFJjmw==",
- "dev": true,
- "requires": {
- "regenerate": "^1.4.2",
- "regenerate-unicode-properties": "^10.1.0",
- "regjsgen": "^0.7.1",
- "regjsparser": "^0.9.1",
- "unicode-match-property-ecmascript": "^2.0.0",
- "unicode-match-property-value-ecmascript": "^2.1.0"
- }
- },
- "regjsgen": {
- "version": "0.7.1",
- "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.7.1.tgz",
- "integrity": "sha512-RAt+8H2ZEzHeYWxZ3H2z6tF18zyyOnlcdaafLrm21Bguj7uZy6ULibiAFdXEtKQY4Sy7wDTwDiOazasMLc4KPA==",
- "dev": true
- },
- "regjsparser": {
- "version": "0.9.1",
- "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz",
- "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==",
- "dev": true,
- "requires": {
- "jsesc": "~0.5.0"
- },
- "dependencies": {
- "jsesc": {
- "version": "0.5.0",
- "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz",
- "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==",
- "dev": true
- }
- }
- },
- "require-directory": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
- "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
- "dev": true
- },
- "require-from-string": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
- "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
- "dev": true
- },
- "resolve": {
- "version": "1.22.1",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
- "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
- "dev": true,
- "requires": {
- "is-core-module": "^2.9.0",
- "path-parse": "^1.0.7",
- "supports-preserve-symlinks-flag": "^1.0.0"
- }
- },
- "resolve-cwd": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz",
- "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==",
- "dev": true,
- "requires": {
- "resolve-from": "^5.0.0"
- }
- },
- "resolve-from": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
- "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
- "dev": true
- },
- "resolve.exports": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.1.tgz",
- "integrity": "sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ==",
- "dev": true
- },
- "reusify": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
- "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
- "dev": true
- },
- "rfdc": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz",
- "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA=="
- },
- "rimraf": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
- "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
- "dev": true,
- "requires": {
- "glob": "^7.1.3"
- }
- },
- "run-parallel": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
- "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
- "dev": true,
- "requires": {
- "queue-microtask": "^1.2.2"
- }
- },
- "safe-buffer": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
- "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
- "dev": true
- },
- "schema-utils": {
- "version": "2.7.1",
- "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz",
- "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==",
- "dev": true,
- "requires": {
- "@types/json-schema": "^7.0.5",
- "ajv": "^6.12.4",
- "ajv-keywords": "^3.5.2"
- }
- },
- "semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
- "dev": true
- },
- "serialize-javascript": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz",
- "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==",
- "dev": true,
- "requires": {
- "randombytes": "^2.1.0"
- }
- },
- "shallow-clone": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz",
- "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==",
- "dev": true,
- "requires": {
- "kind-of": "^6.0.2"
- }
- },
- "shebang-command": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
- "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
- "dev": true,
- "requires": {
- "shebang-regex": "^3.0.0"
- }
- },
- "shebang-regex": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
- "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
- "dev": true
- },
- "signal-exit": {
- "version": "3.0.7",
- "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
- "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
- "dev": true
- },
- "sirv": {
- "version": "1.0.19",
- "resolved": "https://registry.npmjs.org/sirv/-/sirv-1.0.19.tgz",
- "integrity": "sha512-JuLThK3TnZG1TAKDwNIqNq6QA2afLOCcm+iE8D1Kj3GA40pSPsxQjjJl0J8X3tsR7T+CP1GavpzLwYkgVLWrZQ==",
- "dev": true,
- "requires": {
- "@polka/url": "^1.0.0-next.20",
- "mrmime": "^1.0.0",
- "totalist": "^1.0.0"
- }
- },
- "sisteransi": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
- "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==",
- "dev": true
- },
- "slash": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz",
- "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==",
- "dev": true
- },
- "slice-ansi": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz",
- "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.0.0",
- "astral-regex": "^2.0.0",
- "is-fullwidth-code-point": "^3.0.0"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- }
- }
- },
- "source-map": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
- "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
- "dev": true
- },
- "source-map-support": {
- "version": "0.5.21",
- "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
- "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
- "dev": true,
- "requires": {
- "buffer-from": "^1.0.0",
- "source-map": "^0.6.0"
- }
- },
- "sprintf-js": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
- "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
- "dev": true
- },
- "stack-utils": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz",
- "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==",
- "dev": true,
- "requires": {
- "escape-string-regexp": "^2.0.0"
- },
- "dependencies": {
- "escape-string-regexp": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz",
- "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==",
- "dev": true
- }
- }
- },
- "string-length": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz",
- "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==",
- "dev": true,
- "requires": {
- "char-regex": "^1.0.2",
- "strip-ansi": "^6.0.0"
- }
- },
- "string-width": {
- "version": "4.2.3",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
- "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
- "dev": true,
- "requires": {
- "emoji-regex": "^8.0.0",
- "is-fullwidth-code-point": "^3.0.0",
- "strip-ansi": "^6.0.1"
- }
- },
- "strip-ansi": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
- "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "dev": true,
- "requires": {
- "ansi-regex": "^5.0.1"
- }
- },
- "strip-bom": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz",
- "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==",
- "dev": true
- },
- "strip-final-newline": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
- "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
- "dev": true
- },
- "strip-json-comments": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
- "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
- "dev": true
- },
- "supports-color": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
- "dev": true,
- "requires": {
- "has-flag": "^3.0.0"
- }
- },
- "supports-preserve-symlinks-flag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
- "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
- "dev": true
- },
- "table": {
- "version": "6.8.1",
- "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz",
- "integrity": "sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==",
- "dev": true,
- "requires": {
- "ajv": "^8.0.1",
- "lodash.truncate": "^4.4.2",
- "slice-ansi": "^4.0.0",
- "string-width": "^4.2.3",
- "strip-ansi": "^6.0.1"
- },
- "dependencies": {
- "ajv": {
- "version": "8.12.0",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
- "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
- "dev": true,
- "requires": {
- "fast-deep-equal": "^3.1.1",
- "json-schema-traverse": "^1.0.0",
- "require-from-string": "^2.0.2",
- "uri-js": "^4.2.2"
- }
- },
- "json-schema-traverse": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
- "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
- "dev": true
- }
- }
- },
- "tapable": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
- "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==",
- "dev": true
- },
- "terser": {
- "version": "5.16.1",
- "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.1.tgz",
- "integrity": "sha512-xvQfyfA1ayT0qdK47zskQgRZeWLoOQ8JQ6mIgRGVNwZKdQMU+5FkCBjmv4QjcrTzyZquRw2FVtlJSRUmMKQslw==",
- "dev": true,
- "requires": {
- "@jridgewell/source-map": "^0.3.2",
- "acorn": "^8.5.0",
- "commander": "^2.20.0",
- "source-map-support": "~0.5.20"
- },
- "dependencies": {
- "commander": {
- "version": "2.20.3",
- "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
- "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
- "dev": true
- }
- }
- },
- "terser-webpack-plugin": {
- "version": "5.3.6",
- "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.6.tgz",
- "integrity": "sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ==",
- "dev": true,
- "requires": {
- "@jridgewell/trace-mapping": "^0.3.14",
- "jest-worker": "^27.4.5",
- "schema-utils": "^3.1.1",
- "serialize-javascript": "^6.0.0",
- "terser": "^5.14.1"
- },
- "dependencies": {
- "has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true
- },
- "jest-worker": {
- "version": "27.5.1",
- "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz",
- "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==",
- "dev": true,
- "requires": {
- "@types/node": "*",
- "merge-stream": "^2.0.0",
- "supports-color": "^8.0.0"
- }
- },
- "schema-utils": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz",
- "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==",
- "dev": true,
- "requires": {
- "@types/json-schema": "^7.0.8",
- "ajv": "^6.12.5",
- "ajv-keywords": "^3.5.2"
- }
- },
- "supports-color": {
- "version": "8.1.1",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
- "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
- "dev": true,
- "requires": {
- "has-flag": "^4.0.0"
- }
- }
- }
- },
- "test-exclude": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz",
- "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==",
- "dev": true,
- "requires": {
- "@istanbuljs/schema": "^0.1.2",
- "glob": "^7.1.4",
- "minimatch": "^3.0.4"
- }
- },
- "text-table": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
- "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
- "dev": true
- },
- "tmpl": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz",
- "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==",
- "dev": true
- },
- "to-fast-properties": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
- "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==",
- "dev": true
- },
- "to-regex-range": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
- "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
- "dev": true,
- "requires": {
- "is-number": "^7.0.0"
- }
- },
- "totalist": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/totalist/-/totalist-1.1.0.tgz",
- "integrity": "sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==",
- "dev": true
- },
- "ts-jest": {
- "version": "29.0.5",
- "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.5.tgz",
- "integrity": "sha512-PL3UciSgIpQ7f6XjVOmbi96vmDHUqAyqDr8YxzopDqX3kfgYtX1cuNeBjP+L9sFXi6nzsGGA6R3fP3DDDJyrxA==",
- "dev": true,
- "requires": {
- "bs-logger": "0.x",
- "fast-json-stable-stringify": "2.x",
- "jest-util": "^29.0.0",
- "json5": "^2.2.3",
- "lodash.memoize": "4.x",
- "make-error": "1.x",
- "semver": "7.x",
- "yargs-parser": "^21.0.1"
- },
- "dependencies": {
- "lru-cache": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
- "dev": true,
- "requires": {
- "yallist": "^4.0.0"
- }
- },
- "semver": {
- "version": "7.3.8",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
- "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
- "dev": true,
- "requires": {
- "lru-cache": "^6.0.0"
- }
- },
- "yallist": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
- "dev": true
- }
- }
- },
- "ts-loader": {
- "version": "9.4.2",
- "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.4.2.tgz",
- "integrity": "sha512-OmlC4WVmFv5I0PpaxYb+qGeGOdm5giHU7HwDDUjw59emP2UYMHy9fFSDcYgSNoH8sXcj4hGCSEhlDZ9ULeDraA==",
- "dev": true,
- "requires": {
- "chalk": "^4.1.0",
- "enhanced-resolve": "^5.0.0",
- "micromatch": "^4.0.0",
- "semver": "^7.3.4"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true
- },
- "lru-cache": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
- "dev": true,
- "requires": {
- "yallist": "^4.0.0"
- }
- },
- "semver": {
- "version": "7.3.8",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
- "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
- "dev": true,
- "requires": {
- "lru-cache": "^6.0.0"
- }
- },
- "supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "requires": {
- "has-flag": "^4.0.0"
- }
- },
- "yallist": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
- "dev": true
- }
- }
- },
- "tslib": {
- "version": "1.14.1",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
- "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
- "dev": true
- },
- "tsutils": {
- "version": "3.21.0",
- "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
- "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
- "dev": true,
- "requires": {
- "tslib": "^1.8.1"
- }
- },
- "type-check": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
- "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
- "dev": true,
- "requires": {
- "prelude-ls": "^1.2.1"
- }
- },
- "type-detect": {
- "version": "4.0.8",
- "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
- "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
- "dev": true
- },
- "type-fest": {
- "version": "0.21.3",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz",
- "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==",
- "dev": true
- },
- "typescript": {
- "version": "4.9.4",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz",
- "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==",
- "dev": true
- },
- "unicode-canonical-property-names-ecmascript": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz",
- "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==",
- "dev": true
- },
- "unicode-match-property-ecmascript": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz",
- "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==",
- "dev": true,
- "requires": {
- "unicode-canonical-property-names-ecmascript": "^2.0.0",
- "unicode-property-aliases-ecmascript": "^2.0.0"
- }
- },
- "unicode-match-property-value-ecmascript": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz",
- "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==",
- "dev": true
- },
- "unicode-property-aliases-ecmascript": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz",
- "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==",
- "dev": true
- },
- "update-browserslist-db": {
- "version": "1.0.10",
- "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz",
- "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==",
- "dev": true,
- "requires": {
- "escalade": "^3.1.1",
- "picocolors": "^1.0.0"
- }
- },
- "uri-js": {
- "version": "4.4.1",
- "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
- "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
- "dev": true,
- "requires": {
- "punycode": "^2.1.0"
- }
- },
- "v8-compile-cache": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz",
- "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==",
- "dev": true
- },
- "v8-to-istanbul": {
- "version": "9.0.1",
- "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz",
- "integrity": "sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==",
- "dev": true,
- "requires": {
- "@jridgewell/trace-mapping": "^0.3.12",
- "@types/istanbul-lib-coverage": "^2.0.1",
- "convert-source-map": "^1.6.0"
- }
- },
- "walker": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz",
- "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==",
- "dev": true,
- "requires": {
- "makeerror": "1.0.12"
- }
- },
- "watchpack": {
- "version": "2.4.0",
- "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz",
- "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==",
- "dev": true,
- "requires": {
- "glob-to-regexp": "^0.4.1",
- "graceful-fs": "^4.1.2"
- }
- },
- "webpack": {
- "version": "5.76.0",
- "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.0.tgz",
- "integrity": "sha512-l5sOdYBDunyf72HW8dF23rFtWq/7Zgvt/9ftMof71E/yUb1YLOBmTgA2K4vQthB3kotMrSj609txVE0dnr2fjA==",
- "dev": true,
- "requires": {
- "@types/eslint-scope": "^3.7.3",
- "@types/estree": "^0.0.51",
- "@webassemblyjs/ast": "1.11.1",
- "@webassemblyjs/wasm-edit": "1.11.1",
- "@webassemblyjs/wasm-parser": "1.11.1",
- "acorn": "^8.7.1",
- "acorn-import-assertions": "^1.7.6",
- "browserslist": "^4.14.5",
- "chrome-trace-event": "^1.0.2",
- "enhanced-resolve": "^5.10.0",
- "es-module-lexer": "^0.9.0",
- "eslint-scope": "5.1.1",
- "events": "^3.2.0",
- "glob-to-regexp": "^0.4.1",
- "graceful-fs": "^4.2.9",
- "json-parse-even-better-errors": "^2.3.1",
- "loader-runner": "^4.2.0",
- "mime-types": "^2.1.27",
- "neo-async": "^2.6.2",
- "schema-utils": "^3.1.0",
- "tapable": "^2.1.1",
- "terser-webpack-plugin": "^5.1.3",
- "watchpack": "^2.4.0",
- "webpack-sources": "^3.2.3"
- },
- "dependencies": {
- "acorn-import-assertions": {
- "version": "1.8.0",
- "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz",
- "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==",
- "dev": true,
- "requires": {}
- },
- "schema-utils": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz",
- "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==",
- "dev": true,
- "requires": {
- "@types/json-schema": "^7.0.8",
- "ajv": "^6.12.5",
- "ajv-keywords": "^3.5.2"
- }
- }
- }
- },
- "webpack-bundle-analyzer": {
- "version": "4.7.0",
- "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.7.0.tgz",
- "integrity": "sha512-j9b8ynpJS4K+zfO5GGwsAcQX4ZHpWV+yRiHDiL+bE0XHJ8NiPYLTNVQdlFYWxtpg9lfAQNlwJg16J9AJtFSXRg==",
- "dev": true,
- "requires": {
- "acorn": "^8.0.4",
- "acorn-walk": "^8.0.0",
- "chalk": "^4.1.0",
- "commander": "^7.2.0",
- "gzip-size": "^6.0.0",
- "lodash": "^4.17.20",
- "opener": "^1.5.2",
- "sirv": "^1.0.7",
- "ws": "^7.3.1"
- },
- "dependencies": {
- "acorn-walk": {
- "version": "8.2.0",
- "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
- "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
- "dev": true
- },
- "ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "commander": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
- "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
- "dev": true
- },
- "has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true
- },
- "supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "requires": {
- "has-flag": "^4.0.0"
- }
- }
- }
- },
- "webpack-cli": {
- "version": "4.10.0",
- "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.10.0.tgz",
- "integrity": "sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w==",
- "dev": true,
- "requires": {
- "@discoveryjs/json-ext": "^0.5.0",
- "@webpack-cli/configtest": "^1.2.0",
- "@webpack-cli/info": "^1.5.0",
- "@webpack-cli/serve": "^1.7.0",
- "colorette": "^2.0.14",
- "commander": "^7.0.0",
- "cross-spawn": "^7.0.3",
- "fastest-levenshtein": "^1.0.12",
- "import-local": "^3.0.2",
- "interpret": "^2.2.0",
- "rechoir": "^0.7.0",
- "webpack-merge": "^5.7.3"
- },
- "dependencies": {
- "commander": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
- "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
- "dev": true
- }
- }
- },
- "webpack-merge": {
- "version": "5.8.0",
- "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz",
- "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==",
- "dev": true,
- "requires": {
- "clone-deep": "^4.0.1",
- "wildcard": "^2.0.0"
- }
- },
- "webpack-sources": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz",
- "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==",
- "dev": true
- },
- "which": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
- "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
- "dev": true,
- "requires": {
- "isexe": "^2.0.0"
- }
- },
- "wildcard": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz",
- "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==",
- "dev": true
- },
- "word-wrap": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
- "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
- "dev": true
- },
- "wrap-ansi": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
- "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.0.0",
- "string-width": "^4.1.0",
- "strip-ansi": "^6.0.0"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- }
- }
- },
- "wrappy": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
- "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
- "dev": true
- },
- "write-file-atomic": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz",
- "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==",
- "dev": true,
- "requires": {
- "imurmurhash": "^0.1.4",
- "signal-exit": "^3.0.7"
- }
- },
- "ws": {
- "version": "7.5.9",
- "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz",
- "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
- "dev": true,
- "requires": {}
- },
- "y18n": {
- "version": "5.0.8",
- "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
- "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
- "dev": true
- },
- "yallist": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
- "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
- "dev": true
- },
- "yargs": {
- "version": "17.6.2",
- "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz",
- "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==",
- "dev": true,
- "requires": {
- "cliui": "^8.0.1",
- "escalade": "^3.1.1",
- "get-caller-file": "^2.0.5",
- "require-directory": "^2.1.1",
- "string-width": "^4.2.3",
- "y18n": "^5.0.5",
- "yargs-parser": "^21.1.1"
- }
- },
- "yargs-parser": {
- "version": "21.1.1",
- "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
- "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
- "dev": true
- },
- "yocto-queue": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
- "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
- "dev": true
- }
- }
+ "name": "@absmartly/javascript-sdk",
+ "version": "2.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "@absmartly/javascript-sdk",
+ "version": "2.0.0",
+ "license": "Apache-2.0",
+ "devDependencies": {
+ "@vitest/coverage-v8": "^3.0.0",
+ "tsup": "^8.0.0",
+ "tsx": "^4.0.0",
+ "typescript": "^5.4.0",
+ "vitest": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@ampproject/remapping": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
+ "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/helper-string-parser": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
+ "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-identifier": {
+ "version": "7.28.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz",
+ "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/parser": {
+ "version": "7.29.2",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz",
+ "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.29.0"
+ },
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/types": {
+ "version": "7.29.0",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz",
+ "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-string-parser": "^7.27.1",
+ "@babel/helper-validator-identifier": "^7.28.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@bcoe/v8-coverage": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz",
+ "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/aix-ppc64": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.4.tgz",
+ "integrity": "sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "aix"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.4.tgz",
+ "integrity": "sha512-X9bUgvxiC8CHAGKYufLIHGXPJWnr0OCdR0anD2e21vdvgCI8lIfqFbnoeOz7lBjdrAGUhqLZLcQo6MLhTO2DKQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm64": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.4.tgz",
+ "integrity": "sha512-gdLscB7v75wRfu7QSm/zg6Rx29VLdy9eTr2t44sfTW7CxwAtQghZ4ZnqHk3/ogz7xao0QAgrkradbBzcqFPasw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-x64": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.4.tgz",
+ "integrity": "sha512-PzPFnBNVF292sfpfhiyiXCGSn9HZg5BcAz+ivBuSsl6Rk4ga1oEXAamhOXRFyMcjwr2DVtm40G65N3GLeH1Lvw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-arm64": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.4.tgz",
+ "integrity": "sha512-b7xaGIwdJlht8ZFCvMkpDN6uiSmnxxK56N2GDTMYPr2/gzvfdQN8rTfBsvVKmIVY/X7EM+/hJKEIbbHs9oA4tQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-x64": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.4.tgz",
+ "integrity": "sha512-sR+OiKLwd15nmCdqpXMnuJ9W2kpy0KigzqScqHI3Hqwr7IXxBp3Yva+yJwoqh7rE8V77tdoheRYataNKL4QrPw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.4.tgz",
+ "integrity": "sha512-jnfpKe+p79tCnm4GVav68A7tUFeKQwQyLgESwEAUzyxk/TJr4QdGog9sqWNcUbr/bZt/O/HXouspuQDd9JxFSw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-x64": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.4.tgz",
+ "integrity": "sha512-2kb4ceA/CpfUrIcTUl1wrP/9ad9Atrp5J94Lq69w7UwOMolPIGrfLSvAKJp0RTvkPPyn6CIWrNy13kyLikZRZQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.4.tgz",
+ "integrity": "sha512-aBYgcIxX/wd5n2ys0yESGeYMGF+pv6g0DhZr3G1ZG4jMfruU9Tl1i2Z+Wnj9/KjGz1lTLCcorqE2viePZqj4Eg==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm64": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.4.tgz",
+ "integrity": "sha512-7nQOttdzVGth1iz57kxg9uCz57dxQLHWxopL6mYuYthohPKEK0vU0C3O21CcBK6KDlkYVcnDXY099HcCDXd9dA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ia32": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.4.tgz",
+ "integrity": "sha512-oPtixtAIzgvzYcKBQM/qZ3R+9TEUd1aNJQu0HhGyqtx6oS7qTpvjheIWBbes4+qu1bNlo2V4cbkISr8q6gRBFA==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-loong64": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.4.tgz",
+ "integrity": "sha512-8mL/vh8qeCoRcFH2nM8wm5uJP+ZcVYGGayMavi8GmRJjuI3g1v6Z7Ni0JJKAJW+m0EtUuARb6Lmp4hMjzCBWzA==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-mips64el": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.4.tgz",
+ "integrity": "sha512-1RdrWFFiiLIW7LQq9Q2NES+HiD4NyT8Itj9AUeCl0IVCA459WnPhREKgwrpaIfTOe+/2rdntisegiPWn/r/aAw==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ppc64": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.4.tgz",
+ "integrity": "sha512-tLCwNG47l3sd9lpfyx9LAGEGItCUeRCWeAx6x2Jmbav65nAwoPXfewtAdtbtit/pJFLUWOhpv0FpS6GQAmPrHA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-riscv64": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.4.tgz",
+ "integrity": "sha512-BnASypppbUWyqjd1KIpU4AUBiIhVr6YlHx/cnPgqEkNoVOhHg+YiSVxM1RLfiy4t9cAulbRGTNCKOcqHrEQLIw==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-s390x": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.4.tgz",
+ "integrity": "sha512-+eUqgb/Z7vxVLezG8bVB9SfBie89gMueS+I0xYh2tJdw3vqA/0ImZJ2ROeWwVJN59ihBeZ7Tu92dF/5dy5FttA==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-x64": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.4.tgz",
+ "integrity": "sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-arm64": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.4.tgz",
+ "integrity": "sha512-xHT8X4sb0GS8qTqiwzHqpY00C95DPAq7nAwX35Ie/s+LO9830hrMd3oX0ZMKLvy7vsonee73x0lmcdOVXFzd6Q==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-x64": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.4.tgz",
+ "integrity": "sha512-RugOvOdXfdyi5Tyv40kgQnI0byv66BFgAqjdgtAKqHoZTbTF2QqfQrFwa7cHEORJf6X2ht+l9ABLMP0dnKYsgg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-arm64": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.4.tgz",
+ "integrity": "sha512-2MyL3IAaTX+1/qP0O1SwskwcwCoOI4kV2IBX1xYnDDqthmq5ArrW94qSIKCAuRraMgPOmG0RDTA74mzYNQA9ow==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-x64": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.4.tgz",
+ "integrity": "sha512-u8fg/jQ5aQDfsnIV6+KwLOf1CmJnfu1ShpwqdwC0uA7ZPwFws55Ngc12vBdeUdnuWoQYx/SOQLGDcdlfXhYmXQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openharmony-arm64": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.4.tgz",
+ "integrity": "sha512-JkTZrl6VbyO8lDQO3yv26nNr2RM2yZzNrNHEsj9bm6dOwwu9OYN28CjzZkH57bh4w0I2F7IodpQvUAEd1mbWXg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openharmony"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/sunos-x64": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.4.tgz",
+ "integrity": "sha512-/gOzgaewZJfeJTlsWhvUEmUG4tWEY2Spp5M20INYRg2ZKl9QPO3QEEgPeRtLjEWSW8FilRNacPOg8R1uaYkA6g==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-arm64": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.4.tgz",
+ "integrity": "sha512-Z9SExBg2y32smoDQdf1HRwHRt6vAHLXcxD2uGgO/v2jK7Y718Ix4ndsbNMU/+1Qiem9OiOdaqitioZwxivhXYg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-ia32": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.4.tgz",
+ "integrity": "sha512-DAyGLS0Jz5G5iixEbMHi5KdiApqHBWMGzTtMiJ72ZOLhbu/bzxgAe8Ue8CTS3n3HbIUHQz/L51yMdGMeoxXNJw==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-x64": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.4.tgz",
+ "integrity": "sha512-+knoa0BDoeXgkNvvV1vvbZX4+hizelrkwmGJBdT17t8FNPwG2lKemmuMZlmaNQ3ws3DKKCxpb4zRZEIp3UxFCg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@isaacs/cliui": {
+ "version": "8.0.2",
+ "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
+ "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "string-width": "^5.1.2",
+ "string-width-cjs": "npm:string-width@^4.2.0",
+ "strip-ansi": "^7.0.1",
+ "strip-ansi-cjs": "npm:strip-ansi@^6.0.1",
+ "wrap-ansi": "^8.1.0",
+ "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@istanbuljs/schema": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz",
+ "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@jridgewell/gen-mapping": {
+ "version": "0.3.13",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
+ "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.5.0",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ }
+ },
+ "node_modules/@jridgewell/resolve-uri": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+ "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.5.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
+ "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.31",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
+ "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.1.0",
+ "@jridgewell/sourcemap-codec": "^1.4.14"
+ }
+ },
+ "node_modules/@pkgjs/parseargs": {
+ "version": "0.11.0",
+ "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
+ "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">=14"
+ }
+ },
+ "node_modules/@rollup/rollup-android-arm-eabi": {
+ "version": "4.60.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.0.tgz",
+ "integrity": "sha512-WOhNW9K8bR3kf4zLxbfg6Pxu2ybOUbB2AjMDHSQx86LIF4rH4Ft7vmMwNt0loO0eonglSNy4cpD3MKXXKQu0/A==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-android-arm64": {
+ "version": "4.60.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.0.tgz",
+ "integrity": "sha512-u6JHLll5QKRvjciE78bQXDmqRqNs5M/3GVqZeMwvmjaNODJih/WIrJlFVEihvV0MiYFmd+ZyPr9wxOVbPAG2Iw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-arm64": {
+ "version": "4.60.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.0.tgz",
+ "integrity": "sha512-qEF7CsKKzSRc20Ciu2Zw1wRrBz4g56F7r/vRwY430UPp/nt1x21Q/fpJ9N5l47WWvJlkNCPJz3QRVw008fi7yA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-x64": {
+ "version": "4.60.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.0.tgz",
+ "integrity": "sha512-WADYozJ4QCnXCH4wPB+3FuGmDPoFseVCUrANmA5LWwGmC6FL14BWC7pcq+FstOZv3baGX65tZ378uT6WG8ynTw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-freebsd-arm64": {
+ "version": "4.60.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.0.tgz",
+ "integrity": "sha512-6b8wGHJlDrGeSE3aH5mGNHBjA0TTkxdoNHik5EkvPHCt351XnigA4pS7Wsj/Eo9Y8RBU6f35cjN9SYmCFBtzxw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-freebsd-x64": {
+ "version": "4.60.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.0.tgz",
+ "integrity": "sha512-h25Ga0t4jaylMB8M/JKAyrvvfxGRjnPQIR8lnCayyzEjEOx2EJIlIiMbhpWxDRKGKF8jbNH01NnN663dH638mA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
+ "version": "4.60.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.0.tgz",
+ "integrity": "sha512-RzeBwv0B3qtVBWtcuABtSuCzToo2IEAIQrcyB/b2zMvBWVbjo8bZDjACUpnaafaxhTw2W+imQbP2BD1usasK4g==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-musleabihf": {
+ "version": "4.60.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.0.tgz",
+ "integrity": "sha512-Sf7zusNI2CIU1HLzuu9Tc5YGAHEZs5Lu7N1ssJG4Tkw6e0MEsN7NdjUDDfGNHy2IU+ENyWT+L2obgWiguWibWQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-gnu": {
+ "version": "4.60.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.0.tgz",
+ "integrity": "sha512-DX2x7CMcrJzsE91q7/O02IJQ5/aLkVtYFryqCjduJhUfGKG6yJV8hxaw8pZa93lLEpPTP/ohdN4wFz7yp/ry9A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-musl": {
+ "version": "4.60.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.0.tgz",
+ "integrity": "sha512-09EL+yFVbJZlhcQfShpswwRZ0Rg+z/CsSELFCnPt3iK+iqwGsI4zht3secj5vLEs957QvFFXnzAT0FFPIxSrkQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-loong64-gnu": {
+ "version": "4.60.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.0.tgz",
+ "integrity": "sha512-i9IcCMPr3EXm8EQg5jnja0Zyc1iFxJjZWlb4wr7U2Wx/GrddOuEafxRdMPRYVaXjgbhvqalp6np07hN1w9kAKw==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-loong64-musl": {
+ "version": "4.60.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.0.tgz",
+ "integrity": "sha512-DGzdJK9kyJ+B78MCkWeGnpXJ91tK/iKA6HwHxF4TAlPIY7GXEvMe8hBFRgdrR9Ly4qebR/7gfUs9y2IoaVEyog==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-ppc64-gnu": {
+ "version": "4.60.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.0.tgz",
+ "integrity": "sha512-RwpnLsqC8qbS8z1H1AxBA1H6qknR4YpPR9w2XX0vo2Sz10miu57PkNcnHVaZkbqyw/kUWfKMI73jhmfi9BRMUQ==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-ppc64-musl": {
+ "version": "4.60.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.0.tgz",
+ "integrity": "sha512-Z8pPf54Ly3aqtdWC3G4rFigZgNvd+qJlOE52fmko3KST9SoGfAdSRCwyoyG05q1HrrAblLbk1/PSIV+80/pxLg==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-riscv64-gnu": {
+ "version": "4.60.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.0.tgz",
+ "integrity": "sha512-3a3qQustp3COCGvnP4SvrMHnPQ9d1vzCakQVRTliaz8cIp/wULGjiGpbcqrkv0WrHTEp8bQD/B3HBjzujVWLOA==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-riscv64-musl": {
+ "version": "4.60.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.0.tgz",
+ "integrity": "sha512-pjZDsVH/1VsghMJ2/kAaxt6dL0psT6ZexQVrijczOf+PeP2BUqTHYejk3l6TlPRydggINOeNRhvpLa0AYpCWSQ==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-s390x-gnu": {
+ "version": "4.60.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.0.tgz",
+ "integrity": "sha512-3ObQs0BhvPgiUVZrN7gqCSvmFuMWvWvsjG5ayJ3Lraqv+2KhOsp+pUbigqbeWqueGIsnn+09HBw27rJ+gYK4VQ==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-gnu": {
+ "version": "4.60.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.0.tgz",
+ "integrity": "sha512-EtylprDtQPdS5rXvAayrNDYoJhIz1/vzN2fEubo3yLE7tfAw+948dO0g4M0vkTVFhKojnF+n6C8bDNe+gDRdTg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-musl": {
+ "version": "4.60.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.0.tgz",
+ "integrity": "sha512-k09oiRCi/bHU9UVFqD17r3eJR9bn03TyKraCrlz5ULFJGdJGi7VOmm9jl44vOJvRJ6P7WuBi/s2A97LxxHGIdw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-openbsd-x64": {
+ "version": "4.60.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.0.tgz",
+ "integrity": "sha512-1o/0/pIhozoSaDJoDcec+IVLbnRtQmHwPV730+AOD29lHEEo4F5BEUB24H0OBdhbBBDwIOSuf7vgg0Ywxdfiiw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-openharmony-arm64": {
+ "version": "4.60.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.0.tgz",
+ "integrity": "sha512-pESDkos/PDzYwtyzB5p/UoNU/8fJo68vcXM9ZW2V0kjYayj1KaaUfi1NmTUTUpMn4UhU4gTuK8gIaFO4UGuMbA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openharmony"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-arm64-msvc": {
+ "version": "4.60.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.0.tgz",
+ "integrity": "sha512-hj1wFStD7B1YBeYmvY+lWXZ7ey73YGPcViMShYikqKT1GtstIKQAtfUI6yrzPjAy/O7pO0VLXGmUVWXQMaYgTQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-ia32-msvc": {
+ "version": "4.60.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.0.tgz",
+ "integrity": "sha512-SyaIPFoxmUPlNDq5EHkTbiKzmSEmq/gOYFI/3HHJ8iS/v1mbugVa7dXUzcJGQfoytp9DJFLhHH4U3/eTy2Bq4w==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-x64-gnu": {
+ "version": "4.60.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.0.tgz",
+ "integrity": "sha512-RdcryEfzZr+lAr5kRm2ucN9aVlCCa2QNq4hXelZxb8GG0NJSazq44Z3PCCc8wISRuCVnGs0lQJVX5Vp6fKA+IA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-x64-msvc": {
+ "version": "4.60.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.0.tgz",
+ "integrity": "sha512-PrsWNQ8BuE00O3Xsx3ALh2Df8fAj9+cvvX9AIA6o4KpATR98c9mud4XtDWVvsEuyia5U4tVSTKygawyJkjm60w==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@types/chai": {
+ "version": "5.2.3",
+ "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz",
+ "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/deep-eql": "*",
+ "assertion-error": "^2.0.1"
+ }
+ },
+ "node_modules/@types/deep-eql": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz",
+ "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/estree": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
+ "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@vitest/coverage-v8": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-3.2.4.tgz",
+ "integrity": "sha512-EyF9SXU6kS5Ku/U82E259WSnvg6c8KTjppUncuNdm5QHpe17mwREHnjDzozC8x9MZ0xfBUFSaLkRv4TMA75ALQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@ampproject/remapping": "^2.3.0",
+ "@bcoe/v8-coverage": "^1.0.2",
+ "ast-v8-to-istanbul": "^0.3.3",
+ "debug": "^4.4.1",
+ "istanbul-lib-coverage": "^3.2.2",
+ "istanbul-lib-report": "^3.0.1",
+ "istanbul-lib-source-maps": "^5.0.6",
+ "istanbul-reports": "^3.1.7",
+ "magic-string": "^0.30.17",
+ "magicast": "^0.3.5",
+ "std-env": "^3.9.0",
+ "test-exclude": "^7.0.1",
+ "tinyrainbow": "^2.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ },
+ "peerDependencies": {
+ "@vitest/browser": "3.2.4",
+ "vitest": "3.2.4"
+ },
+ "peerDependenciesMeta": {
+ "@vitest/browser": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@vitest/expect": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.4.tgz",
+ "integrity": "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/chai": "^5.2.2",
+ "@vitest/spy": "3.2.4",
+ "@vitest/utils": "3.2.4",
+ "chai": "^5.2.0",
+ "tinyrainbow": "^2.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/@vitest/mocker": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.4.tgz",
+ "integrity": "sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/spy": "3.2.4",
+ "estree-walker": "^3.0.3",
+ "magic-string": "^0.30.17"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ },
+ "peerDependencies": {
+ "msw": "^2.4.9",
+ "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0"
+ },
+ "peerDependenciesMeta": {
+ "msw": {
+ "optional": true
+ },
+ "vite": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@vitest/pretty-format": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.4.tgz",
+ "integrity": "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "tinyrainbow": "^2.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/@vitest/runner": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.4.tgz",
+ "integrity": "sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/utils": "3.2.4",
+ "pathe": "^2.0.3",
+ "strip-literal": "^3.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/@vitest/snapshot": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.4.tgz",
+ "integrity": "sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/pretty-format": "3.2.4",
+ "magic-string": "^0.30.17",
+ "pathe": "^2.0.3"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/@vitest/spy": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.4.tgz",
+ "integrity": "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "tinyspy": "^4.0.3"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/@vitest/utils": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.4.tgz",
+ "integrity": "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/pretty-format": "3.2.4",
+ "loupe": "^3.1.4",
+ "tinyrainbow": "^2.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/acorn": {
+ "version": "8.16.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
+ "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/ansi-regex": {
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz",
+ "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+ }
+ },
+ "node_modules/ansi-styles": {
+ "version": "6.2.3",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz",
+ "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/any-promise": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
+ "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/assertion-error": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz",
+ "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/ast-v8-to-istanbul": {
+ "version": "0.3.12",
+ "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-0.3.12.tgz",
+ "integrity": "sha512-BRRC8VRZY2R4Z4lFIL35MwNXmwVqBityvOIwETtsCSwvjl0IdgFsy9NhdaA6j74nUdtJJlIypeRhpDam19Wq3g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/trace-mapping": "^0.3.31",
+ "estree-walker": "^3.0.3",
+ "js-tokens": "^10.0.0"
+ }
+ },
+ "node_modules/balanced-match": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
+ "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "18 || 20 || >=22"
+ }
+ },
+ "node_modules/brace-expansion": {
+ "version": "5.0.5",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz",
+ "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^4.0.2"
+ },
+ "engines": {
+ "node": "18 || 20 || >=22"
+ }
+ },
+ "node_modules/bundle-require": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/bundle-require/-/bundle-require-5.1.0.tgz",
+ "integrity": "sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "load-tsconfig": "^0.2.3"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "peerDependencies": {
+ "esbuild": ">=0.18"
+ }
+ },
+ "node_modules/cac": {
+ "version": "6.7.14",
+ "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz",
+ "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/chai": {
+ "version": "5.3.3",
+ "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz",
+ "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "assertion-error": "^2.0.1",
+ "check-error": "^2.1.1",
+ "deep-eql": "^5.0.1",
+ "loupe": "^3.1.0",
+ "pathval": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/check-error": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.3.tgz",
+ "integrity": "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 16"
+ }
+ },
+ "node_modules/chokidar": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
+ "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "readdirp": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 14.16.0"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
+ "node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/commander": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
+ "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/confbox": {
+ "version": "0.1.8",
+ "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz",
+ "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/consola": {
+ "version": "3.4.2",
+ "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz",
+ "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^14.18.0 || >=16.10.0"
+ }
+ },
+ "node_modules/cross-spawn": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+ "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/debug": {
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/deep-eql": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz",
+ "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/eastasianwidth": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
+ "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/emoji-regex": {
+ "version": "9.2.2",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
+ "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/es-module-lexer": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz",
+ "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/esbuild": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.4.tgz",
+ "integrity": "sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "optionalDependencies": {
+ "@esbuild/aix-ppc64": "0.27.4",
+ "@esbuild/android-arm": "0.27.4",
+ "@esbuild/android-arm64": "0.27.4",
+ "@esbuild/android-x64": "0.27.4",
+ "@esbuild/darwin-arm64": "0.27.4",
+ "@esbuild/darwin-x64": "0.27.4",
+ "@esbuild/freebsd-arm64": "0.27.4",
+ "@esbuild/freebsd-x64": "0.27.4",
+ "@esbuild/linux-arm": "0.27.4",
+ "@esbuild/linux-arm64": "0.27.4",
+ "@esbuild/linux-ia32": "0.27.4",
+ "@esbuild/linux-loong64": "0.27.4",
+ "@esbuild/linux-mips64el": "0.27.4",
+ "@esbuild/linux-ppc64": "0.27.4",
+ "@esbuild/linux-riscv64": "0.27.4",
+ "@esbuild/linux-s390x": "0.27.4",
+ "@esbuild/linux-x64": "0.27.4",
+ "@esbuild/netbsd-arm64": "0.27.4",
+ "@esbuild/netbsd-x64": "0.27.4",
+ "@esbuild/openbsd-arm64": "0.27.4",
+ "@esbuild/openbsd-x64": "0.27.4",
+ "@esbuild/openharmony-arm64": "0.27.4",
+ "@esbuild/sunos-x64": "0.27.4",
+ "@esbuild/win32-arm64": "0.27.4",
+ "@esbuild/win32-ia32": "0.27.4",
+ "@esbuild/win32-x64": "0.27.4"
+ }
+ },
+ "node_modules/estree-walker": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
+ "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "^1.0.0"
+ }
+ },
+ "node_modules/expect-type": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz",
+ "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=12.0.0"
+ }
+ },
+ "node_modules/fdir": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
+ "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "peerDependencies": {
+ "picomatch": "^3 || ^4"
+ },
+ "peerDependenciesMeta": {
+ "picomatch": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/fix-dts-default-cjs-exports": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/fix-dts-default-cjs-exports/-/fix-dts-default-cjs-exports-1.0.1.tgz",
+ "integrity": "sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "magic-string": "^0.30.17",
+ "mlly": "^1.7.4",
+ "rollup": "^4.34.8"
+ }
+ },
+ "node_modules/foreground-child": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz",
+ "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "cross-spawn": "^7.0.6",
+ "signal-exit": "^4.0.1"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/get-tsconfig": {
+ "version": "4.13.7",
+ "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.7.tgz",
+ "integrity": "sha512-7tN6rFgBlMgpBML5j8typ92BKFi2sFQvIdpAqLA2beia5avZDrMs0FLZiM5etShWq5irVyGcGMEA1jcDaK7A/Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "resolve-pkg-maps": "^1.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
+ }
+ },
+ "node_modules/glob": {
+ "version": "10.5.0",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz",
+ "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==",
+ "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "foreground-child": "^3.1.0",
+ "jackspeak": "^3.1.2",
+ "minimatch": "^9.0.4",
+ "minipass": "^7.1.2",
+ "package-json-from-dist": "^1.0.0",
+ "path-scurry": "^1.11.1"
+ },
+ "bin": {
+ "glob": "dist/esm/bin.mjs"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/glob/node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/glob/node_modules/brace-expansion": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz",
+ "integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/glob/node_modules/minimatch": {
+ "version": "9.0.9",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz",
+ "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^2.0.2"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/html-escaper": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
+ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/istanbul-lib-coverage": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz",
+ "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/istanbul-lib-report": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz",
+ "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "istanbul-lib-coverage": "^3.0.0",
+ "make-dir": "^4.0.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/istanbul-lib-source-maps": {
+ "version": "5.0.6",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz",
+ "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "@jridgewell/trace-mapping": "^0.3.23",
+ "debug": "^4.1.1",
+ "istanbul-lib-coverage": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/istanbul-reports": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz",
+ "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "html-escaper": "^2.0.0",
+ "istanbul-lib-report": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/jackspeak": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
+ "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "@isaacs/cliui": "^8.0.2"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ },
+ "optionalDependencies": {
+ "@pkgjs/parseargs": "^0.11.0"
+ }
+ },
+ "node_modules/joycon": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz",
+ "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/js-tokens": {
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-10.0.0.tgz",
+ "integrity": "sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/lilconfig": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz",
+ "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antonk52"
+ }
+ },
+ "node_modules/lines-and-columns": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
+ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/load-tsconfig": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/load-tsconfig/-/load-tsconfig-0.2.5.tgz",
+ "integrity": "sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ }
+ },
+ "node_modules/loupe": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz",
+ "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/lru-cache": {
+ "version": "10.4.3",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
+ "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/magic-string": {
+ "version": "0.30.21",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
+ "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.5.5"
+ }
+ },
+ "node_modules/magicast": {
+ "version": "0.3.5",
+ "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.3.5.tgz",
+ "integrity": "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.25.4",
+ "@babel/types": "^7.25.4",
+ "source-map-js": "^1.2.0"
+ }
+ },
+ "node_modules/make-dir": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz",
+ "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "semver": "^7.5.3"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "10.2.4",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz",
+ "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "brace-expansion": "^5.0.2"
+ },
+ "engines": {
+ "node": "18 || 20 || >=22"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/minipass": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz",
+ "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ }
+ },
+ "node_modules/mlly": {
+ "version": "1.8.2",
+ "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.2.tgz",
+ "integrity": "sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "acorn": "^8.16.0",
+ "pathe": "^2.0.3",
+ "pkg-types": "^1.3.1",
+ "ufo": "^1.6.3"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/mz": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
+ "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "any-promise": "^1.0.0",
+ "object-assign": "^4.0.1",
+ "thenify-all": "^1.0.0"
+ }
+ },
+ "node_modules/nanoid": {
+ "version": "3.3.11",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
+ "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "bin": {
+ "nanoid": "bin/nanoid.cjs"
+ },
+ "engines": {
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+ }
+ },
+ "node_modules/object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/package-json-from-dist": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
+ "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==",
+ "dev": true,
+ "license": "BlueOak-1.0.0"
+ },
+ "node_modules/path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-scurry": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
+ "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "lru-cache": "^10.2.0",
+ "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/pathe": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz",
+ "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/pathval": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz",
+ "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 14.16"
+ }
+ },
+ "node_modules/picocolors": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/picomatch": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
+ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/pirates": {
+ "version": "4.0.7",
+ "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz",
+ "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/pkg-types": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz",
+ "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "confbox": "^0.1.8",
+ "mlly": "^1.7.4",
+ "pathe": "^2.0.1"
+ }
+ },
+ "node_modules/postcss": {
+ "version": "8.5.8",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz",
+ "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/postcss"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "nanoid": "^3.3.11",
+ "picocolors": "^1.1.1",
+ "source-map-js": "^1.2.1"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ }
+ },
+ "node_modules/postcss-load-config": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz",
+ "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "lilconfig": "^3.1.1"
+ },
+ "engines": {
+ "node": ">= 18"
+ },
+ "peerDependencies": {
+ "jiti": ">=1.21.0",
+ "postcss": ">=8.0.9",
+ "tsx": "^4.8.1",
+ "yaml": "^2.4.2"
+ },
+ "peerDependenciesMeta": {
+ "jiti": {
+ "optional": true
+ },
+ "postcss": {
+ "optional": true
+ },
+ "tsx": {
+ "optional": true
+ },
+ "yaml": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/readdirp": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
+ "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 14.18.0"
+ },
+ "funding": {
+ "type": "individual",
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
+ "node_modules/resolve-from": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
+ "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/resolve-pkg-maps": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz",
+ "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
+ }
+ },
+ "node_modules/rollup": {
+ "version": "4.60.0",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.0.tgz",
+ "integrity": "sha512-yqjxruMGBQJ2gG4HtjZtAfXArHomazDHoFwFFmZZl0r7Pdo7qCIXKqKHZc8yeoMgzJJ+pO6pEEHa+V7uzWlrAQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "1.0.8"
+ },
+ "bin": {
+ "rollup": "dist/bin/rollup"
+ },
+ "engines": {
+ "node": ">=18.0.0",
+ "npm": ">=8.0.0"
+ },
+ "optionalDependencies": {
+ "@rollup/rollup-android-arm-eabi": "4.60.0",
+ "@rollup/rollup-android-arm64": "4.60.0",
+ "@rollup/rollup-darwin-arm64": "4.60.0",
+ "@rollup/rollup-darwin-x64": "4.60.0",
+ "@rollup/rollup-freebsd-arm64": "4.60.0",
+ "@rollup/rollup-freebsd-x64": "4.60.0",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.60.0",
+ "@rollup/rollup-linux-arm-musleabihf": "4.60.0",
+ "@rollup/rollup-linux-arm64-gnu": "4.60.0",
+ "@rollup/rollup-linux-arm64-musl": "4.60.0",
+ "@rollup/rollup-linux-loong64-gnu": "4.60.0",
+ "@rollup/rollup-linux-loong64-musl": "4.60.0",
+ "@rollup/rollup-linux-ppc64-gnu": "4.60.0",
+ "@rollup/rollup-linux-ppc64-musl": "4.60.0",
+ "@rollup/rollup-linux-riscv64-gnu": "4.60.0",
+ "@rollup/rollup-linux-riscv64-musl": "4.60.0",
+ "@rollup/rollup-linux-s390x-gnu": "4.60.0",
+ "@rollup/rollup-linux-x64-gnu": "4.60.0",
+ "@rollup/rollup-linux-x64-musl": "4.60.0",
+ "@rollup/rollup-openbsd-x64": "4.60.0",
+ "@rollup/rollup-openharmony-arm64": "4.60.0",
+ "@rollup/rollup-win32-arm64-msvc": "4.60.0",
+ "@rollup/rollup-win32-ia32-msvc": "4.60.0",
+ "@rollup/rollup-win32-x64-gnu": "4.60.0",
+ "@rollup/rollup-win32-x64-msvc": "4.60.0",
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/semver": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
+ "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/shebang-command": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "shebang-regex": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/shebang-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/siginfo": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz",
+ "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/signal-exit": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
+ "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/source-map": {
+ "version": "0.7.6",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz",
+ "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">= 12"
+ }
+ },
+ "node_modules/source-map-js": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/stackback": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz",
+ "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/std-env": {
+ "version": "3.10.0",
+ "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz",
+ "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/string-width": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
+ "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "eastasianwidth": "^0.2.0",
+ "emoji-regex": "^9.2.2",
+ "strip-ansi": "^7.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/string-width-cjs": {
+ "name": "string-width",
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/string-width-cjs/node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/string-width-cjs/node_modules/emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/string-width-cjs/node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-ansi": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz",
+ "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^6.2.2"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+ }
+ },
+ "node_modules/strip-ansi-cjs": {
+ "name": "strip-ansi",
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-ansi-cjs/node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-literal": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.1.0.tgz",
+ "integrity": "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "js-tokens": "^9.0.1"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ }
+ },
+ "node_modules/strip-literal/node_modules/js-tokens": {
+ "version": "9.0.1",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz",
+ "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/sucrase": {
+ "version": "3.35.1",
+ "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz",
+ "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.2",
+ "commander": "^4.0.0",
+ "lines-and-columns": "^1.1.6",
+ "mz": "^2.7.0",
+ "pirates": "^4.0.1",
+ "tinyglobby": "^0.2.11",
+ "ts-interface-checker": "^0.1.9"
+ },
+ "bin": {
+ "sucrase": "bin/sucrase",
+ "sucrase-node": "bin/sucrase-node"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ }
+ },
+ "node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/test-exclude": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-7.0.2.tgz",
+ "integrity": "sha512-u9E6A+ZDYdp7a4WnarkXPZOx8Ilz46+kby6p1yZ8zsGTz9gYa6FIS7lj2oezzNKmtdyyJNNmmXDppga5GB7kSw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "@istanbuljs/schema": "^0.1.2",
+ "glob": "^10.4.1",
+ "minimatch": "^10.2.2"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/thenify": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
+ "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "any-promise": "^1.0.0"
+ }
+ },
+ "node_modules/thenify-all": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz",
+ "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "thenify": ">= 3.1.0 < 4"
+ },
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/tinybench": {
+ "version": "2.9.0",
+ "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz",
+ "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/tinyexec": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz",
+ "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/tinyglobby": {
+ "version": "0.2.15",
+ "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
+ "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fdir": "^6.5.0",
+ "picomatch": "^4.0.3"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/SuperchupuDev"
+ }
+ },
+ "node_modules/tinypool": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz",
+ "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^18.0.0 || >=20.0.0"
+ }
+ },
+ "node_modules/tinyrainbow": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz",
+ "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/tinyspy": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.4.tgz",
+ "integrity": "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/tree-kill": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz",
+ "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "tree-kill": "cli.js"
+ }
+ },
+ "node_modules/ts-interface-checker": {
+ "version": "0.1.13",
+ "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
+ "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==",
+ "dev": true,
+ "license": "Apache-2.0"
+ },
+ "node_modules/tsup": {
+ "version": "8.5.1",
+ "resolved": "https://registry.npmjs.org/tsup/-/tsup-8.5.1.tgz",
+ "integrity": "sha512-xtgkqwdhpKWr3tKPmCkvYmS9xnQK3m3XgxZHwSUjvfTjp7YfXe5tT3GgWi0F2N+ZSMsOeWeZFh7ZZFg5iPhing==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "bundle-require": "^5.1.0",
+ "cac": "^6.7.14",
+ "chokidar": "^4.0.3",
+ "consola": "^3.4.0",
+ "debug": "^4.4.0",
+ "esbuild": "^0.27.0",
+ "fix-dts-default-cjs-exports": "^1.0.0",
+ "joycon": "^3.1.1",
+ "picocolors": "^1.1.1",
+ "postcss-load-config": "^6.0.1",
+ "resolve-from": "^5.0.0",
+ "rollup": "^4.34.8",
+ "source-map": "^0.7.6",
+ "sucrase": "^3.35.0",
+ "tinyexec": "^0.3.2",
+ "tinyglobby": "^0.2.11",
+ "tree-kill": "^1.2.2"
+ },
+ "bin": {
+ "tsup": "dist/cli-default.js",
+ "tsup-node": "dist/cli-node.js"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@microsoft/api-extractor": "^7.36.0",
+ "@swc/core": "^1",
+ "postcss": "^8.4.12",
+ "typescript": ">=4.5.0"
+ },
+ "peerDependenciesMeta": {
+ "@microsoft/api-extractor": {
+ "optional": true
+ },
+ "@swc/core": {
+ "optional": true
+ },
+ "postcss": {
+ "optional": true
+ },
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/tsx": {
+ "version": "4.21.0",
+ "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz",
+ "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "esbuild": "~0.27.0",
+ "get-tsconfig": "^4.7.5"
+ },
+ "bin": {
+ "tsx": "dist/cli.mjs"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.3"
+ }
+ },
+ "node_modules/typescript": {
+ "version": "5.9.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
+ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
+ "node_modules/ufo": {
+ "version": "1.6.3",
+ "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.3.tgz",
+ "integrity": "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/vite": {
+ "version": "7.3.1",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz",
+ "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "esbuild": "^0.27.0",
+ "fdir": "^6.5.0",
+ "picomatch": "^4.0.3",
+ "postcss": "^8.5.6",
+ "rollup": "^4.43.0",
+ "tinyglobby": "^0.2.15"
+ },
+ "bin": {
+ "vite": "bin/vite.js"
+ },
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ },
+ "funding": {
+ "url": "https://github.com/vitejs/vite?sponsor=1"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.3"
+ },
+ "peerDependencies": {
+ "@types/node": "^20.19.0 || >=22.12.0",
+ "jiti": ">=1.21.0",
+ "less": "^4.0.0",
+ "lightningcss": "^1.21.0",
+ "sass": "^1.70.0",
+ "sass-embedded": "^1.70.0",
+ "stylus": ">=0.54.8",
+ "sugarss": "^5.0.0",
+ "terser": "^5.16.0",
+ "tsx": "^4.8.1",
+ "yaml": "^2.4.2"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ },
+ "jiti": {
+ "optional": true
+ },
+ "less": {
+ "optional": true
+ },
+ "lightningcss": {
+ "optional": true
+ },
+ "sass": {
+ "optional": true
+ },
+ "sass-embedded": {
+ "optional": true
+ },
+ "stylus": {
+ "optional": true
+ },
+ "sugarss": {
+ "optional": true
+ },
+ "terser": {
+ "optional": true
+ },
+ "tsx": {
+ "optional": true
+ },
+ "yaml": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/vite-node": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.4.tgz",
+ "integrity": "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "cac": "^6.7.14",
+ "debug": "^4.4.1",
+ "es-module-lexer": "^1.7.0",
+ "pathe": "^2.0.3",
+ "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0"
+ },
+ "bin": {
+ "vite-node": "vite-node.mjs"
+ },
+ "engines": {
+ "node": "^18.0.0 || ^20.0.0 || >=22.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/vitest": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.4.tgz",
+ "integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/chai": "^5.2.2",
+ "@vitest/expect": "3.2.4",
+ "@vitest/mocker": "3.2.4",
+ "@vitest/pretty-format": "^3.2.4",
+ "@vitest/runner": "3.2.4",
+ "@vitest/snapshot": "3.2.4",
+ "@vitest/spy": "3.2.4",
+ "@vitest/utils": "3.2.4",
+ "chai": "^5.2.0",
+ "debug": "^4.4.1",
+ "expect-type": "^1.2.1",
+ "magic-string": "^0.30.17",
+ "pathe": "^2.0.3",
+ "picomatch": "^4.0.2",
+ "std-env": "^3.9.0",
+ "tinybench": "^2.9.0",
+ "tinyexec": "^0.3.2",
+ "tinyglobby": "^0.2.14",
+ "tinypool": "^1.1.1",
+ "tinyrainbow": "^2.0.0",
+ "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0",
+ "vite-node": "3.2.4",
+ "why-is-node-running": "^2.3.0"
+ },
+ "bin": {
+ "vitest": "vitest.mjs"
+ },
+ "engines": {
+ "node": "^18.0.0 || ^20.0.0 || >=22.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ },
+ "peerDependencies": {
+ "@edge-runtime/vm": "*",
+ "@types/debug": "^4.1.12",
+ "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
+ "@vitest/browser": "3.2.4",
+ "@vitest/ui": "3.2.4",
+ "happy-dom": "*",
+ "jsdom": "*"
+ },
+ "peerDependenciesMeta": {
+ "@edge-runtime/vm": {
+ "optional": true
+ },
+ "@types/debug": {
+ "optional": true
+ },
+ "@types/node": {
+ "optional": true
+ },
+ "@vitest/browser": {
+ "optional": true
+ },
+ "@vitest/ui": {
+ "optional": true
+ },
+ "happy-dom": {
+ "optional": true
+ },
+ "jsdom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "node-which": "bin/node-which"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/why-is-node-running": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz",
+ "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "siginfo": "^2.0.0",
+ "stackback": "0.0.2"
+ },
+ "bin": {
+ "why-is-node-running": "cli.js"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/wrap-ansi": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
+ "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^6.1.0",
+ "string-width": "^5.0.1",
+ "strip-ansi": "^7.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
+ "node_modules/wrap-ansi-cjs": {
+ "name": "wrap-ansi",
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
+ "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/wrap-ansi-cjs/node_modules/string-width": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ }
+ }
}
diff --git a/package.json b/package.json
index 380e9ad..22a304d 100644
--- a/package.json
+++ b/package.json
@@ -1,93 +1,65 @@
{
- "name": "@absmartly/javascript-sdk",
- "version": "1.13.4",
- "description": "A/B Smartly Javascript SDK",
- "homepage": "https://github.com/absmartly/javascript-sdk#README.md",
- "bugs": "https://github.com/absmartly/javascript-sdk/issues",
- "keywords": [
- "absmartly",
- "ab-smartly",
- "a/b-smartly",
- "ab-testing",
- "a/b-testing",
- "split-testing",
- "ab",
- "a/b",
- "cro"
- ],
- "license": "Apache-2.0",
- "main": "lib/index.js",
- "module": "es/index.js",
- "browser": "dist/absmartly.min.js",
- "types": "types/index.d.ts",
- "engines": {
- "npm": ">=3",
- "node": ">=6"
- },
- "scripts": {
- "build-browser": "TARGET=browser webpack --progress --config webpack.config.js && TARGET=browser NODE_ENV=production webpack --progress --config webpack.config.js",
- "build-cjs": "TARGET=cjs babel js --delete-dir-on-start --ignore 'browser.js' -d lib",
- "build-es": "TARGET=es babel js --delete-dir-on-start --ignore 'browser.js' -d es",
- "build": "npm run -s format && npm run -s lint && npm run -s generate-version && npm run -s compile && npm run -s test && npm run -s build-es && npm run -s build-cjs && npm run -s build-browser",
- "lint": "eslint -f stylish 'src/**/*.{js,mjs,jsx,ts,mts,tsx}'",
- "format": "prettier --write '**/*.{js,mjs,jsx,json,ts,mts,tsx}'",
- "test": "jest --coverage",
- "prepack": "npm run -s build",
- "compile": "tsc",
- "generate-version": "node scripts/generate-version.js"
- },
- "dependencies": {
- "node-fetch": "^2.6.7",
- "rfdc": "^1.3.0",
- "core-js": "^3.20.0"
- },
- "devDependencies": {
- "@babel/cli": "^7.17.3",
- "@babel/core": "^7.17.4",
- "@babel/eslint-parser": "^7.17.0",
- "@babel/plugin-proposal-class-properties": "^7.16.7",
- "@babel/plugin-proposal-export-default-from": "^7.16.7",
- "@babel/plugin-proposal-export-namespace-from": "^7.16.7",
- "@babel/plugin-proposal-logical-assignment-operators": "^7.16.7",
- "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.7",
- "@babel/plugin-proposal-numeric-separator": "^7.16.7",
- "@babel/plugin-proposal-optional-chaining": "^7.16.7",
- "@babel/plugin-proposal-throw-expressions": "^7.16.7",
- "@babel/plugin-syntax-dynamic-import": "^7.8.3",
- "@babel/plugin-syntax-import-meta": "^7.10.4",
- "@babel/plugin-transform-runtime": "^7.16.7",
- "@babel/preset-env": "^7.16.11",
- "@babel/preset-typescript": "^7.18.6",
- "@babel/register": "^7.17.0",
- "@types/jest": "^29.2.5",
- "@types/node-fetch": "^2.6.2",
- "@typescript-eslint/eslint-plugin": "^5.48.2",
- "@typescript-eslint/parser": "^5.48.2",
- "babel-jest": "^29",
- "babel-loader": "^8.2.3",
- "eslint": "^7.32.0",
- "eslint-config-prettier": "^7.1.0",
- "jest": "^29.3.1",
- "prettier": "^2.4.1",
- "terser-webpack-plugin": "^5.3.1",
- "ts-jest": "^29.0.5",
- "ts-loader": "^9.4.2",
- "typescript": "^4.9.4",
- "webpack": "^5.60.0",
- "webpack-bundle-analyzer": "^4.5.0",
- "webpack-cli": "^4.9.1"
- },
- "publishConfig": {
- "access": "public"
- },
- "files": [
- "README.md",
- "CONTRIBUTING.md",
- "LICENSE",
- "package.json",
- "dist/",
- "es/",
- "lib/",
- "types/"
- ]
+ "name": "@absmartly/javascript-sdk",
+ "version": "2.0.0",
+ "description": "A/B Smartly Javascript SDK",
+ "homepage": "https://github.com/absmartly/javascript-sdk#README.md",
+ "bugs": "https://github.com/absmartly/javascript-sdk/issues",
+ "keywords": [
+ "absmartly",
+ "ab-smartly",
+ "a/b-smartly",
+ "ab-testing",
+ "a/b-testing",
+ "split-testing",
+ "ab",
+ "a/b",
+ "cro"
+ ],
+ "license": "Apache-2.0",
+ "type": "module",
+ "main": "dist/index.cjs",
+ "module": "dist/index.js",
+ "browser": "dist/index.global.js",
+ "types": "dist/index.d.ts",
+ "exports": {
+ ".": {
+ "import": {
+ "types": "./dist/index.d.ts",
+ "default": "./dist/index.js"
+ },
+ "require": {
+ "types": "./dist/index.d.cts",
+ "default": "./dist/index.cjs"
+ }
+ }
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "scripts": {
+ "build": "npm run generate-version && tsup",
+ "test": "vitest run",
+ "test:watch": "vitest",
+ "test:coverage": "vitest run --coverage",
+ "typecheck": "tsc --noEmit",
+ "lint": "tsc --noEmit",
+ "generate-version": "tsx scripts/generate-version.ts",
+ "prepack": "npm run build"
+ },
+ "devDependencies": {
+ "tsup": "^8.0.0",
+ "typescript": "^5.4.0",
+ "vitest": "^3.0.0",
+ "tsx": "^4.0.0",
+ "@vitest/coverage-v8": "^3.0.0"
+ },
+ "publishConfig": {
+ "access": "public"
+ },
+ "files": [
+ "README.md",
+ "LICENSE",
+ "package.json",
+ "dist/"
+ ]
}
diff --git a/scripts/generate-version.js b/scripts/generate-version.js
deleted file mode 100644
index 8824f3c..0000000
--- a/scripts/generate-version.js
+++ /dev/null
@@ -1,7 +0,0 @@
-const fs = require("fs");
-const path = require("path");
-
-const pkg = require(path.resolve(__dirname, "../package.json"));
-const versionFile = path.resolve(__dirname, "../src/version.ts");
-
-fs.writeFileSync(versionFile, `export const SDK_VERSION = "${pkg.version}";\n`);
diff --git a/scripts/generate-version.ts b/scripts/generate-version.ts
new file mode 100644
index 0000000..ef29a41
--- /dev/null
+++ b/scripts/generate-version.ts
@@ -0,0 +1,4 @@
+import { readFileSync, writeFileSync } from "node:fs";
+
+const pkg = JSON.parse(readFileSync("package.json", "utf-8"));
+writeFileSync("src/version.ts", `export const SDK_VERSION = "${pkg.version}";\n`);
diff --git a/src/__tests__/abort-controller-shim.test.js b/src/__tests__/abort-controller-shim.test.js
deleted file mode 100644
index fdc3ee0..0000000
--- a/src/__tests__/abort-controller-shim.test.js
+++ /dev/null
@@ -1,91 +0,0 @@
-// eslint-disable-next-line no-shadow
-import { AbortController, AbortSignal } from "../abort-controller-shim";
-
-describe("AbortSignal", () => {
- const expectedEvent = expect.objectContaining({
- type: expect.any(String),
- cancelable: false,
- bubbles: false,
- });
-
- describe("dispatchEvent", () => {
- it("calls listeners", async () => {
- const aborter = new AbortController();
- const signal = aborter.signal;
- const listener1 = jest.fn();
- const listener2 = jest.fn();
- const listener3 = jest.fn();
- signal.onabort = listener3;
- signal.addEventListener("abort", listener1);
- signal.addEventListener("abort", listener2);
- signal.dispatchEvent({ type: "abort", cancelable: false, bubbles: false });
-
- expect(listener1).toHaveBeenCalledTimes(1);
- expect(listener1).toHaveBeenCalledWith(expectedEvent);
-
- expect(listener2).toHaveBeenCalledTimes(1);
- expect(listener2).toHaveBeenCalledWith(expectedEvent);
-
- expect(listener3).toHaveBeenCalledTimes(1);
- expect(listener3).toHaveBeenCalledWith(expectedEvent);
-
- signal.removeEventListener("abort", listener1);
- signal.removeEventListener("abort", listener2);
-
- listener1.mockClear();
- listener2.mockClear();
- listener3.mockClear();
-
- signal.dispatchEvent({ type: "abort", cancelable: false, bubbles: false });
-
- expect(listener1).not.toHaveBeenCalled();
- expect(listener2).not.toHaveBeenCalled();
- expect(listener3).toHaveBeenCalledTimes(1);
- });
- });
-
- it("toString() returns [object AbortSignal]", async () => {
- const aborter = new AbortSignal();
-
- expect(aborter.toString()).toEqual("[object AbortSignal]");
- });
-
- it("toStringTag is set to AbortSignal", async () => {
- const aborter = new AbortSignal();
-
- expect(aborter[Symbol.toStringTag]).toEqual("AbortSignal");
- });
-});
-
-describe("AbortController", () => {
- it("creates abort signal", async () => {
- const aborter = new AbortController();
- expect(aborter.signal).toBeInstanceOf(AbortSignal);
- expect(aborter.signal.aborted).toBe(false);
- });
-
- it("abort dispatches event on signal and aborted is set", async () => {
- const aborter = new AbortController();
- jest.spyOn(aborter.signal, "dispatchEvent").mockImplementation(() => {});
-
- aborter.abort();
-
- expect(aborter.signal.aborted).toBe(true);
- expect(aborter.signal.dispatchEvent).toHaveBeenCalledTimes(1);
- expect(aborter.signal.dispatchEvent).toHaveBeenCalledWith(
- expect.objectContaining({ type: expect.any(String) })
- );
- });
-
- it("toString() returns [object AbortController]", async () => {
- const aborter = new AbortController();
-
- expect(aborter.toString()).toEqual("[object AbortController]");
- });
-
- it("toStringTag is set to AbortController", async () => {
- const aborter = new AbortController();
-
- expect(aborter[Symbol.toStringTag]).toEqual("AbortController");
- });
-});
diff --git a/src/__tests__/algorithm.test.js b/src/__tests__/algorithm.test.js
deleted file mode 100644
index f4ab39d..0000000
--- a/src/__tests__/algorithm.test.js
+++ /dev/null
@@ -1,43 +0,0 @@
-import { insertUniqueSorted } from "../algorithm";
-
-describe("insertUniqueSorted", () => {
- it("should insert a number into the center of an array", (done) => {
- const arr = [0, 1, 3, 5, 8];
-
- insertUniqueSorted(arr, 2, (a, b) => a < b);
-
- expect(arr).toEqual([0, 1, 2, 3, 5, 8]);
-
- done();
- });
-
- it("should not insert a duplicate value", (done) => {
- const arr = [0, 1, 2, 3];
-
- insertUniqueSorted(arr, 2, (a, b) => a < b);
-
- expect(arr).toEqual([0, 1, 2, 3]);
-
- done();
- });
-
- it("should insert the highest value at the end of an array", (done) => {
- const arr = [0, 1, 2, 3];
-
- insertUniqueSorted(arr, 100, (a, b) => a < b);
-
- expect(arr).toEqual([0, 1, 2, 3, 100]);
-
- done();
- });
-
- it("should insert the lowest value at the beginning of an array", (done) => {
- const arr = [1, 2, 3];
-
- insertUniqueSorted(arr, 0, (a, b) => a < b);
-
- expect(arr).toEqual([0, 1, 2, 3]);
-
- done();
- });
-});
diff --git a/src/__tests__/algorithm.test.ts b/src/__tests__/algorithm.test.ts
new file mode 100644
index 0000000..9fce62c
--- /dev/null
+++ b/src/__tests__/algorithm.test.ts
@@ -0,0 +1,34 @@
+import { describe, expect, test } from "vitest";
+import { insertUniqueSorted } from "../algorithm";
+
+describe("insertUniqueSorted", () => {
+ test("inserts into empty array", () => {
+ const arr: number[] = [];
+ insertUniqueSorted(arr, 5, (a, b) => a < b);
+ expect(arr).toEqual([5]);
+ });
+
+ test("inserts in sorted order", () => {
+ const arr = [1, 3, 5];
+ insertUniqueSorted(arr, 2, (a, b) => a < b);
+ expect(arr).toEqual([1, 2, 3, 5]);
+ });
+
+ test("inserts at beginning", () => {
+ const arr = [2, 3, 4];
+ insertUniqueSorted(arr, 1, (a, b) => a < b);
+ expect(arr).toEqual([1, 2, 3, 4]);
+ });
+
+ test("inserts at end", () => {
+ const arr = [1, 2, 3];
+ insertUniqueSorted(arr, 4, (a, b) => a < b);
+ expect(arr).toEqual([1, 2, 3, 4]);
+ });
+
+ test("does not insert duplicate", () => {
+ const arr = [1, 2, 3];
+ insertUniqueSorted(arr, 2, (a, b) => a < b);
+ expect(arr).toEqual([1, 2, 3]);
+ });
+});
diff --git a/src/__tests__/assigner.test.js b/src/__tests__/assigner.test.js
deleted file mode 100644
index bdd2b63..0000000
--- a/src/__tests__/assigner.test.js
+++ /dev/null
@@ -1,66 +0,0 @@
-import { VariantAssigner } from "../assigner";
-import { hashUnit } from "../utils";
-
-describe("VariantAssigner", () => {
- it("assign() should be deterministic", (done) => {
- const testCases = {
- "bleh@absmartly.com": [
- [[0.5, 0.5], 0x00000000, 0x00000000, 0],
- [[0.5, 0.5], 0x00000000, 0x00000001, 1],
- [[0.5, 0.5], 0x8015406f, 0x7ef49b98, 0],
- [[0.5, 0.5], 0x3b2e7d90, 0xca87df4d, 0],
- [[0.5, 0.5], 0x52c1f657, 0xd248bb2e, 0],
- [[0.5, 0.5], 0x865a84d0, 0xaa22d41a, 0],
- [[0.5, 0.5], 0x27d1dc86, 0x845461b9, 1],
- [[0.33, 0.33, 0.34], 0x00000000, 0x00000000, 0],
- [[0.33, 0.33, 0.34], 0x00000000, 0x00000001, 2],
- [[0.33, 0.33, 0.34], 0x8015406f, 0x7ef49b98, 0],
- [[0.33, 0.33, 0.34], 0x3b2e7d90, 0xca87df4d, 0],
- [[0.33, 0.33, 0.34], 0x52c1f657, 0xd248bb2e, 0],
- [[0.33, 0.33, 0.34], 0x865a84d0, 0xaa22d41a, 1],
- [[0.33, 0.33, 0.34], 0x27d1dc86, 0x845461b9, 1],
- ],
- 123456789: [
- [[0.5, 0.5], 0x00000000, 0x00000000, 1],
- [[0.5, 0.5], 0x00000000, 0x00000001, 0],
- [[0.5, 0.5], 0x8015406f, 0x7ef49b98, 1],
- [[0.5, 0.5], 0x3b2e7d90, 0xca87df4d, 1],
- [[0.5, 0.5], 0x52c1f657, 0xd248bb2e, 1],
- [[0.5, 0.5], 0x865a84d0, 0xaa22d41a, 0],
- [[0.5, 0.5], 0x27d1dc86, 0x845461b9, 0],
- [[0.33, 0.33, 0.34], 0x00000000, 0x00000000, 2],
- [[0.33, 0.33, 0.34], 0x00000000, 0x00000001, 1],
- [[0.33, 0.33, 0.34], 0x8015406f, 0x7ef49b98, 2],
- [[0.33, 0.33, 0.34], 0x3b2e7d90, 0xca87df4d, 2],
- [[0.33, 0.33, 0.34], 0x52c1f657, 0xd248bb2e, 2],
- [[0.33, 0.33, 0.34], 0x865a84d0, 0xaa22d41a, 0],
- [[0.33, 0.33, 0.34], 0x27d1dc86, 0x845461b9, 0],
- ],
- e791e240fcd3df7d238cfc285f475e8152fcc0ec: [
- [[0.5, 0.5], 0x00000000, 0x00000000, 1],
- [[0.5, 0.5], 0x00000000, 0x00000001, 0],
- [[0.5, 0.5], 0x8015406f, 0x7ef49b98, 1],
- [[0.5, 0.5], 0x3b2e7d90, 0xca87df4d, 1],
- [[0.5, 0.5], 0x52c1f657, 0xd248bb2e, 0],
- [[0.5, 0.5], 0x865a84d0, 0xaa22d41a, 0],
- [[0.5, 0.5], 0x27d1dc86, 0x845461b9, 0],
- [[0.33, 0.33, 0.34], 0x00000000, 0x00000000, 2],
- [[0.33, 0.33, 0.34], 0x00000000, 0x00000001, 0],
- [[0.33, 0.33, 0.34], 0x8015406f, 0x7ef49b98, 2],
- [[0.33, 0.33, 0.34], 0x3b2e7d90, 0xca87df4d, 1],
- [[0.33, 0.33, 0.34], 0x52c1f657, 0xd248bb2e, 0],
- [[0.33, 0.33, 0.34], 0x865a84d0, 0xaa22d41a, 0],
- [[0.33, 0.33, 0.34], 0x27d1dc86, 0x845461b9, 1],
- ],
- };
-
- for (const [unit, tests] of Object.entries(testCases)) {
- const assigner = new VariantAssigner(hashUnit(unit));
- for (const testCase of tests) {
- const variant = assigner.assign(testCase[0], testCase[1], testCase[2]);
- expect(variant).toBe(testCase[3]);
- }
- }
- done();
- });
-});
diff --git a/src/__tests__/assigner.test.ts b/src/__tests__/assigner.test.ts
new file mode 100644
index 0000000..c71d135
--- /dev/null
+++ b/src/__tests__/assigner.test.ts
@@ -0,0 +1,67 @@
+import { describe, expect, test } from "vitest";
+import { VariantAssigner } from "../assigner";
+import { hashUnit } from "../hashing";
+
+describe("VariantAssigner", () => {
+ const testCases: Record = {
+ "bleh@absmartly.com": [
+ [[0.5, 0.5], 0x00000000, 0x00000000, 0],
+ [[0.5, 0.5], 0x00000000, 0x00000001, 1],
+ [[0.5, 0.5], 0x8015406f, 0x7ef49b98, 0],
+ [[0.5, 0.5], 0x3b2e7d90, 0xca87df4d, 0],
+ [[0.5, 0.5], 0x52c1f657, 0xd248bb2e, 0],
+ [[0.5, 0.5], 0x865a84d0, 0xaa22d41a, 0],
+ [[0.5, 0.5], 0x27d1dc86, 0x845461b9, 1],
+ [[0.33, 0.33, 0.34], 0x00000000, 0x00000000, 0],
+ [[0.33, 0.33, 0.34], 0x00000000, 0x00000001, 2],
+ [[0.33, 0.33, 0.34], 0x8015406f, 0x7ef49b98, 0],
+ [[0.33, 0.33, 0.34], 0x3b2e7d90, 0xca87df4d, 0],
+ [[0.33, 0.33, 0.34], 0x52c1f657, 0xd248bb2e, 0],
+ [[0.33, 0.33, 0.34], 0x865a84d0, 0xaa22d41a, 1],
+ [[0.33, 0.33, 0.34], 0x27d1dc86, 0x845461b9, 1],
+ ],
+ "123456789": [
+ [[0.5, 0.5], 0x00000000, 0x00000000, 1],
+ [[0.5, 0.5], 0x00000000, 0x00000001, 0],
+ [[0.5, 0.5], 0x8015406f, 0x7ef49b98, 1],
+ [[0.5, 0.5], 0x3b2e7d90, 0xca87df4d, 1],
+ [[0.5, 0.5], 0x52c1f657, 0xd248bb2e, 1],
+ [[0.5, 0.5], 0x865a84d0, 0xaa22d41a, 0],
+ [[0.5, 0.5], 0x27d1dc86, 0x845461b9, 0],
+ [[0.33, 0.33, 0.34], 0x00000000, 0x00000000, 2],
+ [[0.33, 0.33, 0.34], 0x00000000, 0x00000001, 1],
+ [[0.33, 0.33, 0.34], 0x8015406f, 0x7ef49b98, 2],
+ [[0.33, 0.33, 0.34], 0x3b2e7d90, 0xca87df4d, 2],
+ [[0.33, 0.33, 0.34], 0x52c1f657, 0xd248bb2e, 2],
+ [[0.33, 0.33, 0.34], 0x865a84d0, 0xaa22d41a, 0],
+ [[0.33, 0.33, 0.34], 0x27d1dc86, 0x845461b9, 0],
+ ],
+ e791e240fcd3df7d238cfc285f475e8152fcc0ec: [
+ [[0.5, 0.5], 0x00000000, 0x00000000, 1],
+ [[0.5, 0.5], 0x00000000, 0x00000001, 0],
+ [[0.5, 0.5], 0x8015406f, 0x7ef49b98, 1],
+ [[0.5, 0.5], 0x3b2e7d90, 0xca87df4d, 1],
+ [[0.5, 0.5], 0x52c1f657, 0xd248bb2e, 0],
+ [[0.5, 0.5], 0x865a84d0, 0xaa22d41a, 0],
+ [[0.5, 0.5], 0x27d1dc86, 0x845461b9, 0],
+ [[0.33, 0.33, 0.34], 0x00000000, 0x00000000, 2],
+ [[0.33, 0.33, 0.34], 0x00000000, 0x00000001, 0],
+ [[0.33, 0.33, 0.34], 0x8015406f, 0x7ef49b98, 2],
+ [[0.33, 0.33, 0.34], 0x3b2e7d90, 0xca87df4d, 1],
+ [[0.33, 0.33, 0.34], 0x52c1f657, 0xd248bb2e, 0],
+ [[0.33, 0.33, 0.34], 0x865a84d0, 0xaa22d41a, 0],
+ [[0.33, 0.33, 0.34], 0x27d1dc86, 0x845461b9, 1],
+ ],
+ };
+
+ for (const [unit, cases] of Object.entries(testCases)) {
+ describe(`unit: "${unit}"`, () => {
+ const assigner = new VariantAssigner(hashUnit(unit));
+ for (const [split, seedHi, seedLo, expected] of cases) {
+ test(`assign([${split}], 0x${seedHi.toString(16)}, 0x${seedLo.toString(16)}) == ${expected}`, () => {
+ expect(assigner.assign(split, seedHi, seedLo)).toBe(expected);
+ });
+ }
+ });
+ }
+});
diff --git a/src/__tests__/client.test.js b/src/__tests__/client.test.js
deleted file mode 100644
index 7834ff4..0000000
--- a/src/__tests__/client.test.js
+++ /dev/null
@@ -1,1071 +0,0 @@
-import Client from "../client";
-// eslint-disable-next-line no-shadow
-import fetch from "../fetch";
-// eslint-disable-next-line no-shadow
-import { AbortController } from "../abort";
-import { AbortError, RetryError, TimeoutError } from "../errors"; //eslint-disable-line no-shadow
-import { SDK_VERSION } from "../version";
-
-jest.mock("../fetch");
-
-describe("Client", () => {
- beforeEach(() => {
- jest.useFakeTimers("legacy");
- jest.spyOn(global, "setTimeout");
- });
-
- afterEach(() => {
- fetch.mockReset();
- });
-
- function advanceFakeTimers() {
- return new Promise((resolve) => {
- let iterations = 0;
-
- const advance = () => {
- jest.advanceTimersByTime(100);
-
- if (++iterations <= 50) {
- Promise.resolve().then(advance);
- } else {
- resolve();
- }
- };
-
- Promise.resolve().then(advance);
- });
- }
-
- const endpoint = "test.absmartly.com:8080/v1";
- const apiKey = "5ebf06d8cb5d8137290c4abb64155584fbdb64d8";
- const agent = "javascript-client";
- const environment = "test";
- const application = {
- name: "test_app",
- version: 1_000_000,
- };
-
- const units = {
- session_id: "dca367dcda209b5197f5f83aee862c7bfb09dc68",
- };
-
- const clientOptions = {
- endpoint,
- agent,
- environment,
- apiKey,
- application,
- keepalive: true,
- timeout: 5000,
- retries: 3,
- };
-
- const defaultMockResponse = {
- units,
- };
-
- const goals = [
- {
- name: "goal1",
- value: [123],
- achievedAt: 123456789,
- },
- ];
-
- const exposures = [
- {
- name: "exp_test",
- variant: 1,
- exposedAt: 123456789,
- assigned: true,
- },
- ];
-
- const attributes = [
- {
- name: "exp_test",
- value: "1",
- setAt: 123456789,
- },
- ];
-
- const publishedAt = 1234567890;
-
- function responseMock(statusCode, statusText, response) {
- return {
- ok: statusCode >= 200 && statusCode <= 299,
- status: statusCode,
- statusText,
- text: () => Promise.resolve(response),
- json: () => Promise.resolve(JSON.parse(JSON.stringify(response))),
- };
- }
-
- function mockFetch(delay, response) {
- return (url, opts) => {
- if (delay > 0) {
- return new Promise((resolve, reject) => {
- const timeout = setTimeout(() => {
- resolve(response);
- }, delay);
-
- if (opts.signal) {
- opts.signal.onabort = () => {
- clearTimeout(timeout);
- reject(new AbortError());
- };
- }
- });
- }
-
- return new Promise.resolve(response);
- };
- }
-
- it("constructor() should validate options", (done) => {
- const deleteOption = (options, key) => {
- const result = Object.assign({}, options);
- delete result[key];
-
- return result;
- };
-
- const emptyOption = (options, key) => {
- const result = Object.assign({}, options);
- result[key] = "";
-
- return result;
- };
-
- for (const key of ["apiKey", "application", "endpoint", "environment"]) {
- expect(() => new Client(deleteOption(clientOptions, key))).toThrow();
- expect(() => new Client(emptyOption(clientOptions, key))).toThrow();
- }
- expect(() => new Client(emptyOption(clientOptions, "agent"))).toThrow();
-
- done();
- });
-
- it("constructor() should accept string application", (done) => {
- const options = Object.assign({}, clientOptions, { application: "website" });
-
- expect(() => new Client(options)).not.toThrow();
-
- done();
- });
-
- it("createContext() calls endpoint", (done) => {
- fetch.mockResolvedValue(responseMock(200, "OK", defaultMockResponse));
-
- const client = new Client(clientOptions);
-
- client
- .createContext({
- units,
- })
- .then((response) => {
- expect(fetch).toHaveBeenCalledTimes(1);
- expect(fetch).toHaveBeenCalledWith(`${endpoint}/context`, {
- method: "POST",
- headers: {
- "Content-Type": "application/json",
- "X-API-Key": apiKey,
- "X-Agent": "javascript-client",
- "X-Environment": "test",
- "X-Application": "test_app",
- "X-Application-Version": 1000000,
- },
- body: JSON.stringify({
- units,
- }),
- keepalive: true,
- signal: expect.any(Object),
- });
-
- expect(response).toStrictEqual(defaultMockResponse);
-
- done();
- });
- });
-
- it("getContext() calls endpoint with correct query", (done) => {
- fetch.mockResolvedValueOnce(responseMock(200, "OK", defaultMockResponse));
-
- const client = new Client(clientOptions);
-
- client.getContext().then((response) => {
- expect(fetch).toHaveBeenCalledTimes(1);
- expect(fetch).toHaveBeenCalledWith(`${endpoint}/context?application=test_app&environment=test`, {
- method: "GET",
- keepalive: true,
- signal: expect.any(Object),
- });
-
- expect(response).toEqual(defaultMockResponse);
-
- done();
- });
- });
-
- it("request() retries on connection error", (done) => {
- fetch
- .mockRejectedValueOnce(new Error("error 1"))
- .mockRejectedValueOnce(new Error("error 2"))
- .mockResolvedValueOnce(responseMock(200, "OK", defaultMockResponse));
-
- const client = new Client(clientOptions);
-
- client
- .request({
- auth: true,
- method: "PUT",
- path: "/context",
- query: { a: 1 },
- body: {},
- })
- .then((response) => {
- expect(fetch).toHaveBeenCalledTimes(3);
- expect(fetch).toHaveBeenLastCalledWith(`${endpoint}/context?a=1`, {
- method: "PUT",
- headers: {
- "Content-Type": "application/json",
- "X-API-Key": apiKey,
- "X-Agent": "javascript-client",
- "X-Environment": "test",
- "X-Application": "test_app",
- "X-Application-Version": 1000000,
- },
- body: JSON.stringify({}),
- keepalive: true,
- signal: expect.any(Object),
- });
-
- expect(response).toEqual(defaultMockResponse);
-
- done();
- });
-
- advanceFakeTimers();
- });
-
- it("request() stops retrying after options.retries", (done) => {
- fetch
- .mockRejectedValueOnce(new Error("error 1"))
- .mockRejectedValueOnce(new Error("error 2"))
- .mockRejectedValueOnce(new Error("error 3"))
- .mockRejectedValueOnce(new Error("error 4"))
- .mockRejectedValueOnce(new Error("error 5"))
- .mockRejectedValueOnce(new Error("error 6"))
- .mockRejectedValueOnce(new Error("error 7"));
-
- jest.spyOn(Math, "random");
- Math.random.mockReturnValue(0.0);
-
- const options = Object.assign({}, clientOptions, { retries: 5, timeout: 5000 });
- const client = new Client(options);
-
- client
- .request({
- auth: true,
- method: "PUT",
- path: "/context",
- query: { a: 1 },
- body: {},
- })
- .catch((error) => {
- expect(fetch).toHaveBeenCalledTimes(6);
- expect(fetch).toHaveBeenLastCalledWith(`${endpoint}/context?a=1`, {
- method: "PUT",
- headers: {
- "Content-Type": "application/json",
- "X-API-Key": apiKey,
- "X-Agent": "javascript-client",
- "X-Environment": "test",
- "X-Application": "test_app",
- "X-Application-Version": 1000000,
- },
- body: JSON.stringify({}),
- keepalive: true,
- signal: expect.any(Object),
- });
-
- expect(error).toBeInstanceOf(RetryError);
- expect(setTimeout).toHaveBeenCalledTimes(6);
- expect(setTimeout.mock.calls.map((x) => x[1]).reduce((x, y) => x + y)).toBeLessThanOrEqual(5000 + 1675);
-
- done();
- });
-
- advanceFakeTimers();
- });
-
- it("request() does not retry with options.retries == 0", (done) => {
- fetch.mockRejectedValueOnce(new Error("error 1"));
-
- jest.spyOn(Math, "random");
- Math.random.mockReturnValue(0.0);
-
- const options = Object.assign({}, clientOptions, { retries: 0, timeout: 5000 });
- const client = new Client(options);
-
- client
- .request({
- auth: true,
- method: "PUT",
- path: "/context",
- query: { a: 1 },
- body: {},
- })
- .catch((error) => {
- expect(fetch).toHaveBeenCalledTimes(1);
- expect(fetch).toHaveBeenLastCalledWith(`${endpoint}/context?a=1`, {
- method: "PUT",
- headers: {
- "Content-Type": "application/json",
- "X-API-Key": apiKey,
- "X-Agent": "javascript-client",
- "X-Environment": "test",
- "X-Application": "test_app",
- "X-Application-Version": 1000000,
- },
- body: JSON.stringify({}),
- keepalive: true,
- signal: expect.any(Object),
- });
-
- expect(error.message).toEqual("error 1");
- expect(setTimeout).toHaveBeenCalledTimes(1);
- expect(setTimeout.mock.calls.map((x) => x[1]).reduce((x, y) => x + y)).toBe(5000);
-
- done();
- });
-
- advanceFakeTimers();
- });
-
- it("request() stops retrying after options.timeout", (done) => {
- fetch
- .mockRejectedValueOnce(new Error("error 1"))
- .mockRejectedValueOnce(new Error("error 2"))
- .mockRejectedValueOnce(new Error("error 3"))
- .mockRejectedValueOnce(new Error("error 4"))
- .mockRejectedValueOnce(new Error("error 5"))
- .mockRejectedValueOnce(new Error("error 6"))
- .mockRejectedValueOnce(new Error("error 7"));
-
- jest.spyOn(Math, "random");
- Math.random.mockReturnValue(1.0);
-
- const options = Object.assign({}, clientOptions, { retries: 5, timeout: 5000 });
- const client = new Client(options);
-
- client
- .request({
- auth: true,
- method: "PUT",
- path: "/context",
- query: { a: 1 },
- body: {},
- })
- .catch((error) => {
- expect(fetch).toHaveBeenCalledTimes(6);
- expect(fetch).toHaveBeenLastCalledWith(`${endpoint}/context?a=1`, {
- method: "PUT",
- headers: {
- "Content-Type": "application/json",
- "X-API-Key": apiKey,
- "X-Agent": "javascript-client",
- "X-Environment": "test",
- "X-Application": "test_app",
- "X-Application-Version": 1000000,
- },
- body: JSON.stringify({}),
- keepalive: true,
- signal: expect.any(Object),
- });
-
- expect(error).toBeInstanceOf(RetryError);
- expect(setTimeout).toHaveBeenCalledTimes(6);
- expect(setTimeout.mock.calls.map((x) => x[1]).reduce((x, y) => x + y)).toBeCloseTo(5000 + 1675, 3);
-
- done();
- });
-
- advanceFakeTimers();
- });
-
- it("request() does not abort before options.timeout", (done) => {
- fetch.mockImplementation(mockFetch(1000, responseMock(200, "OK", defaultMockResponse)));
-
- const options = Object.assign({}, clientOptions, { timeout: 2000 });
- const client = new Client(options);
-
- client
- .request({
- auth: true,
- method: "PUT",
- path: "/context",
- query: { a: 1 },
- body: {},
- })
- .then((response) => {
- expect(response).toStrictEqual(defaultMockResponse);
-
- done();
- })
- .catch((error) => {
- done(error);
- });
-
- advanceFakeTimers();
- });
-
- it("request() aborts after options.timeout", (done) => {
- fetch.mockImplementation(mockFetch(2000, responseMock(200, "OK", defaultMockResponse)));
-
- const options = Object.assign({}, clientOptions, { timeout: 1000 });
- const client = new Client(options);
-
- client
- .request({
- auth: true,
- method: "PUT",
- path: "/context",
- query: { a: 1 },
- body: {},
- })
- .then(() => {
- done("unexpected");
- })
- .catch((error) => {
- expect(error).toBeInstanceOf(TimeoutError);
-
- done();
- });
-
- advanceFakeTimers();
- });
-
- it("request() aborts when abort() is called", (done) => {
- fetch.mockImplementation(mockFetch(3000, responseMock(200, "OK", defaultMockResponse)));
-
- const aborter = new AbortController();
- const options = Object.assign({}, clientOptions, { timeout: 5000 });
- const client = new Client(options);
-
- client
- .request({
- auth: true,
- method: "PUT",
- path: "/context",
- query: { a: 1 },
- body: {},
- signal: aborter.signal,
- })
- .then(() => {
- done("unexpected");
- })
- .catch((error) => {
- expect(error).toBeInstanceOf(AbortError);
-
- done();
- });
-
- setTimeout(() => {
- aborter.abort();
- }, 500);
-
- advanceFakeTimers();
- });
-
- it("request() aborts when abort() is called during a retry wait", (done) => {
- fetch
- .mockRejectedValueOnce(new Error("error 1"))
- .mockRejectedValueOnce(new Error("error 2"))
- .mockRejectedValueOnce(new Error("error 3"))
- .mockRejectedValueOnce(new Error("error 4"))
- .mockRejectedValueOnce(new Error("error 5"))
- .mockRejectedValueOnce(new Error("error 6"))
- .mockRejectedValueOnce(new Error("error 7"));
-
- jest.spyOn(Math, "random");
- Math.random.mockReturnValue(1.0);
-
- const aborter = new AbortController();
- const options = Object.assign({}, clientOptions, { retries: 7, timeout: 5000 });
- const client = new Client(options);
-
- client
- .request({
- auth: true,
- method: "PUT",
- path: "/context",
- query: { a: 1 },
- body: {},
- signal: aborter.signal,
- })
- .then(() => {
- done("unexpected");
- })
- .catch((error) => {
- expect(error).toBeInstanceOf(AbortError);
-
- done();
- });
-
- setTimeout(() => {
- aborter.abort();
- }, 500);
-
- advanceFakeTimers();
- });
-
- it("request() cleans up signal event listener on error", (done) => {
- fetch.mockRejectedValueOnce(new Error("error 1"));
-
- const aborter = new AbortController();
- jest.spyOn(aborter.signal, "addEventListener");
- jest.spyOn(aborter.signal, "removeEventListener");
-
- const options = Object.assign({}, clientOptions, { retries: 0, timeout: 5000 });
- const client = new Client(options);
-
- client
- .request({
- auth: true,
- method: "PUT",
- path: "/context",
- query: { a: 1 },
- body: {},
- signal: aborter.signal,
- })
- .then(() => {
- done("unexpected");
- })
- .catch(() => {
- expect(aborter.signal.addEventListener).toHaveBeenCalledTimes(1);
- expect(aborter.signal.removeEventListener).toHaveBeenCalledTimes(1);
-
- done();
- });
- });
-
- it("request() cleans up signal event listener on success", (done) => {
- fetch.mockResolvedValueOnce(responseMock(200, "OK", defaultMockResponse));
-
- const aborter = new AbortController();
- jest.spyOn(aborter.signal, "addEventListener");
- jest.spyOn(aborter.signal, "removeEventListener");
-
- const options = Object.assign({}, clientOptions, { retries: 0, timeout: 5000 });
- const client = new Client(options);
-
- client
- .request({
- auth: true,
- method: "PUT",
- path: "/context",
- query: { a: 1 },
- body: {},
- signal: aborter.signal,
- })
- .then(() => {
- expect(aborter.signal.addEventListener).toHaveBeenCalledTimes(1);
- expect(aborter.signal.removeEventListener).toHaveBeenCalledTimes(1);
-
- done();
- })
- .catch((error) => {
- done(error);
- });
- });
-
- it("request() stops retrying on bad request", (done) => {
- fetch.mockResolvedValueOnce(responseMock(400, "bad request", "bad request error text"));
-
- const client = new Client(clientOptions);
-
- client
- .request({
- auth: true,
- method: "POST",
- path: "/context",
- query: { a: 1 },
- body: {},
- })
- .catch((error) => {
- expect(fetch).toHaveBeenCalledTimes(1);
- expect(fetch).toHaveBeenLastCalledWith(`${endpoint}/context?a=1`, {
- method: "POST",
- headers: {
- "Content-Type": "application/json",
- "X-API-Key": apiKey,
- "X-Agent": "javascript-client",
- "X-Environment": "test",
- "X-Application": "test_app",
- "X-Application-Version": 1000000,
- },
- body: JSON.stringify({}),
- keepalive: true,
- signal: expect.any(Object),
- });
-
- expect(error.message).toEqual("bad request error text");
-
- done();
- });
- });
-
- it("request() retries on server errors", (done) => {
- fetch
- .mockResolvedValueOnce(responseMock(500, "server error", "server error text"))
- .mockResolvedValueOnce(responseMock(200, "OK", defaultMockResponse));
-
- const client = new Client(clientOptions);
-
- client
- .request({
- auth: true,
- method: "POST",
- path: "/context",
- query: { a: 1 },
- body: {},
- })
- .then((response) => {
- expect(fetch).toHaveBeenCalledTimes(2);
- expect(fetch).toHaveBeenLastCalledWith(`${endpoint}/context?a=1`, {
- method: "POST",
- headers: {
- "Content-Type": "application/json",
- "X-API-Key": apiKey,
- "X-Agent": "javascript-client",
- "X-Environment": "test",
- "X-Application": "test_app",
- "X-Application-Version": 1000000,
- },
- body: JSON.stringify({}),
- keepalive: true,
- signal: expect.any(Object),
- });
-
- expect(response).toEqual(defaultMockResponse);
-
- done();
- });
-
- advanceFakeTimers();
- });
-
- it("request() should encode url query parameters", (done) => {
- fetch.mockResolvedValueOnce(responseMock(200, "OK", defaultMockResponse));
-
- const client = new Client(clientOptions);
-
- client
- .request({
- auth: true,
- method: "PUT",
- path: "/context",
- query: { a: 1, b: "ã=á" },
- body: {},
- })
- .then((response) => {
- expect(fetch).toHaveBeenCalledTimes(1);
- expect(fetch).toHaveBeenLastCalledWith(`${endpoint}/context?a=1&b=%C3%A3%3D%C3%A1`, {
- method: "PUT",
- headers: {
- "Content-Type": "application/json",
- "X-API-Key": apiKey,
- "X-Agent": "javascript-client",
- "X-Environment": "test",
- "X-Application": "test_app",
- "X-Application-Version": 1000000,
- },
- body: JSON.stringify({}),
- keepalive: true,
- signal: expect.any(Object),
- });
-
- expect(response).toEqual(defaultMockResponse);
-
- done();
- });
- });
-
- it("request() should omit query parameters if dict empty", (done) => {
- fetch.mockResolvedValueOnce(responseMock(200, "OK", defaultMockResponse));
-
- const client = new Client(clientOptions);
-
- client
- .request({
- auth: true,
- method: "PUT",
- path: "/context",
- query: {},
- body: {},
- })
- .then((response) => {
- expect(fetch).toHaveBeenCalledTimes(1);
- expect(fetch).toHaveBeenLastCalledWith(`${endpoint}/context`, {
- method: "PUT",
- headers: {
- "Content-Type": "application/json",
- "X-API-Key": apiKey,
- "X-Agent": "javascript-client",
- "X-Environment": "test",
- "X-Application": "test_app",
- "X-Application-Version": 1000000,
- },
- body: JSON.stringify({}),
- keepalive: true,
- signal: expect.any(Object),
- });
-
- expect(response).toEqual(defaultMockResponse);
-
- done();
- });
- });
-
- it("request() should call fetch with an empty body if not specified", (done) => {
- fetch.mockResolvedValueOnce(responseMock(200, "OK", defaultMockResponse));
-
- const client = new Client(clientOptions);
-
- client
- .request({
- auth: true,
- method: "PUT",
- path: "/context",
- })
- .then((response) => {
- expect(fetch).toHaveBeenCalledTimes(1);
- expect(fetch).toHaveBeenLastCalledWith(`${endpoint}/context`, {
- method: "PUT",
- headers: {
- "Content-Type": "application/json",
- "X-API-Key": apiKey,
- "X-Agent": "javascript-client",
- "X-Environment": "test",
- "X-Application": "test_app",
- "X-Application-Version": 1000000,
- },
- body: undefined,
- keepalive: true,
- signal: expect.any(Object),
- });
-
- expect(response).toEqual(defaultMockResponse);
-
- done();
- });
- });
-
- it("request() should set applications headers for string application", (done) => {
- fetch.mockResolvedValueOnce(responseMock(200, "OK", defaultMockResponse));
-
- const client = new Client(Object.assign({}, clientOptions, { application: "website" }));
-
- client
- .request({
- auth: true,
- method: "PUT",
- path: "/context",
- })
- .then((response) => {
- expect(fetch).toHaveBeenCalledTimes(1);
- expect(fetch).toHaveBeenLastCalledWith(`${endpoint}/context`, {
- method: "PUT",
- headers: {
- "Content-Type": "application/json",
- "X-API-Key": apiKey,
- "X-Agent": "javascript-client",
- "X-Environment": "test",
- "X-Application": "website",
- "X-Application-Version": 0,
- },
- keepalive: true,
- body: undefined,
- signal: expect.any(Object),
- });
-
- expect(response).toEqual(defaultMockResponse);
-
- done();
- });
- });
-
- it("request() should not send headers when auth argument is false", (done) => {
- fetch.mockResolvedValueOnce(responseMock(200, "OK", defaultMockResponse));
-
- const client = new Client(Object.assign({}, clientOptions, { application: "website" }));
-
- client
- .request({
- auth: false,
- method: "PUT",
- path: "/context",
- })
- .then((response) => {
- expect(fetch).toHaveBeenCalledTimes(1);
- expect(fetch).toHaveBeenLastCalledWith(`${endpoint}/context`, {
- method: "PUT",
- body: undefined,
- keepalive: true,
- signal: expect.any(Object),
- });
-
- expect(response).toEqual(defaultMockResponse);
-
- done();
- });
- });
-
- it("publish() calls endpoint", (done) => {
- fetch.mockResolvedValueOnce(responseMock(200, "OK", defaultMockResponse));
-
- const client = new Client(clientOptions);
-
- client
- .publish({
- units,
- publishedAt,
- sdkVersion: SDK_VERSION,
- goals,
- exposures,
- attributes,
- })
- .then((response) => {
- expect(fetch).toHaveBeenCalledTimes(1);
- expect(fetch).toHaveBeenCalledWith(`${endpoint}/context`, {
- method: "PUT",
- headers: {
- "Content-Type": "application/json",
- "X-API-Key": apiKey,
- "X-Agent": "javascript-client",
- "X-Environment": "test",
- "X-Application": "test_app",
- "X-Application-Version": 1000000,
- },
- keepalive: true,
- body: JSON.stringify({
- units,
- publishedAt,
- sdkVersion: SDK_VERSION,
- goals,
- exposures,
- attributes,
- }),
- signal: expect.any(Object),
- });
-
- expect(response).toEqual(defaultMockResponse);
-
- done();
- });
- });
-
- it("publish() should omit empty arrays", (done) => {
- fetch.mockResolvedValueOnce(responseMock(200, "OK", defaultMockResponse));
-
- const client = new Client(clientOptions);
-
- client
- .publish({
- units,
- publishedAt,
- sdkVersion: SDK_VERSION,
- goals: [],
- exposures: [],
- })
- .then((response) => {
- expect(fetch).toHaveBeenCalledTimes(1);
- expect(fetch).toHaveBeenCalledWith(`${endpoint}/context`, {
- method: "PUT",
- headers: {
- "Content-Type": "application/json",
- "X-API-Key": apiKey,
- "X-Agent": "javascript-client",
- "X-Environment": "test",
- "X-Application": "test_app",
- "X-Application-Version": 1000000,
- },
- keepalive: true,
- body: JSON.stringify({
- units,
- publishedAt,
- sdkVersion: SDK_VERSION,
- }),
- signal: expect.any(Object),
- });
-
- expect(response).toEqual(defaultMockResponse);
-
- done();
- });
- });
-
- it("publish() should set publishedAt if not present", (done) => {
- fetch.mockResolvedValueOnce(responseMock(200, "OK", defaultMockResponse));
- jest.spyOn(Date, "now").mockReturnValue(publishedAt + 100);
-
- const client = new Client(clientOptions);
-
- client
- .publish({
- units,
- sdkVersion: SDK_VERSION,
- goals: [],
- exposures: [],
- })
- .then((response) => {
- expect(fetch).toHaveBeenCalledTimes(1);
- expect(fetch).toHaveBeenCalledWith(`${endpoint}/context`, {
- method: "PUT",
- headers: {
- "Content-Type": "application/json",
- "X-API-Key": apiKey,
- "X-Agent": "javascript-client",
- "X-Environment": "test",
- "X-Application": "test_app",
- "X-Application-Version": 1000000,
- },
- keepalive: true,
- body: JSON.stringify({
- units,
- publishedAt: publishedAt + 100,
- sdkVersion: SDK_VERSION,
- }),
- signal: expect.any(Object),
- });
-
- expect(response).toEqual(defaultMockResponse);
-
- done();
- });
- });
-
- it("constructor() should accept custom agent string", (done) => {
- fetch.mockResolvedValueOnce(responseMock(200, "OK", defaultMockResponse));
-
- const customAgent = "custom-agent";
- const client = new Client({ ...clientOptions, agent: customAgent });
-
- client
- .request({
- auth: true,
- method: "PUT",
- path: "/context",
- })
- .then(() => {
- expect(fetch).toHaveBeenCalledTimes(1);
- expect(fetch).toHaveBeenCalledWith(`${endpoint}/context`, {
- method: "PUT",
- headers: {
- "Content-Type": "application/json",
- "X-API-Key": apiKey,
- "X-Agent": customAgent,
- "X-Environment": "test",
- "X-Application": "test_app",
- "X-Application-Version": 1000000,
- },
- body: undefined,
- keepalive: true,
- signal: expect.any(Object),
- });
-
- done();
- });
- });
-
- it("publish() should include sdkVersion in body", (done) => {
- fetch.mockResolvedValueOnce(responseMock(200, "OK", defaultMockResponse));
-
- const client = new Client(clientOptions);
-
- client
- .publish({
- units,
- publishedAt,
- sdkVersion: "1.2.3",
- goals: [],
- exposures: [],
- })
- .then(() => {
- const body = JSON.parse(fetch.mock.calls[0][1].body);
- expect(body.sdkVersion).toEqual("1.2.3");
-
- done();
- });
- });
-
- it("getAgent() should return default agent when not specified", () => {
- const { agent: _, ...optionsWithoutAgent } = clientOptions;
- const client = new Client(optionsWithoutAgent);
- expect(client.getAgent()).toEqual("javascript-client");
- });
-
- it("getAgent() should return custom agent when specified", () => {
- const client = new Client({ ...clientOptions, agent: "custom-sdk" });
- expect(client.getAgent()).toEqual("custom-sdk");
- });
-
- it("getApplication() should return normalized application object", () => {
- const client = new Client(clientOptions);
- expect(client.getApplication()).toEqual({ name: "test_app", version: 1000000 });
- });
-
- it("getApplication() should normalize string application to object", () => {
- const client = new Client({ ...clientOptions, application: "website" });
- expect(client.getApplication()).toEqual({ name: "website", version: 0 });
- });
-
- it("getApplication() should accept semver string version", () => {
- const client = new Client({ ...clientOptions, application: { name: "website", version: "1.2.3" } });
- expect(client.getApplication()).toEqual({ name: "website", version: "1.2.3" });
- });
-
- it("getEnvironment() should return the environment", () => {
- const client = new Client(clientOptions);
- expect(client.getEnvironment()).toEqual(environment);
- });
-
- it("publish() should not have the keepalive flag if specified", (done) => {
- fetch.mockResolvedValueOnce(responseMock(200, "OK", defaultMockResponse));
-
- const client = new Client({ ...clientOptions, keepalive: false });
-
- client
- .publish({
- units,
- publishedAt,
- goals: [],
- exposures: [],
- })
- .then((response) => {
- expect(fetch).toHaveBeenCalledTimes(1);
- expect(fetch).toHaveBeenCalledWith(`${endpoint}/context`, {
- method: "PUT",
- headers: {
- "Content-Type": "application/json",
- "X-API-Key": apiKey,
- "X-Agent": "javascript-client",
- "X-Environment": "test",
- "X-Application": "test_app",
- "X-Application-Version": 1000000,
- },
- keepalive: false,
- body: JSON.stringify({
- units,
- publishedAt,
- }),
- signal: expect.any(Object),
- });
-
- expect(response).toEqual(defaultMockResponse);
-
- done();
- });
- });
-});
diff --git a/src/__tests__/client.test.ts b/src/__tests__/client.test.ts
new file mode 100644
index 0000000..6947093
--- /dev/null
+++ b/src/__tests__/client.test.ts
@@ -0,0 +1,221 @@
+import { describe, expect, test, vi, beforeEach, afterEach } from "vitest";
+import { DefaultClient } from "../client";
+import type { ClientOptions } from "../interfaces";
+
+const defaultOpts: ClientOptions = {
+ agent: "test-agent",
+ apiKey: "test-api-key",
+ application: "test-app",
+ endpoint: "https://test.absmartly.io/v1",
+ environment: "test",
+};
+
+describe("Client", () => {
+ describe("constructor validation", () => {
+ test("throws for missing apiKey", () => {
+ const opts = { ...defaultOpts, apiKey: undefined } as unknown as ClientOptions;
+ expect(() => new DefaultClient(opts)).toThrow("Missing 'apiKey' in options argument");
+ });
+
+ test("uses injected fetch implementation", async () => {
+ const fetchImpl = vi.fn().mockResolvedValue({ ok: true, json: () => Promise.resolve({ experiments: [] }) });
+ const client = new DefaultClient({ ...defaultOpts, retries: 0, timeout: 1000, fetchImpl });
+ await client.getContext();
+ expect(fetchImpl).toHaveBeenCalledTimes(1);
+ });
+
+ test("uses injected AbortController implementation", async () => {
+ const abort = vi.fn();
+ class FakeAbortController {
+ signal = { addEventListener: vi.fn(), removeEventListener: vi.fn() } as unknown as AbortSignal;
+ abort = abort;
+ }
+ const fetchImpl = vi.fn().mockResolvedValue({ ok: true, json: () => Promise.resolve({ experiments: [] }) });
+ const client = new DefaultClient({
+ ...defaultOpts,
+ retries: 0,
+ timeout: 1000,
+ fetchImpl,
+ AbortControllerImpl: FakeAbortController as unknown as typeof AbortController,
+ });
+ await client.getContext();
+ expect(fetchImpl).toHaveBeenCalledTimes(1);
+ });
+
+ test("throws for missing endpoint", () => {
+ const opts = { ...defaultOpts, endpoint: undefined } as unknown as ClientOptions;
+ expect(() => new DefaultClient(opts)).toThrow("Missing 'endpoint' in options argument");
+ });
+
+ test("throws for missing environment", () => {
+ const opts = { ...defaultOpts, environment: undefined } as unknown as ClientOptions;
+ expect(() => new DefaultClient(opts)).toThrow("Missing 'environment' in options argument");
+ });
+
+ test("throws for missing application", () => {
+ const opts = { ...defaultOpts, application: undefined } as unknown as ClientOptions;
+ expect(() => new DefaultClient(opts)).toThrow("Missing 'application' in options argument");
+ });
+
+ test("throws for empty apiKey", () => {
+ const opts = { ...defaultOpts, apiKey: "" };
+ expect(() => new DefaultClient(opts)).toThrow("Invalid 'apiKey' in options argument");
+ });
+
+ test("accepts ApplicationObject", () => {
+ const opts = { ...defaultOpts, application: { name: "my-app", version: "1.0.0" } };
+ const client = new DefaultClient(opts);
+ expect(client.getApplication()).toEqual({ name: "my-app", version: "1.0.0" });
+ });
+
+ test("converts string application to ApplicationObject", () => {
+ const client = new DefaultClient(defaultOpts);
+ expect(client.getApplication()).toEqual({ name: "test-app", version: 0 });
+ });
+ });
+
+ describe("accessors", () => {
+ test("getAgent", () => {
+ const client = new DefaultClient(defaultOpts);
+ expect(client.getAgent()).toBe("test-agent");
+ });
+
+ test("getEnvironment", () => {
+ const client = new DefaultClient(defaultOpts);
+ expect(client.getEnvironment()).toBe("test");
+ });
+ });
+
+ describe("getContext", () => {
+ beforeEach(() => {
+ vi.stubGlobal("fetch", vi.fn());
+ });
+
+ afterEach(() => {
+ vi.restoreAllMocks();
+ });
+
+ test("makes GET request to /context", async () => {
+ const mockResponse = { ok: true, json: () => Promise.resolve({ experiments: [] }) };
+ (globalThis.fetch as ReturnType).mockResolvedValue(mockResponse);
+
+ const client = new DefaultClient({ ...defaultOpts, retries: 0, timeout: 1000 });
+ await client.getContext();
+
+ expect(globalThis.fetch).toHaveBeenCalledTimes(1);
+ const [url] = (globalThis.fetch as ReturnType).mock.calls[0]!;
+ expect(url).toContain("/context");
+ expect(url).toContain("application=test-app");
+ expect(url).toContain("environment=test");
+ });
+
+ test("GET /context does NOT include auth headers", async () => {
+ const mockResponse = { ok: true, json: () => Promise.resolve({ experiments: [] }) };
+ (globalThis.fetch as ReturnType).mockResolvedValue(mockResponse);
+
+ const client = new DefaultClient({ ...defaultOpts, retries: 0, timeout: 1000 });
+ await client.getContext();
+
+ const [, opts] = (globalThis.fetch as ReturnType).mock.calls[0]!;
+ expect(opts.headers).toBeUndefined();
+ });
+ });
+
+ describe("publish", () => {
+ beforeEach(() => {
+ vi.stubGlobal("fetch", vi.fn());
+ });
+
+ afterEach(() => {
+ vi.restoreAllMocks();
+ });
+
+ test("makes PUT request to /context with auth headers", async () => {
+ const mockResponse = { ok: true, json: () => Promise.resolve({}) };
+ (globalThis.fetch as ReturnType).mockResolvedValue(mockResponse);
+
+ const client = new DefaultClient({ ...defaultOpts, retries: 0, timeout: 1000 });
+ await client.publish({
+ units: [{ type: "session_id", uid: "abc" }],
+ publishedAt: 1000,
+ hashed: true,
+ sdkVersion: "2.0.0",
+ });
+
+ const [, opts] = (globalThis.fetch as ReturnType).mock.calls[0]!;
+ expect(opts.method).toBe("PUT");
+ expect(opts.headers["X-API-Key"]).toBe("test-api-key");
+ expect(opts.headers["X-Agent"]).toBe("test-agent");
+ expect(opts.headers["X-Environment"]).toBe("test");
+ });
+
+ test("omits empty goals and exposures arrays", async () => {
+ const mockResponse = { ok: true, json: () => Promise.resolve({}) };
+ (globalThis.fetch as ReturnType).mockResolvedValue(mockResponse);
+
+ const client = new DefaultClient({ ...defaultOpts, retries: 0, timeout: 1000 });
+ await client.publish({
+ units: [{ type: "session_id", uid: "abc" }],
+ publishedAt: 1000,
+ hashed: true,
+ sdkVersion: "2.0.0",
+ goals: [],
+ exposures: [],
+ });
+
+ const [, opts] = (globalThis.fetch as ReturnType).mock.calls[0]!;
+ const body = JSON.parse(opts.body);
+ expect(body.goals).toBeUndefined();
+ expect(body.exposures).toBeUndefined();
+ });
+ });
+
+ describe("retry logic", () => {
+ beforeEach(() => {
+ vi.useFakeTimers();
+ vi.stubGlobal("fetch", vi.fn());
+ });
+
+ afterEach(() => {
+ vi.useRealTimers();
+ vi.restoreAllMocks();
+ });
+
+ test("retries on server error", async () => {
+ const failResponse = { ok: false, status: 500, statusText: "Server Error", text: () => Promise.resolve("") };
+ const successResponse = { ok: true, json: () => Promise.resolve({ data: "ok" }) };
+
+ (globalThis.fetch as ReturnType)
+ .mockResolvedValueOnce(failResponse)
+ .mockResolvedValueOnce(successResponse);
+
+ const client = new DefaultClient({ ...defaultOpts, retries: 3, timeout: 10000 });
+ const promise = client.getContext();
+
+ await vi.runAllTimersAsync();
+ const result = await promise;
+
+ expect(result).toEqual({ data: "ok" });
+ expect(globalThis.fetch).toHaveBeenCalledTimes(2);
+ });
+
+ test("does not retry on 4xx error", async () => {
+ const failResponse = {
+ ok: false,
+ status: 400,
+ statusText: "Bad Request",
+ text: () => Promise.resolve("bad request"),
+ };
+
+ (globalThis.fetch as ReturnType).mockResolvedValue(failResponse);
+
+ const client = new DefaultClient({ ...defaultOpts, retries: 3, timeout: 10000 });
+ const promise = client.getContext();
+
+ await expect(promise).rejects.toThrow("bad request");
+ expect(globalThis.fetch).toHaveBeenCalledTimes(1);
+
+ await vi.runAllTimersAsync();
+ });
+ });
+});
diff --git a/src/__tests__/config.test.js b/src/__tests__/config.test.js
deleted file mode 100644
index 5be597c..0000000
--- a/src/__tests__/config.test.js
+++ /dev/null
@@ -1,236 +0,0 @@
-import { mergeConfig } from "../config";
-import Context from "../context";
-
-jest.mock("../context");
-
-describe("Config", () => {
- describe("mergeConfig()", () => {
- it("should create getters that call context.variable()", (done) => {
- const context = new Context();
-
- const variableKeys = {
- button: "exp_test_abc",
- "banner.border": "exp_test_ab",
- "banner.size": "exp_test_ab",
- "home.arrow.direction": "exp_test_arrow",
- };
-
- const expectedValues = {
- button: true,
- "banner.border": 10,
- "banner.size": 812,
- "home.arrow.direction": "up",
- };
-
- context.variableKeys.mockReturnValue(variableKeys);
- context.variableValue.mockImplementation((key) => expectedValues[key]);
-
- const previousConfig = {
- button: false,
- banner: {
- size: 420,
- border: 0,
- },
- home: {
- arrow: {
- direction: "down",
- },
- },
- other: "unused",
- };
-
- const expectedConfig = {
- button: true,
- banner: {
- size: 812,
- border: 10,
- },
- home: {
- arrow: {
- direction: "up",
- },
- },
- other: "unused",
- };
-
- const actual = mergeConfig(context, previousConfig);
- expect(actual).not.toBe(previousConfig); // should be a clone and new properties are not values, but have accessors
- expect(actual).toMatchObject(expectedConfig);
- expect(context.variableValue).toHaveBeenCalledTimes(4); // called during equality check above
- context.variableValue.mockClear();
-
- expect(actual.button).toEqual(expectedConfig.button);
- expect(context.variableValue).toHaveBeenCalledTimes(1);
- expect(context.variableValue).toHaveBeenCalledWith("button", previousConfig.button);
- context.variableValue.mockClear();
-
- expect(actual.banner.border).toEqual(expectedConfig.banner.border);
- expect(context.variableValue).toHaveBeenCalledTimes(1);
- expect(context.variableValue).toHaveBeenCalledWith("banner.border", previousConfig.banner.border);
- context.variableValue.mockClear();
-
- expect(actual.banner.size).toEqual(expectedConfig.banner.size);
- expect(context.variableValue).toHaveBeenCalledTimes(1);
- expect(context.variableValue).toHaveBeenCalledWith("banner.size", previousConfig.banner.size);
- context.variableValue.mockClear();
-
- expect(actual.home.arrow.direction).toEqual(expectedConfig.home.arrow.direction);
- expect(context.variableValue).toHaveBeenCalledTimes(1);
- expect(context.variableValue).toHaveBeenCalledWith(
- "home.arrow.direction",
- previousConfig.home.arrow.direction
- );
- context.variableValue.mockClear();
-
- expect(actual.other).toEqual(expectedConfig.other);
- expect(context.variableValue).not.toHaveBeenCalled();
-
- done();
- });
-
- it("should warn about mismatching object merges", (done) => {
- jest.spyOn(console, "warn").mockImplementation(() => {});
-
- const context = new Context();
-
- const variableKeys = {
- "button.active": "exp_test_abc",
- "banner.border": "exp_test_ab",
- "banner.size": "exp_test_ab",
- "home.arrow.direction": "exp_test_arrow",
- };
-
- const expectedValues = {
- "button.active": true,
- "banner.border": 10,
- "banner.size": 812,
- "home.arrow.direction": "up",
- };
-
- context.variableKeys.mockReturnValue(variableKeys);
- context.variableValue.mockImplementation((key) => expectedValues[key]);
-
- const previousConfig = {
- button: true,
- banner: {
- size: 420,
- border: 0,
- },
- home: {
- arrow: "down",
- },
- other: "unused",
- };
-
- const expectedConfig = {
- button: {
- active: true,
- },
- banner: {
- size: 812,
- border: 10,
- },
- home: {
- arrow: {
- direction: "up",
- },
- },
- other: "unused",
- };
-
- const actual = mergeConfig(context, previousConfig);
- expect(actual).not.toBe(previousConfig); // should be a clone and new properties are not values, but have accessors
- expect(actual).toMatchObject(expectedConfig);
- expect(context.variableValue).toHaveBeenCalledTimes(4); // called during equality check above
- context.variableValue.mockClear();
-
- expect(console.warn).toHaveBeenCalledTimes(2);
- expect(console.warn).toHaveBeenCalledWith(
- "Config key 'button.active' for experiment 'exp_test_abc' is overriding non-object value at 'button' with an object."
- );
- expect(console.warn).toHaveBeenCalledWith(
- "Config key 'home.arrow.direction' for experiment 'exp_test_arrow' is overriding non-object value at 'home.arrow' with an object."
- );
-
- expect(actual.button.active).toEqual(expectedConfig.button.active);
- expect(context.variableValue).toHaveBeenCalledTimes(1);
- expect(context.variableValue).toHaveBeenCalledWith("button.active", undefined);
- context.variableValue.mockClear();
-
- expect(actual.home.arrow.direction).toEqual(expectedConfig.home.arrow.direction);
- expect(context.variableValue).toHaveBeenCalledTimes(1);
- expect(context.variableValue).toHaveBeenCalledWith("home.arrow.direction", undefined);
- context.variableValue.mockClear();
-
- done();
- });
-
- it("should error with multiple experiments overriding key", (done) => {
- jest.spyOn(console, "error").mockImplementation(() => {});
-
- jest.spyOn(console, "warn").mockImplementation(() => {});
-
- const context = new Context();
-
- const variableKeys = {
- "button.active": true,
- "banner.border": "exp_test_ab",
- "banner.size": "exp_test_abc",
- "home.arrow": "exp_test_arrow",
- "home.arrow.direction": "exp_test_arrow_direction",
- };
-
- const expectedValues = {
- "button.active": true,
- "banner.border": 10,
- "banner.size": 812,
- "home.arrow": "up",
- "home.arrow.direction": "up",
- };
-
- context.variableKeys.mockReturnValue(variableKeys);
- context.variableValue.mockImplementation((key) => expectedValues[key]);
-
- const previousConfig = {
- button: {
- active: false,
- },
- banner: {
- size: 420,
- border: 0,
- },
- home: {
- arrow: "down",
- },
- other: "unused",
- };
-
- const expectedConfig = {
- button: {
- active: true,
- },
- banner: {
- size: 812,
- border: 10,
- },
- home: {
- arrow: "up",
- },
- other: "unused",
- };
-
- const actual = mergeConfig(context, previousConfig);
- expect(actual).not.toBe(previousConfig); // should be a clone and new properties are not values, but have accessors
- expect(actual).toMatchObject(expectedConfig);
- expect(context.variableValue).toHaveBeenCalledTimes(4); // called during equality check above
- context.variableValue.mockClear();
-
- expect(console.error).toHaveBeenCalledTimes(1);
- expect(console.error).toHaveBeenCalledWith(
- "Config key 'home.arrow' already set by experiment 'exp_test_arrow'."
- );
-
- done();
- });
- });
-});
diff --git a/src/__tests__/config.test.ts b/src/__tests__/config.test.ts
new file mode 100644
index 0000000..0f9ae9b
--- /dev/null
+++ b/src/__tests__/config.test.ts
@@ -0,0 +1,59 @@
+import { describe, expect, test, vi } from "vitest";
+import { mergeConfig } from "../config";
+
+function mockContext(
+ variableKeys: Record,
+ variableValues: Record = {},
+) {
+ return {
+ variableKeys: () => variableKeys,
+ variableValue: (key: string, defaultValue: unknown) =>
+ key in variableValues ? variableValues[key] : defaultValue,
+ };
+}
+
+describe("mergeConfig", () => {
+ test("returns new object, does not mutate original", () => {
+ const original = { key: "value" };
+ const context = mockContext({});
+ const result = mergeConfig(context as never, original);
+ expect(result).not.toBe(original);
+ expect(result).toEqual({ key: "value" });
+ });
+
+ test("creates getter for experiment variable", () => {
+ const context = mockContext({ "button.color": ["exp_test"] }, { "button.color": "red" });
+ const config = { button: { color: "blue" } };
+ const result = mergeConfig(context as never, config);
+ expect(result.button).toBeDefined();
+ expect((result.button as Record).color).toBe("red");
+ });
+
+ test("falls back to default when variable not set", () => {
+ const context = mockContext({ "button.color": ["exp_test"] });
+ const config = { button: { color: "blue" } };
+ const result = mergeConfig(context as never, config);
+ expect((result.button as Record).color).toBe("blue");
+ });
+
+ test("warns when overriding non-object value with object", () => {
+ const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
+ const context = mockContext({ "button.active.color": ["exp_test"] });
+ const config = { button: { active: "yes" } };
+ mergeConfig(context as never, config);
+ expect(warnSpy).toHaveBeenCalled();
+ warnSpy.mockRestore();
+ });
+
+ test("errors when key already set by another experiment", () => {
+ const errorSpy = vi.spyOn(console, "error").mockImplementation(() => {});
+ const context = mockContext({
+ "button.color": ["exp_test_1"],
+ "button.color.shade": ["exp_test_2"],
+ });
+ const config = { button: { color: "blue" } };
+ mergeConfig(context as never, config);
+ expect(errorSpy).toHaveBeenCalled();
+ errorSpy.mockRestore();
+ });
+});
diff --git a/src/__tests__/context.test.js b/src/__tests__/context.test.js
deleted file mode 100644
index bac768c..0000000
--- a/src/__tests__/context.test.js
+++ /dev/null
@@ -1,4178 +0,0 @@
-import Client from "../client";
-import SDK from "../sdk";
-import Context from "../context";
-import { hashUnit } from "../utils";
-import clone from "rfdc/default";
-import { ContextPublisher } from "../publisher";
-import { ContextDataProvider } from "../provider";
-import { SDK_VERSION } from "../version";
-
-jest.mock("../client");
-jest.mock("../sdk");
-jest.mock("../provider");
-jest.mock("../publisher");
-
-describe("Context", () => {
- const contextParams = {
- units: {
- session_id: "e791e240fcd3df7d238cfc285f475e8152fcc0ec",
- user_id: 12317303,
- },
- };
-
- const publishUnits = Object.entries(contextParams.units).map((x) => ({ type: x[0], uid: hashUnit(x[1]) }));
-
- const units = {
- session_id: "e791e240fcd3df7d238cfc285f475e8152fcc0ec",
- user_id: "123456789",
- email: "bleh@absmartly.com",
- };
-
- const getContextResponse = {
- experiments: [
- {
- id: 1,
- name: "exp_test_ab",
- iteration: 1,
- unitType: "session_id",
- seedHi: 3603515,
- seedLo: 233373850,
- split: [0.5, 0.5],
- trafficSeedHi: 449867249,
- trafficSeedLo: 455443629,
- trafficSplit: [0.0, 1.0],
- fullOnVariant: 0,
- applications: [
- {
- name: "website",
- },
- ],
- variants: [
- {
- name: "A",
- config: null,
- },
- {
- name: "B",
- config: '{"banner.border":1,"banner.size":"large"}',
- },
- ],
- audience: null,
- customFieldValues: null,
- },
- {
- id: 2,
- name: "exp_test_abc",
- iteration: 1,
- unitType: "session_id",
- seedHi: 55006150,
- seedLo: 47189152,
- split: [0.34, 0.33, 0.33],
- trafficSeedHi: 705671872,
- trafficSeedLo: 212903484,
- trafficSplit: [0.0, 1.0],
- fullOnVariant: 0,
- applications: [
- {
- name: "website",
- },
- ],
- variants: [
- {
- name: "A",
- config: null,
- },
- {
- name: "B",
- config: '{"button.color":"blue"}',
- },
- {
- name: "C",
- config: '{"button.color":"red"}',
- },
- ],
- audience: "",
- customFieldValues: [
- {
- name: "country",
- value: "US,PT,ES,DE,FR",
- type: "string",
- },
- {
- name: "json_object",
- value: '{"123":1,"456":0}',
- type: "json",
- },
- {
- name: "json_array",
- value: '["hello", "world"]',
- type: "json",
- },
- {
- name: "json_number",
- value: "123",
- type: "json",
- },
- {
- name: "json_string",
- value: '"hello"',
- type: "json",
- },
- {
- name: "json_boolean",
- value: "true",
- type: "json",
- },
- {
- name: "json_null",
- value: "null",
- type: "json",
- },
- {
- name: "json_invalid",
- value: "invalid",
- type: "json",
- },
- ],
- },
- {
- id: 3,
- name: "exp_test_not_eligible",
- iteration: 1,
- unitType: "user_id",
- seedHi: 503266407,
- seedLo: 144942754,
- split: [0.34, 0.33, 0.33],
- trafficSeedHi: 87768905,
- trafficSeedLo: 511357582,
- trafficSplit: [0.99, 0.01],
- fullOnVariant: 0,
- applications: [
- {
- name: "website",
- },
- ],
- variants: [
- {
- name: "A",
- config: null,
- },
- {
- name: "B",
- config: '{"card.width":"80%"}',
- },
- {
- name: "C",
- config: '{"card.width":"75%"}',
- },
- ],
- audience: "{}",
- customFieldValues: null,
- },
- {
- id: 4,
- name: "exp_test_fullon",
- iteration: 1,
- unitType: "session_id",
- seedHi: 856061641,
- seedLo: 990838475,
- split: [0.25, 0.25, 0.25, 0.25],
- trafficSeedHi: 360868579,
- trafficSeedLo: 330937933,
- trafficSplit: [0.0, 1.0],
- fullOnVariant: 2,
- applications: [
- {
- name: "website",
- },
- ],
- variants: [
- {
- name: "A",
- config: null,
- },
- {
- name: "B",
- config: '{"submit.color":"red","submit.shape":"circle"}',
- },
- {
- name: "C",
- config: '{"submit.color":"blue","submit.shape":"rect"}',
- },
- {
- name: "D",
- config: '{"submit.color":"green","submit.shape":"square"}',
- },
- ],
- audience: "null",
- customFieldValues: null,
- },
- {
- id: 5,
- name: "exp_test_custom_fields",
- iteration: 1,
- unitType: "session_id",
- seedHi: 9372617,
- seedLo: 121364805,
- split: [0.5, 0.5],
- trafficSeedHi: 318746944,
- trafficSeedLo: 359812364,
- trafficSplit: [0.0, 1.0],
- fullOnVariant: 0,
- applications: [
- {
- name: "website",
- },
- ],
- variants: [
- {
- name: "A",
- config: null,
- },
- {
- name: "B",
- config: '{"submit.size":"sm"}',
- },
- ],
- audience: null,
- customFieldValues: [
- {
- name: "country",
- value: "US,PT,ES",
- type: "string",
- },
- {
- name: "languages",
- value: "en-US,en-GB,pt-PT,pt-BR,es-ES,es-MX",
- type: "string",
- },
- {
- name: "text_field",
- value: "hello text",
- type: "text",
- },
- {
- name: "string_field",
- value: "hello string",
- type: "string",
- },
- {
- name: "number_field",
- value: "123",
- type: "number",
- },
- {
- name: "boolean_field",
- value: "true",
- type: "boolean",
- },
- {
- name: "false_boolean_field",
- value: "false",
- type: "boolean",
- },
- {
- name: "invalid_type_field",
- value: "invalid",
- type: "invalid",
- },
- ],
- },
- ],
- };
-
- const refreshContextResponse = Object.assign({}, getContextResponse, {
- experiments: [
- {
- id: 6,
- name: "exp_test_new",
- iteration: 2,
- unitType: "session_id",
- seedHi: 934590467,
- seedLo: 714771373,
- split: [0.5, 0.5],
- trafficSeedHi: 940553836,
- trafficSeedLo: 270705624,
- trafficSplit: [0.0, 1.0],
- fullOnVariant: 1,
- applications: [
- {
- name: "website",
- },
- ],
- variants: [
- {
- name: "A",
- config: null,
- },
- {
- name: "B",
- config: '{"show-modal":true}',
- },
- ],
- },
- ].concat(getContextResponse.experiments),
- });
-
- const audienceContextResponse = {
- ...getContextResponse,
- experiments: getContextResponse.experiments.map((x) => {
- if (x.name === "exp_test_ab") {
- return {
- ...x,
- audience: JSON.stringify({
- filter: [{ gte: [{ var: "age" }, { value: 20 }] }],
- }),
- };
- }
- return x;
- }),
- };
-
- const audienceStrictContextResponse = {
- ...audienceContextResponse,
- experiments: audienceContextResponse.experiments.map((x) => {
- if (x.name === "exp_test_ab") {
- return {
- ...x,
- audienceStrict: true,
- variants: x.variants.map((v) => {
- if (v.name === "A") {
- return { name: "A", config: '{"banner.size":"tiny"}' };
- }
- return v;
- }),
- };
- }
- return x;
- }),
- };
-
- const expectedVariants = {
- exp_test_ab: 1,
- exp_test_abc: 2,
- exp_test_not_eligible: 0,
- exp_test_fullon: 2,
- exp_test_new: 1,
- exp_test_custom_fields: 1,
- };
-
- const lowestIdConflictingKeyContextResponse = {
- ...getContextResponse,
- experiments: getContextResponse.experiments.map((e) => {
- if (e.name === "exp_test_ab") {
- return {
- ...e,
- id: 99,
- variants: e.variants.map((v, i) => {
- if (i === expectedVariants[e.name]) {
- return {
- ...v,
- config: JSON.stringify({
- icon: "arrow",
- }),
- };
- }
- return v;
- }),
- };
- }
- if (e.name === "exp_test_abc") {
- return {
- ...e,
- id: 1,
- variants: e.variants.map((v, i) => {
- if (i === expectedVariants[e.name]) {
- return {
- ...v,
- config: JSON.stringify({ icon: "circle" }),
- };
- }
- return v;
- }),
- };
- }
- return e;
- }),
- };
-
- const disjointedContextResponse = {
- ...getContextResponse,
- experiments: getContextResponse.experiments.map((exp) => {
- if (exp.name === "exp_test_ab") {
- return {
- ...exp,
- audienceStrict: true,
- audience: JSON.stringify({
- filter: [{ gte: [{ var: "age" }, { value: 20 }] }],
- }),
- variants: exp.variants.map((v, i) => {
- if (i === expectedVariants[exp.name]) {
- return {
- ...v,
- config: JSON.stringify({
- icon: "arrow",
- }),
- };
- }
- return v;
- }),
- };
- }
- if (exp.name === "exp_test_abc") {
- return {
- ...exp,
- audienceStrict: true,
- audience: JSON.stringify({
- filter: [{ lt: [{ var: "age" }, { value: 20 }] }],
- }),
- variants: exp.variants.map((variant, i) => {
- if (i === expectedVariants[exp.name]) {
- return {
- ...variant,
- config: JSON.stringify({
- icon: "circle",
- }),
- };
- }
- return variant;
- }),
- };
- }
- return exp;
- }),
- };
-
- const expectedVariables = {
- "banner.border": 1,
- "banner.size": "large",
- "button.color": "red",
- "submit.color": "blue",
- "submit.shape": "rect",
- "show-modal": true,
- "submit.size": "sm",
- };
-
- const variableExperiments = {
- "banner.border": ["exp_test_ab"],
- "banner.size": ["exp_test_ab"],
- "button.color": ["exp_test_abc"],
- "card.width": ["exp_test_not_eligible"],
- "submit.color": ["exp_test_fullon"],
- "submit.shape": ["exp_test_fullon"],
- "submit.size": ["exp_test_custom_fields"],
- "show-modal": ["exp_test_new"],
- };
-
- const sdk = new SDK();
- const client = new Client();
- const publisher = new ContextPublisher();
- const provider = new ContextDataProvider();
-
- sdk.getContextDataProvider.mockReturnValue(provider);
- sdk.getContextPublisher.mockReturnValue(publisher);
- sdk.getClient.mockReturnValue(client);
- sdk.getEventLogger.mockReturnValue(SDK.defaultEventLogger);
-
- client.getAgent.mockReturnValue("absmartly-javascript-sdk");
- client.getApplication.mockReturnValue({ name: "website", version: 0 });
- client.getEnvironment.mockReturnValue("production");
-
- const contextOptions = {
- publishDelay: -1,
- refreshPeriod: 0,
- };
-
- const timeOrigin = 1611141535729;
-
- beforeEach(() => {
- jest.spyOn(Date, "now").mockImplementation(() => timeOrigin);
- });
-
- describe("Context", () => {
- it("should be ready with data", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
- expect(context.isReady()).toEqual(true);
- expect(context.isFailed()).toEqual(false);
-
- context.ready().then(() => {
- expect(context.isReady()).toEqual(true);
- expect(context.data()).toStrictEqual(getContextResponse);
- expect(context.eventLogger()).toBe(SDK.defaultEventLogger);
- expect(context.provider()).toBe(provider);
- expect(context.publisher()).toBe(publisher);
-
- done();
- });
- });
-
- it("should use custom publisher, dataProvider and eventLogger", (done) => {
- const customPublisher = new ContextPublisher();
- const customDataProvider = new ContextDataProvider();
- const customEventLogger = jest.fn();
-
- const context = new Context(
- sdk,
- {
- ...contextOptions,
- publisher: customPublisher,
- dataProvider: customDataProvider,
- eventLogger: customEventLogger,
- },
- contextParams,
- getContextResponse
- );
- expect(context.isReady()).toEqual(true);
- expect(context.isFailed()).toEqual(false);
-
- context.ready().then(() => {
- expect(context.isReady()).toEqual(true);
- expect(context.data()).toStrictEqual(getContextResponse);
- expect(context.eventLogger()).toBe(customEventLogger);
- expect(context.provider()).toBe(customDataProvider);
- expect(context.publisher()).toBe(customPublisher);
-
- done();
- });
- });
-
- it("should become ready and call handler", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, Promise.resolve(getContextResponse));
- expect(context.isReady()).toEqual(false);
- expect(context.isFailed()).toEqual(false);
-
- context.ready().then(() => {
- expect(context.isReady()).toEqual(true);
- expect(context.data()).toStrictEqual(getContextResponse);
- expect(context.eventLogger()).toBe(SDK.defaultEventLogger);
- expect(context.provider()).toBe(provider);
- expect(context.publisher()).toBe(publisher);
-
- done();
- });
- });
-
- it("should become ready and failed, and call handler on failure", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, Promise.reject("bad request error text"));
- expect(context.isReady()).toEqual(false);
- expect(context.isFailed()).toEqual(false);
-
- context.ready().then(() => {
- expect(context.isReady()).toEqual(true);
- expect(context.isFailed()).toEqual(true);
- expect(context.data()).toStrictEqual({});
- expect(context.eventLogger()).toBe(SDK.defaultEventLogger);
- expect(context.provider()).toBe(provider);
- expect(context.publisher()).toBe(publisher);
-
- done();
- });
- });
-
- it("should call event logger on error", (done) => {
- SDK.defaultEventLogger.mockClear();
-
- const context = new Context(sdk, contextOptions, contextParams, Promise.reject("bad request error text"));
- context.ready().then(() => {
- expect(SDK.defaultEventLogger).toHaveBeenCalledTimes(1);
- expect(SDK.defaultEventLogger).toHaveBeenCalledWith(context, "error", "bad request error text");
-
- done();
- });
- });
-
- it("should call event logger on success", (done) => {
- SDK.defaultEventLogger.mockClear();
-
- const context = new Context(sdk, contextOptions, contextParams, Promise.resolve(getContextResponse));
- context.ready().then(() => {
- expect(SDK.defaultEventLogger).toHaveBeenCalledTimes(1);
- expect(SDK.defaultEventLogger).toHaveBeenCalledWith(context, "ready", getContextResponse);
-
- done();
- });
- });
-
- it("should call event logger on pre-fetched experiment data", (done) => {
- SDK.defaultEventLogger.mockClear();
-
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
- context.ready().then(() => {
- expect(SDK.defaultEventLogger).toHaveBeenCalledTimes(1);
- expect(SDK.defaultEventLogger).toHaveBeenCalledWith(context, "ready", getContextResponse);
-
- done();
- });
- });
-
- it("should throw when not ready", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, Promise.resolve(getContextResponse));
- expect(context.isReady()).toEqual(false);
- expect(context.isFailed()).toEqual(false);
- expect(context.isFinalized()).toEqual(false);
-
- expect(() => context.data()).toThrow();
- expect(() => context.treatment("test")).toThrow();
- expect(() => context.peek("test")).toThrow();
- expect(() => context.experiments()).toThrow();
- expect(() => context.variableKeys()).toThrow();
- expect(() => context.variableValue("a", 17)).toThrow();
- expect(() => context.peekVariableValue("a", 17)).toThrow();
-
- done();
- });
-
- it("should load experiment data", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
-
- expect(context.experiments()).toEqual(getContextResponse.experiments.map((x) => x.name));
- for (const experiment of getContextResponse.experiments) {
- expect(context.peek(experiment.name)).toEqual(expectedVariants[experiment.name]);
- expect(context.treatment(experiment.name)).toEqual(expectedVariants[experiment.name]);
- }
- expect(context.data()).toEqual(getContextResponse);
-
- done();
- });
-
- it("should start refresh timer after ready", (done) => {
- jest.useFakeTimers("legacy");
- jest.spyOn(global, "setInterval");
-
- const refreshPeriod = 1000;
- const context = new Context(
- sdk,
- Object.assign(contextOptions, { refreshPeriod }),
- contextParams,
- Promise.resolve(getContextResponse)
- );
-
- expect(context.isReady()).toEqual(false);
- expect(context.isFailed()).toEqual(false);
-
- expect(setInterval).not.toHaveBeenCalled();
-
- context.ready().then(() => {
- expect(setInterval).toHaveBeenCalledTimes(1);
- expect(setInterval).toHaveBeenCalledWith(expect.anything(), refreshPeriod);
- setInterval.mockClear();
-
- jest.advanceTimersByTime(refreshPeriod - 1);
-
- expect(provider.getContextData).not.toHaveBeenCalled();
-
- const getContextPromise = Promise.resolve(refreshContextResponse);
- provider.getContextData.mockReturnValue(getContextPromise);
-
- jest.advanceTimersByTime(refreshPeriod);
-
- getContextPromise.then(() => {
- expect(setInterval).not.toHaveBeenCalled();
- expect(provider.getContextData).toHaveBeenCalledTimes(1);
- expect(provider.getContextData).toHaveBeenCalledWith(sdk, undefined);
- provider.getContextData.mockClear();
-
- // test another interval
- const nextGetContextPromise = Promise.resolve(refreshContextResponse);
- provider.getContextData.mockReturnValue(nextGetContextPromise);
-
- jest.advanceTimersByTime(refreshPeriod);
- nextGetContextPromise.then(() => {
- expect(setInterval).not.toHaveBeenCalled();
- expect(provider.getContextData).toHaveBeenCalledTimes(1);
- expect(provider.getContextData).toHaveBeenCalledWith(sdk, undefined);
-
- done();
- });
- });
- });
- });
- });
-
- describe("unit()", () => {
- it("should set a unit", (done) => {
- const context = new Context(sdk, contextOptions, { units: {} }, getContextResponse);
-
- context.units(units);
-
- for (const [key, value] of Object.entries(units)) {
- expect(context.getUnit(key)).toEqual(value);
- }
-
- expect(context.getUnits()).toEqual(units);
-
- done();
- });
- it("should throw on duplicate unit type set", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
- expect(context.isReady()).toEqual(true);
-
- expect(() => context.unit("session_id", "new_id")).toThrow();
-
- // should not throw if set to the same value
- expect(() => context.unit("session_id", "e791e240fcd3df7d238cfc285f475e8152fcc0ec")).not.toThrow();
-
- done();
- });
-
- it("should throw on invalid uid", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
- expect(context.isReady()).toEqual(true);
-
- expect(() => context.unit("session_id", "")).toThrow();
- expect(() => context.unit("session_id", null)).toThrow();
- expect(() => context.unit("session_id", undefined)).toThrow();
- expect(() => context.unit("session_id", true)).toThrow();
- expect(() => context.unit("session_id", {})).toThrow();
- expect(() => context.unit("session_id", [])).toThrow();
-
- done();
- });
-
- it("should be callable before ready()", (done) => {
- const context = new Context(sdk, contextOptions, {}, Promise.resolve(getContextResponse));
-
- context.units(contextParams.units);
-
- context.ready().then(() => {
- expect(context.isReady()).toEqual(true);
-
- context.treatment("exp_test_ab");
-
- publisher.publish.mockReturnValue(Promise.resolve());
-
- jest.spyOn(Date, "now").mockImplementation(() => timeOrigin + 100);
-
- context.publish().then(() => {
- expect(publisher.publish).toHaveBeenCalledTimes(1);
- expect(publisher.publish).toHaveBeenCalledWith(
- {
- publishedAt: 1611141535829,
- units: publishUnits,
- hashed: true,
- sdkVersion: SDK_VERSION,
- exposures: [
- {
- id: 1,
- name: "exp_test_ab",
- unit: "session_id",
- exposedAt: 1611141535729,
- variant: 1,
- assigned: true,
- eligible: true,
- overridden: false,
- fullOn: false,
- custom: false,
- audienceMismatch: false,
- },
- ],
- },
- sdk,
- context,
- undefined
- );
-
- done();
- });
- });
- });
-
- it("should throw after finalized() call", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
- publisher.publish.mockReturnValue(Promise.resolve());
-
- context.treatment("exp_test_ab");
-
- expect(context.pending()).toEqual(1);
-
- context.finalize().then(() => {
- expect(() => context.unit("test", "test")).toThrow(); // finalizing
-
- done();
- });
-
- expect(context.isFinalizing()).toEqual(true);
- expect(() => context.unit("test", "test")).toThrow(); // finalizing
- });
- });
-
- describe("getAttribute()", () => {
- it("should get the last set attribute", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
-
- context.attribute("attr1", "value1");
- context.attribute("attr1", "value2");
-
- expect(context.getAttribute("attr1")).toEqual("value2");
-
- done();
- });
- });
-
- describe("attribute()", () => {
- it("should set an attribute", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
-
- context.attribute("attr1", "value1");
- context.attributes({
- attr2: "value2",
- attr3: 15,
- });
-
- expect(context.getAttribute("attr1")).toEqual("value1");
- expect(context.getAttributes()).toEqual({
- attr1: "value1",
- attr2: "value2",
- attr3: 15,
- });
-
- done();
- });
-
- it("should be callable before ready()", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, Promise.resolve(getContextResponse));
- expect(context.isReady()).toEqual(false);
- expect(context.isFailed()).toEqual(false);
- expect(context.isFinalized()).toEqual(false);
-
- context.attribute("attr1", "value1");
- context.attributes({
- attr2: "value2",
- attr3: 3,
- });
-
- expect(context.getAttribute("attr1")).toEqual("value1");
- expect(context.getAttributes()).toEqual({
- attr1: "value1",
- attr2: "value2",
- attr3: 3,
- });
-
- context.ready().then(() => {
- expect(context.isReady()).toEqual(true);
-
- context.treatment("exp_test_ab");
-
- publisher.publish.mockReturnValue(Promise.resolve());
-
- jest.spyOn(Date, "now").mockImplementation(() => timeOrigin + 100);
-
- context.publish().then(() => {
- expect(publisher.publish).toHaveBeenCalledTimes(1);
- expect(publisher.publish).toHaveBeenCalledWith(
- {
- publishedAt: 1611141535829,
- units: publishUnits,
- hashed: true,
- sdkVersion: SDK_VERSION,
- exposures: [
- {
- id: 1,
- name: "exp_test_ab",
- unit: "session_id",
- exposedAt: 1611141535729,
- variant: 1,
- assigned: true,
- eligible: true,
- overridden: false,
- fullOn: false,
- custom: false,
- audienceMismatch: false,
- },
- ],
- attributes: [
- {
- name: "attr1",
- setAt: 1611141535729,
- value: "value1",
- },
- {
- name: "attr2",
- setAt: 1611141535729,
- value: "value2",
- },
- {
- name: "attr3",
- setAt: 1611141535729,
- value: 3,
- },
- ],
- },
- sdk,
- context,
- undefined
- );
-
- done();
- });
- });
- });
- });
-
- describe("refresh()", () => {
- it("should call client and load new data", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
-
- provider.getContextData.mockReturnValue(Promise.resolve(refreshContextResponse));
-
- context.refresh().then(() => {
- expect(provider.getContextData).toHaveBeenCalledTimes(1);
- expect(provider.getContextData).toHaveBeenCalledWith(sdk, undefined);
-
- expect(context.experiments()).toEqual(refreshContextResponse.experiments.map((x) => x.name));
- for (const experiment of refreshContextResponse.experiments) {
- expect(context.treatment(experiment.name)).toEqual(expectedVariants[experiment.name]);
- }
- expect(context.data()).toEqual(refreshContextResponse);
-
- done();
- });
- });
-
- it("should pass through request options", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
-
- provider.getContextData.mockReturnValue(Promise.resolve(refreshContextResponse));
-
- context.refresh({ timeout: 1234 }).then(() => {
- expect(provider.getContextData).toHaveBeenCalledTimes(1);
- expect(provider.getContextData).toHaveBeenCalledWith(sdk, { timeout: 1234 });
-
- expect(context.experiments()).toEqual(refreshContextResponse.experiments.map((x) => x.name));
- for (const experiment of refreshContextResponse.experiments) {
- expect(context.treatment(experiment.name)).toEqual(expectedVariants[experiment.name]);
- }
- expect(context.data()).toEqual(refreshContextResponse);
-
- done();
- });
- });
-
- it("should reject promise on error", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
-
- provider.getContextData.mockReturnValueOnce(Promise.reject(new Error("test error")));
-
- context.refresh().catch((error) => {
- expect(error.message).toEqual("test error");
- done();
- });
- });
-
- it("should not re-queue exposures after refresh when not changed", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
-
- for (const experiment of getContextResponse.experiments) {
- context.treatment(experiment.name);
- }
-
- expect(context.pending()).toEqual(getContextResponse.experiments.length);
-
- provider.getContextData.mockReturnValue(Promise.resolve(refreshContextResponse));
-
- context.refresh().then(() => {
- expect(context.pending()).toEqual(getContextResponse.experiments.length);
-
- expect(provider.getContextData).toHaveBeenCalledTimes(1);
- expect(provider.getContextData).toHaveBeenCalledWith(sdk, undefined);
-
- for (const experiment of getContextResponse.experiments) {
- context.treatment(experiment.name);
- }
-
- expect(context.pending()).toEqual(getContextResponse.experiments.length);
-
- for (const experiment of refreshContextResponse.experiments) {
- context.treatment(experiment.name);
- }
-
- expect(context.pending()).toEqual(refreshContextResponse.experiments.length);
-
- done();
- });
- });
-
- it("should not re-queue when not changed on audience mismatch", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, audienceStrictContextResponse);
-
- expect(context.treatment("exp_test_ab")).toEqual(0);
-
- expect(context.pending()).toEqual(1);
-
- provider.getContextData.mockReturnValue(Promise.resolve(audienceStrictContextResponse));
-
- context.refresh().then(() => {
- expect(context.treatment("exp_test_ab")).toEqual(0);
-
- expect(context.pending()).toEqual(1);
-
- done();
- });
- });
-
- it("should not re-queue when not changed with override", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, audienceStrictContextResponse);
-
- context.override("exp_test_ab", 3);
- expect(context.treatment("exp_test_ab")).toEqual(3);
-
- expect(context.pending()).toEqual(1);
-
- provider.getContextData.mockReturnValue(Promise.resolve(audienceStrictContextResponse));
-
- context.refresh().then(() => {
- expect(context.treatment("exp_test_ab")).toEqual(3);
-
- expect(context.pending()).toEqual(1);
-
- done();
- });
- });
-
- it("should not call client publish when failed", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, Promise.reject("bad request error text"));
-
- context.ready().then(() => {
- context.refresh().then(() => {
- expect(provider.getContextData).not.toHaveBeenCalled();
-
- done();
- });
- });
- });
-
- it("should call event logger when failed", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, Promise.resolve(getContextResponse));
- context.ready().then(() => {
- provider.getContextData.mockReturnValueOnce(Promise.reject(new Error("test error")));
-
- SDK.defaultEventLogger.mockClear();
- context.refresh().catch((error) => {
- expect(SDK.defaultEventLogger).toHaveBeenCalledTimes(1);
- expect(SDK.defaultEventLogger).toHaveBeenCalledWith(context, "error", error);
-
- done();
- });
- });
- });
-
- it("should call event logger on success", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, Promise.resolve(getContextResponse));
-
- provider.getContextData.mockReturnValueOnce(Promise.resolve(refreshContextResponse));
-
- context.ready().then(() => {
- SDK.defaultEventLogger.mockClear();
- context.refresh().then(() => {
- expect(SDK.defaultEventLogger).toHaveBeenCalledTimes(1);
- expect(SDK.defaultEventLogger).toHaveBeenCalledWith(context, "refresh", refreshContextResponse);
-
- done();
- });
- });
- });
-
- it("should throw after finalized() call", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
- publisher.publish.mockReturnValue(Promise.resolve());
-
- context.treatment("exp_test_ab");
-
- expect(context.pending()).toEqual(1);
-
- context.finalize().then(() => {
- expect(() => context.refresh()).toThrow();
-
- done();
- });
-
- expect(context.isFinalizing()).toEqual(true);
- expect(() => context.refresh()).toThrow(); // finalizing
- });
-
- it("should keep overrides", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
-
- provider.getContextData.mockReturnValue(Promise.resolve(refreshContextResponse));
-
- context.override("not_found", 3);
- expect(context.peek("not_found")).toEqual(3);
-
- context.refresh().then(() => {
- expect(context.peek("not_found")).toEqual(3);
-
- done();
- });
- });
-
- it("should keep custom assignments", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
-
- provider.getContextData.mockReturnValue(Promise.resolve(refreshContextResponse));
-
- context.customAssignment("exp_test_ab", 3);
-
- expect(context.peek("exp_test_ab")).toEqual(3);
-
- context.refresh().then(() => {
- expect(context.peek("exp_test_ab")).toEqual(3);
-
- done();
- });
- });
-
- it("should pick up changes in experiment stopped", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
- const experimentName = "exp_test_abc";
-
- expect(context.treatment(experimentName)).toEqual(expectedVariants[experimentName]);
- expect(context.pending()).toEqual(1);
-
- const stoppedRefreshContextResponse = clone(getContextResponse);
- stoppedRefreshContextResponse.experiments = stoppedRefreshContextResponse.experiments.filter(
- (x) => x.name !== experimentName
- );
-
- provider.getContextData.mockReturnValue(Promise.resolve(stoppedRefreshContextResponse));
-
- context.refresh().then(() => {
- expect(context.treatment(experimentName)).toEqual(0);
- expect(context.pending()).toEqual(2); // exposure before the change + exposure after stopped
-
- done();
- });
- });
-
- it("should pick up changes in experiment started", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
- const experimentName = "exp_test_new";
-
- expect(context.treatment(experimentName)).toEqual(0);
- expect(context.pending()).toEqual(1);
-
- provider.getContextData.mockReturnValue(Promise.resolve(refreshContextResponse));
-
- context.refresh().then(() => {
- expect(context.treatment(experimentName)).toEqual(1);
- expect(context.pending()).toEqual(2); // exposure before the change + exposure after stopped
-
- done();
- });
- });
-
- it("should pick up changes in experiment fullon", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
- const experimentName = "exp_test_abc";
-
- expect(context.treatment(experimentName)).toEqual(expectedVariants[experimentName]);
- expect(context.pending()).toEqual(1);
-
- const fullOnRefreshContextResponse = clone(getContextResponse);
- for (const experiment of fullOnRefreshContextResponse.experiments) {
- if (experiment.name === experimentName) {
- expect(experiment.fullOnVariant).toEqual(0);
- experiment.fullOnVariant = 1;
- expect(expectedVariants[experimentName]).not.toEqual(experiment.fullOnVariant);
- }
- }
-
- provider.getContextData.mockReturnValue(Promise.resolve(fullOnRefreshContextResponse));
-
- context.refresh().then(() => {
- expect(context.treatment(experimentName)).toEqual(1);
- expect(context.pending()).toEqual(2); // exposure before the change + exposure after fullon
-
- done();
- });
- });
-
- it("should pick up changes in experiment traffic split", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
- const experimentName = "exp_test_not_eligible";
-
- expect(context.treatment(experimentName)).toEqual(expectedVariants[experimentName]);
- expect(context.pending()).toEqual(1);
-
- const scaledUpRefreshContextResponse = clone(getContextResponse);
- for (const experiment of scaledUpRefreshContextResponse.experiments) {
- if (experiment.name === experimentName) {
- experiment.trafficSplit = [0.0, 1.0];
- }
- }
-
- provider.getContextData.mockReturnValue(Promise.resolve(scaledUpRefreshContextResponse));
-
- context.refresh().then(() => {
- expect(context.treatment(experimentName)).toEqual(2);
- expect(context.pending()).toEqual(2); // exposure before the change + exposure after fullon
-
- done();
- });
- });
-
- it("should pick up changes in experiment iteration", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
- const experimentName = "exp_test_abc";
-
- expect(context.treatment(experimentName)).toEqual(expectedVariants[experimentName]);
- expect(context.pending()).toEqual(1);
-
- const iteratedRefreshContextResponse = clone(getContextResponse);
- for (const experiment of iteratedRefreshContextResponse.experiments) {
- if (experiment.name === experimentName) {
- experiment.iteration = 2;
- experiment.trafficSeedHi = 54870830;
- experiment.trafficSeedHi = 398724581;
- experiment.seedHi = 77498863;
- experiment.seedHi = 34737352;
- }
- }
-
- provider.getContextData.mockReturnValue(Promise.resolve(iteratedRefreshContextResponse));
-
- context.refresh().then(() => {
- expect(context.treatment(experimentName)).toEqual(1);
- expect(context.pending()).toEqual(2); // exposure before the change + exposure after fullon
-
- done();
- });
- });
-
- it("should pick up changes in experiment id", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
- const experimentName = "exp_test_abc";
-
- expect(context.treatment(experimentName)).toEqual(expectedVariants[experimentName]);
- expect(context.pending()).toEqual(1);
-
- const iteratedRefreshContextResponse = clone(getContextResponse);
- for (const experiment of iteratedRefreshContextResponse.experiments) {
- if (experiment.name === experimentName) {
- experiment.id = 11;
- experiment.trafficSeedHi = 54870830;
- experiment.trafficSeedHi = 398724581;
- experiment.seedHi = 77498863;
- experiment.seedHi = 34737352;
- }
- }
-
- provider.getContextData.mockReturnValue(Promise.resolve(iteratedRefreshContextResponse));
-
- context.refresh().then(() => {
- expect(context.treatment(experimentName)).toEqual(1);
- expect(context.pending()).toEqual(2); // exposure before the change + exposure after fullon
-
- done();
- });
- });
- });
-
- describe("peek()", () => {
- it("should not queue exposures", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
- expect(context.pending()).toEqual(0);
-
- for (const experiment of getContextResponse.experiments) {
- expect(context.peek(experiment.name)).toEqual(expectedVariants[experiment.name]);
- }
-
- expect(context.pending()).toEqual(0);
-
- done();
- });
-
- it("should return override variant", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
- expect(context.pending()).toEqual(0);
-
- for (const experiment of getContextResponse.experiments) {
- context.override(experiment.name, expectedVariants[experiment.name] + 11);
- }
- context.override("not_found", 3);
-
- for (const experiment of getContextResponse.experiments) {
- expect(context.peek(experiment.name)).toEqual(expectedVariants[experiment.name] + 11);
- }
-
- expect(context.peek("not_found")).toEqual(3);
-
- expect(context.pending()).toEqual(0);
-
- done();
- });
-
- it("should return assigned variant on audience mismatch in non-strict mode", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, audienceContextResponse);
-
- expect(context.peek("exp_test_ab")).toEqual(1);
-
- done();
- });
-
- it("should return control variant on audience mismatch in strict mode", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, audienceStrictContextResponse);
-
- expect(context.peek("exp_test_ab")).toEqual(0);
-
- done();
- });
-
- it("should re-evaluate audience expression when attributes change in strict mode", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, audienceStrictContextResponse);
-
- // First peek call without matching attribute should return control (0)
- expect(context.peek("exp_test_ab")).toEqual(0);
-
- // Set attribute that matches the audience filter (age >= 20)
- context.attribute("age", 25);
-
- // Second peek call should re-evaluate and return assigned variant (1)
- expect(context.peek("exp_test_ab")).toEqual(1);
-
- // peek() should not queue exposures
- expect(context.pending()).toEqual(0);
-
- done();
- });
-
- it("should re-evaluate audience expression when attributes change in non-strict mode", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, audienceContextResponse);
-
- // First peek call without matching attribute should return assigned variant (1)
- expect(context.peek("exp_test_ab")).toEqual(1);
-
- // Set attribute that matches the audience filter (age >= 20)
- context.attribute("age", 25);
-
- // Second peek call should re-evaluate and still return 1
- expect(context.peek("exp_test_ab")).toEqual(1);
-
- // peek() should not queue exposures
- expect(context.pending()).toEqual(0);
-
- done();
- });
-
- it("should not re-evaluate audience when no new attributes set", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, audienceStrictContextResponse);
-
- // Set attribute first
- context.attribute("age", 15);
-
- // First peek call with non-matching attribute should return control (0)
- expect(context.peek("exp_test_ab")).toEqual(0);
-
- // Second peek call without adding new attributes should use cached assignment
- expect(context.peek("exp_test_ab")).toEqual(0);
-
- // peek() should not queue exposures
- expect(context.pending()).toEqual(0);
-
- done();
- });
- });
-
- describe("treatment()", () => {
- it("should queue exposures", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
- expect(context.pending()).toEqual(0);
-
- for (const experiment of getContextResponse.experiments) {
- context.treatment(experiment.name);
- }
-
- expect(context.pending()).toEqual(getContextResponse.experiments.length);
-
- for (const experiment of getContextResponse.experiments) {
- context.treatment(experiment.name);
- }
-
- expect(context.pending()).toEqual(getContextResponse.experiments.length);
-
- publisher.publish.mockReturnValue(Promise.resolve());
-
- context.publish().then(() => {
- expect(publisher.publish).toHaveBeenCalledWith(
- {
- publishedAt: 1611141535729,
- units: publishUnits,
- hashed: true,
- sdkVersion: SDK_VERSION,
- exposures: [
- {
- id: 1,
- assigned: true,
- eligible: true,
- exposedAt: 1611141535729,
- name: "exp_test_ab",
- overridden: false,
- unit: "session_id",
- variant: 1,
- fullOn: false,
- custom: false,
- audienceMismatch: false,
- },
- {
- id: 2,
- assigned: true,
- eligible: true,
- exposedAt: 1611141535729,
- name: "exp_test_abc",
- overridden: false,
- unit: "session_id",
- variant: 2,
- fullOn: false,
- custom: false,
- audienceMismatch: false,
- },
- {
- id: 3,
- assigned: true,
- eligible: false,
- exposedAt: 1611141535729,
- name: "exp_test_not_eligible",
- overridden: false,
- unit: "user_id",
- variant: 0,
- fullOn: false,
- custom: false,
- audienceMismatch: false,
- },
- {
- id: 4,
- assigned: true,
- eligible: true,
- exposedAt: 1611141535729,
- name: "exp_test_fullon",
- overridden: false,
- unit: "session_id",
- variant: 2,
- fullOn: true,
- custom: false,
- audienceMismatch: false,
- },
- {
- id: 5,
- assigned: true,
- eligible: true,
- exposedAt: 1611141535729,
- name: "exp_test_custom_fields",
- overridden: false,
- unit: "session_id",
- variant: 1,
- fullOn: false,
- custom: false,
- audienceMismatch: false,
- },
- ],
- },
- sdk,
- context,
- undefined
- );
-
- done();
- });
- });
-
- it("should queue exposures after peek()", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
- expect(context.pending()).toEqual(0);
-
- for (const experiment of getContextResponse.experiments) {
- context.peek(experiment.name);
- }
-
- expect(context.pending()).toEqual(0);
-
- for (const experiment of getContextResponse.experiments) {
- context.treatment(experiment.name);
- }
-
- expect(context.pending()).toEqual(getContextResponse.experiments.length);
-
- done();
- });
-
- it("should queue exposures only once", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
- expect(context.pending()).toEqual(0);
-
- for (const experiment of getContextResponse.experiments) {
- context.treatment(experiment.name);
- }
-
- expect(context.pending()).toEqual(getContextResponse.experiments.length);
-
- for (const experiment of getContextResponse.experiments) {
- context.treatment(experiment.name);
- }
-
- expect(context.pending()).toEqual(getContextResponse.experiments.length);
-
- done();
- });
-
- it("should call event logger", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
- for (const experiment of getContextResponse.experiments) {
- SDK.defaultEventLogger.mockClear();
- context.treatment(experiment.name);
- expect(SDK.defaultEventLogger).toHaveBeenCalledTimes(1);
- expect(SDK.defaultEventLogger).toHaveBeenCalledWith(context, "exposure", {
- exposedAt: timeOrigin,
- eligible: experiment.name !== "exp_test_not_eligible",
- assigned: true,
- overridden: false,
- id: experiment.id,
- name: experiment.name,
- unit: experiment.unitType,
- variant: expectedVariants[experiment.name],
- fullOn: experiment.name === "exp_test_fullon",
- custom: false,
- audienceMismatch: false,
- });
- }
-
- // check it calls logger only once
- for (const experiment of getContextResponse.experiments) {
- SDK.defaultEventLogger.mockClear();
- context.treatment(experiment.name);
- expect(SDK.defaultEventLogger).not.toHaveBeenCalled();
- }
-
- done();
- });
-
- it("should queue exposure with base variant on unknown/stopped experiment", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
- expect(context.pending()).toEqual(0);
-
- expect(context.treatment("not_found")).toEqual(0);
-
- expect(context.pending()).toEqual(1);
-
- publisher.publish.mockReturnValue(Promise.resolve());
-
- context.publish().then(() => {
- expect(publisher.publish).toHaveBeenCalledWith(
- {
- publishedAt: 1611141535729,
- units: publishUnits,
- hashed: true,
- sdkVersion: SDK_VERSION,
- exposures: [
- {
- id: 0,
- assigned: false,
- eligible: true,
- exposedAt: 1611141535729,
- name: "not_found",
- overridden: false,
- unit: null,
- variant: 0,
- fullOn: false,
- custom: false,
- audienceMismatch: false,
- },
- ],
- },
- sdk,
- context,
- undefined
- );
-
- done();
- });
- });
-
- it("should queue exposure with audienceMatch true on audience match", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, audienceContextResponse);
- context.attribute("age", 21);
-
- expect(context.treatment("exp_test_ab")).toEqual(1);
-
- expect(context.pending()).toEqual(1);
-
- publisher.publish.mockReturnValue(Promise.resolve());
-
- context.publish().then(() => {
- expect(publisher.publish).toHaveBeenCalledWith(
- {
- publishedAt: 1611141535729,
- units: publishUnits,
- hashed: true,
- sdkVersion: SDK_VERSION,
- attributes: [
- {
- name: "age",
- setAt: 1611141535729,
- value: 21,
- },
- ],
- exposures: [
- {
- id: 1,
- assigned: true,
- eligible: true,
- exposedAt: 1611141535729,
- name: "exp_test_ab",
- overridden: false,
- unit: "session_id",
- variant: 1,
- fullOn: false,
- custom: false,
- audienceMismatch: false,
- },
- ],
- },
- sdk,
- context,
- undefined
- );
-
- done();
- });
- });
-
- it("should queue exposure with audienceMatch false on audience mismatch", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, audienceContextResponse);
-
- expect(context.treatment("exp_test_ab")).toEqual(1);
-
- expect(context.pending()).toEqual(1);
-
- publisher.publish.mockReturnValue(Promise.resolve());
-
- context.publish().then(() => {
- expect(publisher.publish).toHaveBeenCalledWith(
- {
- publishedAt: 1611141535729,
- units: publishUnits,
- hashed: true,
- sdkVersion: SDK_VERSION,
- exposures: [
- {
- id: 1,
- assigned: true,
- eligible: true,
- exposedAt: 1611141535729,
- name: "exp_test_ab",
- overridden: false,
- unit: "session_id",
- variant: 1,
- fullOn: false,
- custom: false,
- audienceMismatch: true,
- },
- ],
- },
- sdk,
- context,
- undefined
- );
-
- done();
- });
- });
-
- it("should queue exposure with audienceMatch false and control variant on audience mismatch in strict mode", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, audienceStrictContextResponse);
-
- expect(context.treatment("exp_test_ab")).toEqual(0);
-
- expect(context.pending()).toEqual(1);
-
- publisher.publish.mockReturnValue(Promise.resolve());
-
- context.publish().then(() => {
- expect(publisher.publish).toHaveBeenCalledWith(
- {
- publishedAt: 1611141535729,
- units: publishUnits,
- hashed: true,
- sdkVersion: SDK_VERSION,
- exposures: [
- {
- id: 1,
- assigned: false,
- eligible: true,
- exposedAt: 1611141535729,
- name: "exp_test_ab",
- overridden: false,
- unit: "session_id",
- variant: 0,
- fullOn: false,
- custom: false,
- audienceMismatch: true,
- },
- ],
- },
- sdk,
- context,
- undefined
- );
-
- done();
- });
- });
-
- it("should not re-queue exposure on unknown experiment", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
-
- expect(context.pending()).toEqual(0);
-
- expect(context.treatment("not_found")).toEqual(0);
-
- expect(context.pending()).toEqual(1);
-
- expect(context.treatment("not_found")).toEqual(0);
-
- expect(context.pending()).toEqual(1);
-
- done();
- });
-
- it("should queue exposure with override variant", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
- expect(context.pending()).toEqual(0);
-
- context.override("exp_test_ab", 5);
- context.override("not_found", 3);
-
- expect(context.treatment("exp_test_ab")).toEqual(5);
- expect(context.treatment("not_found")).toEqual(3);
-
- expect(context.pending()).toEqual(2);
-
- publisher.publish.mockReturnValue(Promise.resolve());
-
- context.publish().then(() => {
- expect(publisher.publish).toHaveBeenCalledWith(
- {
- publishedAt: 1611141535729,
- units: publishUnits,
- hashed: true,
- sdkVersion: SDK_VERSION,
- exposures: [
- {
- id: 1,
- assigned: false,
- eligible: true,
- exposedAt: 1611141535729,
- name: "exp_test_ab",
- overridden: true,
- unit: "session_id",
- variant: 5,
- fullOn: false,
- custom: false,
- audienceMismatch: false,
- },
- {
- id: 0,
- assigned: false,
- eligible: true,
- exposedAt: 1611141535729,
- name: "not_found",
- overridden: true,
- unit: null,
- variant: 3,
- fullOn: false,
- custom: false,
- audienceMismatch: false,
- },
- ],
- },
- sdk,
- context,
- undefined
- );
-
- done();
- });
- });
-
- it("should throw after finalized() call", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
- publisher.publish.mockReturnValue(Promise.resolve());
-
- context.treatment("exp_test_ab");
-
- expect(context.pending()).toEqual(1);
-
- context.finalize().then(() => {
- expect(() => context.treatment("exp_test_ab")).toThrow();
-
- done();
- });
-
- expect(context.isFinalizing()).toEqual(true);
- expect(() => context.treatment("exp_test_ab")).toThrow();
- });
-
- it("should re-evaluate audience expression when attributes change in strict mode", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, audienceStrictContextResponse);
-
- // First treatment call without matching attribute should return control (0)
- expect(context.treatment("exp_test_ab")).toEqual(0);
- expect(context.pending()).toEqual(1);
-
- // Set attribute that matches the audience filter (age >= 20)
- context.attribute("age", 25);
-
- // Second treatment call should re-evaluate and return assigned variant (1)
- expect(context.treatment("exp_test_ab")).toEqual(1);
-
- // Should queue another exposure
- expect(context.pending()).toEqual(2);
-
- done();
- });
-
- it("should re-evaluate audience expression when attributes change in non-strict mode", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, audienceContextResponse);
-
- // First treatment call without matching attribute should return assigned variant (1)
- // but with audienceMismatch = true
- expect(context.treatment("exp_test_ab")).toEqual(1);
- expect(context.pending()).toEqual(1);
-
- // Set attribute that matches the audience filter (age >= 20)
- context.attribute("age", 25);
-
- // Second treatment call should re-evaluate
- // The variant stays 1, but audienceMismatch should now be false
- expect(context.treatment("exp_test_ab")).toEqual(1);
-
- // Should queue another exposure since audience result changed
- expect(context.pending()).toEqual(2);
-
- done();
- });
-
- it("should not re-evaluate audience when no new attributes set", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, audienceStrictContextResponse);
-
- // Set attribute first
- context.attribute("age", 15);
-
- // First treatment call with non-matching attribute should return control (0)
- expect(context.treatment("exp_test_ab")).toEqual(0);
- expect(context.pending()).toEqual(1);
-
- // Second treatment call without adding new attributes should use cached assignment
- expect(context.treatment("exp_test_ab")).toEqual(0);
-
- // Should not queue another exposure (uses cached assignment)
- expect(context.pending()).toEqual(1);
-
- done();
- });
-
- it("should not re-evaluate audience for experiments without audience filter", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
-
- // First treatment call
- expect(context.treatment("exp_test_abc")).toEqual(2);
- expect(context.pending()).toEqual(1);
-
- // Set an attribute
- context.attribute("age", 25);
-
- // Second treatment call should use cached assignment since no audience filter
- expect(context.treatment("exp_test_abc")).toEqual(2);
-
- // Should not queue another exposure
- expect(context.pending()).toEqual(1);
-
- done();
- });
-
- it("should re-evaluate from audience mismatch to match in strict mode", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, audienceStrictContextResponse);
-
- // First treatment call without attribute - audience mismatch, returns 0
- expect(context.treatment("exp_test_ab")).toEqual(0);
- expect(context.pending()).toEqual(1);
-
- publisher.publish.mockReturnValue(Promise.resolve());
-
- context.publish().then(() => {
- // Verify first exposure had audienceMismatch = true
- expect(publisher.publish).toHaveBeenCalledWith(
- expect.objectContaining({
- exposures: [
- expect.objectContaining({
- name: "exp_test_ab",
- variant: 0,
- audienceMismatch: true,
- assigned: false,
- }),
- ],
- }),
- sdk,
- context,
- undefined
- );
-
- // Set matching attribute
- context.attribute("age", 30);
-
- // Second treatment should re-evaluate and return 1
- expect(context.treatment("exp_test_ab")).toEqual(1);
- expect(context.pending()).toEqual(1);
-
- context.publish().then(() => {
- // Verify second exposure had audienceMismatch = false
- expect(publisher.publish).toHaveBeenCalledWith(
- expect.objectContaining({
- exposures: [
- expect.objectContaining({
- name: "exp_test_ab",
- variant: 1,
- audienceMismatch: false,
- assigned: true,
- }),
- ],
- }),
- sdk,
- context,
- undefined
- );
-
- done();
- });
- });
- });
-
- it("should not re-evaluate when attribute set before assignment", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, audienceStrictContextResponse);
-
- // Set attribute before treatment call
- context.attribute("age", 25);
-
- // First treatment call - attribute was already set, included in assignment
- expect(context.treatment("exp_test_ab")).toEqual(1);
- expect(context.pending()).toEqual(1);
-
- // Second treatment call should use cached assignment
- expect(context.treatment("exp_test_ab")).toEqual(1);
-
- // Should not queue another exposure
- expect(context.pending()).toEqual(1);
-
- done();
- });
-
- it("should re-evaluate when attribute set after assignment", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, audienceStrictContextResponse);
-
- // First treatment call without attribute - audience mismatch, returns 0
- expect(context.treatment("exp_test_ab")).toEqual(0);
- expect(context.pending()).toEqual(1);
-
- // Set attribute AFTER assignment was computed
- context.attribute("age", 25);
-
- // Second treatment call should re-evaluate because attrsSeq increased
- expect(context.treatment("exp_test_ab")).toEqual(1);
-
- // Should queue another exposure
- expect(context.pending()).toEqual(2);
-
- done();
- });
-
- it("should not invalidate cache when audience result unchanged after attribute change", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, audienceStrictContextResponse);
-
- // Set attribute that doesn't match (age < 20)
- context.attribute("age", 15);
-
- // First treatment call - audience mismatch, returns 0
- expect(context.treatment("exp_test_ab")).toEqual(0);
- expect(context.pending()).toEqual(1);
-
- // Set another attribute that still doesn't match (age < 20)
- context.attribute("age", 18);
-
- // Second treatment call - audience result unchanged (still mismatch), should use cache
- expect(context.treatment("exp_test_ab")).toEqual(0);
-
- // Should NOT queue another exposure since audience result didn't change
- expect(context.pending()).toEqual(1);
-
- done();
- });
-
- it("should update attrsSeq after checking unchanged audience to avoid repeated evaluation", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, audienceStrictContextResponse);
-
- // Set attribute that doesn't match (age < 20)
- context.attribute("age", 15);
-
- // First treatment call - audience mismatch, returns 0
- expect(context.treatment("exp_test_ab")).toEqual(0);
- expect(context.pending()).toEqual(1);
-
- // Set another attribute that still doesn't match
- context.attribute("age", 16);
-
- // Second treatment - evaluates audience but result unchanged, updates attrsSeq
- expect(context.treatment("exp_test_ab")).toEqual(0);
- expect(context.pending()).toEqual(1);
-
- // Set yet another attribute that still doesn't match
- context.attribute("age", 17);
-
- // Third treatment - evaluates audience but result unchanged, updates attrsSeq
- expect(context.treatment("exp_test_ab")).toEqual(0);
- expect(context.pending()).toEqual(1);
-
- // No new attributes set
- // Fourth treatment - should use cache without re-evaluating
- expect(context.treatment("exp_test_ab")).toEqual(0);
- expect(context.pending()).toEqual(1);
-
- done();
- });
- });
-
- describe("variableValue()", () => {
- it("should not return variable values when unassigned", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, audienceStrictContextResponse);
-
- expect(context.pending()).toEqual(0);
-
- expect(context.variableValue("banner.size", 17)).toEqual(17);
-
- done();
- });
- it("should return variable values when overridden", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, audienceStrictContextResponse);
-
- expect(context.pending()).toEqual(0);
-
- context.override("exp_test_ab", 0);
-
- expect(context.variableValue("banner.size", 17)).toEqual("tiny");
-
- done();
- });
- it("conflicting key disjoint audiences", (done) => {
- const context1 = new Context(sdk, contextOptions, contextParams, disjointedContextResponse);
- const context2 = new Context(sdk, contextOptions, contextParams, disjointedContextResponse);
-
- expect(context1.pending()).toEqual(0);
- expect(context2.pending()).toEqual(0);
-
- expect(expectedVariants["exp_test_ab"]).not.toEqual(0);
- expect(expectedVariants["exp_test_abc"]).not.toEqual(0);
-
- context1.attribute("age", 20);
- expect(context1.variableValue("icon", "square")).toEqual("arrow");
-
- context2.attribute("age", 19);
- expect(context2.variableValue("icon", "square")).toEqual("circle");
-
- done();
- });
- it("should queue exposures", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
- expect(context.pending()).toEqual(0);
-
- const experiments = context.experiments();
-
- for (const [key, experimentNames] of Object.entries(variableExperiments)) {
- const experimentName = experimentNames[0];
- const actual = context.variableValue(key, 17);
- const eligible = experimentName !== "exp_test_not_eligible";
-
- if (eligible && experiments.indexOf(experimentName) !== -1) {
- expect(actual).toEqual(expectedVariables[key]);
- } else {
- expect(actual).toBe(17);
- }
- }
-
- expect(context.pending()).toEqual(getContextResponse.experiments.length);
-
- publisher.publish.mockReturnValue(Promise.resolve());
-
- context.publish().then(() => {
- expect(publisher.publish).toHaveBeenCalledWith(
- {
- publishedAt: 1611141535729,
- units: publishUnits,
- hashed: true,
- sdkVersion: SDK_VERSION,
- exposures: [
- {
- id: 1,
- assigned: true,
- eligible: true,
- exposedAt: 1611141535729,
- name: "exp_test_ab",
- overridden: false,
- unit: "session_id",
- variant: 1,
- fullOn: false,
- custom: false,
- audienceMismatch: false,
- },
- {
- id: 2,
- assigned: true,
- eligible: true,
- exposedAt: 1611141535729,
- name: "exp_test_abc",
- overridden: false,
- unit: "session_id",
- variant: 2,
- fullOn: false,
- custom: false,
- audienceMismatch: false,
- },
- {
- id: 3,
- assigned: true,
- eligible: false,
- exposedAt: 1611141535729,
- name: "exp_test_not_eligible",
- overridden: false,
- unit: "user_id",
- variant: 0,
- fullOn: false,
- custom: false,
- audienceMismatch: false,
- },
- {
- id: 4,
- assigned: true,
- eligible: true,
- exposedAt: 1611141535729,
- name: "exp_test_fullon",
- overridden: false,
- unit: "session_id",
- variant: 2,
- fullOn: true,
- custom: false,
- audienceMismatch: false,
- },
- {
- id: 5,
- assigned: true,
- eligible: true,
- exposedAt: 1611141535729,
- name: "exp_test_custom_fields",
- overridden: false,
- unit: "session_id",
- variant: 1,
- fullOn: false,
- custom: false,
- audienceMismatch: false,
- },
- ],
- },
- sdk,
- context,
- undefined
- );
-
- done();
- });
- });
-
- it("should queue exposures after peekVariable()", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
- expect(context.pending()).toEqual(0);
-
- const experiments = context.experiments();
-
- for (const [key, experimentNames] of Object.entries(variableExperiments)) {
- const experimentName = experimentNames[0];
- const actual = context.peekVariableValue(key, 17);
- const eligible = experimentName !== "exp_test_not_eligible";
-
- if (eligible && experiments.indexOf(experimentName) !== -1) {
- expect(actual).toEqual(expectedVariables[key]);
- } else {
- expect(actual).toBe(17);
- }
- }
-
- expect(context.pending()).toEqual(0);
-
- for (const [key, experimentNames] of Object.entries(variableExperiments)) {
- const experimentName = experimentNames[0];
- const actual = context.variableValue(key, 17);
- const eligible = experimentName !== "exp_test_not_eligible";
-
- if (eligible && experiments.indexOf(experimentName) !== -1) {
- expect(actual).toEqual(expectedVariables[key]);
- } else {
- expect(actual).toBe(17);
- }
- }
-
- expect(context.pending()).toEqual(getContextResponse.experiments.length);
-
- done();
- });
-
- it("should queue exposures only once", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
- expect(context.pending()).toEqual(0);
-
- const experiments = context.experiments();
-
- for (const [key, experimentNames] of Object.entries(variableExperiments)) {
- const experimentName = experimentNames[0];
- const actual = context.variableValue(key, 17);
- const eligible = experimentName !== "exp_test_not_eligible";
-
- if (eligible && experiments.indexOf(experimentName) !== -1) {
- expect(actual).toEqual(expectedVariables[key]);
- } else {
- expect(actual).toBe(17);
- }
- }
-
- expect(context.pending()).toEqual(getContextResponse.experiments.length);
-
- for (const [key, experimentNames] of Object.entries(variableExperiments)) {
- const experimentName = experimentNames[0];
- const actual = context.variableValue(key, 17);
- const eligible = experimentName !== "exp_test_not_eligible";
-
- if (eligible && experiments.indexOf(experimentName) !== -1) {
- expect(actual).toEqual(expectedVariables[key]);
- } else {
- expect(actual).toBe(17);
- }
- }
-
- expect(context.pending()).toEqual(getContextResponse.experiments.length);
-
- done();
- });
-
- it("should call event logger", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
- const experiments = context.experiments();
- const exposed = {};
-
- for (const [key, experimentNames] of Object.entries(variableExperiments)) {
- const experimentName = experimentNames[0];
- SDK.defaultEventLogger.mockClear();
- context.variableValue(key, 17);
-
- if (experiments.indexOf(experimentName) !== -1) {
- const experiment = getContextResponse.experiments.filter((x) => x.name === experimentName)[0];
- if (!(experimentName in exposed)) {
- exposed[experimentName] = true;
- expect(SDK.defaultEventLogger).toHaveBeenCalledTimes(1);
- expect(SDK.defaultEventLogger).toHaveBeenCalledWith(context, "exposure", {
- exposedAt: timeOrigin,
- eligible: experiment.name !== "exp_test_not_eligible",
- assigned: true,
- overridden: false,
- id: experiment.id,
- name: experiment.name,
- unit: experiment.unitType,
- variant: expectedVariants[experiment.name],
- fullOn: experiment.name === "exp_test_fullon",
- custom: false,
- audienceMismatch: false,
- });
- } else {
- expect(SDK.defaultEventLogger).not.toHaveBeenCalled();
- }
- }
- }
-
- // check it calls logger only once
- for (const [key, experimentNames] of Object.entries(variableExperiments)) {
- const experimentName = experimentNames[0];
- SDK.defaultEventLogger.mockClear();
- context.variableValue(key, 17);
- if (experiments.indexOf(experimentName) !== -1) {
- expect(SDK.defaultEventLogger).not.toHaveBeenCalled();
- }
- }
-
- done();
- });
-
- it("should return defaultValue on unknown variable", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
- expect(context.pending()).toEqual(0);
-
- expect(context.variableValue("not.found", 17)).toBe(17);
-
- done();
- });
-
- it("should queue exposure with audienceMatch true on audience match", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, audienceContextResponse);
- context.attribute("age", 21);
-
- expect(context.variableValue("banner.size", "small")).toEqual("large");
-
- expect(context.pending()).toEqual(1);
-
- publisher.publish.mockReturnValue(Promise.resolve());
-
- context.publish().then(() => {
- expect(publisher.publish).toHaveBeenCalledWith(
- {
- publishedAt: 1611141535729,
- units: publishUnits,
- hashed: true,
- sdkVersion: SDK_VERSION,
- attributes: [
- {
- name: "age",
- setAt: 1611141535729,
- value: 21,
- },
- ],
- exposures: [
- {
- id: 1,
- assigned: true,
- eligible: true,
- exposedAt: 1611141535729,
- name: "exp_test_ab",
- overridden: false,
- unit: "session_id",
- variant: 1,
- fullOn: false,
- custom: false,
- audienceMismatch: false,
- },
- ],
- },
- sdk,
- context,
- undefined
- );
-
- done();
- });
- });
-
- it("should queue exposure with audienceMatch false on audience mismatch", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, audienceContextResponse);
-
- expect(context.variableValue("banner.size", "small")).toEqual("large");
-
- expect(context.pending()).toEqual(1);
-
- publisher.publish.mockReturnValue(Promise.resolve());
-
- context.publish().then(() => {
- expect(publisher.publish).toHaveBeenCalledWith(
- {
- publishedAt: 1611141535729,
- units: publishUnits,
- hashed: true,
- sdkVersion: SDK_VERSION,
- exposures: [
- {
- id: 1,
- assigned: true,
- eligible: true,
- exposedAt: 1611141535729,
- name: "exp_test_ab",
- overridden: false,
- unit: "session_id",
- variant: 1,
- fullOn: false,
- custom: false,
- audienceMismatch: true,
- },
- ],
- },
- sdk,
- context,
- undefined
- );
-
- done();
- });
- });
-
- it("should queue exposure with audienceMatch false and control variant on audience mismatch in strict mode", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, audienceStrictContextResponse);
-
- expect(context.variableValue("banner.size", "small")).toEqual("small");
-
- expect(context.pending()).toEqual(1);
-
- publisher.publish.mockReturnValue(Promise.resolve());
-
- context.publish().then(() => {
- expect(publisher.publish).toHaveBeenCalledWith(
- {
- publishedAt: 1611141535729,
- units: publishUnits,
- hashed: true,
- sdkVersion: SDK_VERSION,
- exposures: [
- {
- id: 1,
- assigned: false,
- eligible: true,
- exposedAt: 1611141535729,
- name: "exp_test_ab",
- overridden: false,
- unit: "session_id",
- variant: 0,
- fullOn: false,
- custom: false,
- audienceMismatch: true,
- },
- ],
- },
- sdk,
- context,
- undefined
- );
-
- done();
- });
- });
-
- it("should throw after finalized() call", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
- publisher.publish.mockReturnValue(Promise.resolve());
-
- context.variableValue("button.color", 17);
-
- expect(context.pending()).toEqual(1);
-
- context.finalize().then(() => {
- expect(() => context.variableValue("button.color", 17)).toThrow();
-
- done();
- });
-
- expect(context.isFinalizing()).toEqual(true);
- expect(() => context.variableValue("button.color", 17)).toThrow();
- });
- });
-
- describe("peekVariableValue()", () => {
- it("should not return variable values when unassigned", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, audienceStrictContextResponse);
-
- expect(context.pending()).toEqual(0);
-
- expect(context.peekVariableValue("banner.size", 17)).toEqual(17);
-
- done();
- });
- it("should return variable values when overridden", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, audienceStrictContextResponse);
-
- expect(context.pending()).toEqual(0);
-
- context.override("exp_test_ab", 0);
-
- expect(context.peekVariableValue("banner.size", 17)).toEqual("tiny");
-
- done();
- });
- it("conflicting key disjoint audiences", (done) => {
- const context1 = new Context(sdk, contextOptions, contextParams, disjointedContextResponse);
- const context2 = new Context(sdk, contextOptions, contextParams, disjointedContextResponse);
-
- expect(context1.pending()).toEqual(0);
- expect(context2.pending()).toEqual(0);
-
- expect(expectedVariants["exp_test_ab"]).not.toEqual(0);
- expect(expectedVariants["exp_test_abc"]).not.toEqual(0);
-
- context1.attribute("age", 20);
- expect(context1.peekVariableValue("icon", "square")).toEqual("arrow");
-
- context2.attribute("age", 19);
- expect(context2.peekVariableValue("icon", "square")).toEqual("circle");
-
- expect(context1.pending()).toEqual(0);
- expect(context2.pending()).toEqual(0);
-
- done();
- });
-
- it("should pick lowest experiment id on conflicting key", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, lowestIdConflictingKeyContextResponse);
-
- expect(context.pending()).toEqual(0);
-
- expect(expectedVariants["exp_test_ab"]).not.toEqual(0);
- expect(expectedVariants["exp_test_abc"]).not.toEqual(0);
-
- expect(context.peekVariableValue("icon", "square")).toEqual("circle");
-
- done();
- });
-
- it("should not queue exposures", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
- expect(context.pending()).toEqual(0);
-
- const experiments = context.experiments();
-
- for (const [key, experimentNames] of Object.entries(variableExperiments)) {
- const experimentName = experimentNames[0];
- const actual = context.peekVariableValue(key, 17);
- const eligible = experimentName !== "exp_test_not_eligible";
-
- if (eligible && experiments.indexOf(experimentName) !== -1) {
- expect(actual).toEqual(expectedVariables[key]);
- } else {
- expect(actual).toBe(17);
- }
- }
-
- expect(context.pending()).toEqual(0);
-
- done();
- });
-
- it("should return defaultValue on unknown override variant", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
- expect(context.pending()).toEqual(0);
-
- for (const experiment of getContextResponse.experiments) {
- context.override(experiment.name, expectedVariants[experiment.name] + 11);
- }
- context.override("not_found", 3);
-
- for (const key of Object.keys(variableExperiments)) {
- const actual = context.peekVariableValue(key, 17);
- expect(actual).toBe(17);
- }
-
- expect(context.pending()).toEqual(0);
-
- done();
- });
-
- it("should return assigned variant on audience mismatch in non-strict mode", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, audienceContextResponse);
-
- expect(context.peekVariableValue("banner.size", "small")).toEqual("large");
-
- done();
- });
-
- it("should return control variant on audience mismatch in strict mode", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, audienceStrictContextResponse);
-
- expect(context.peekVariableValue("banner.size", "small")).toEqual("small");
-
- done();
- });
- });
-
- describe("variableKeys()", () => {
- it("should return all active keys", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, refreshContextResponse);
- expect(context.pending()).toEqual(0);
-
- expect(context.variableKeys()).toMatchObject(variableExperiments);
-
- expect(context.pending()).toEqual(0);
-
- done();
- });
- });
-
- describe("track()", () => {
- it("should queue goals", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
- expect(context.pending()).toEqual(0);
-
- context.track("goal1", { amount: 125, hours: 245 });
- context.track("goal2", { tries: 7 });
-
- expect(context.pending()).toEqual(2);
-
- context.track("goal2", { tests: 12 });
-
- expect(context.pending()).toEqual(3);
-
- publisher.publish.mockReturnValue(Promise.resolve());
-
- context.publish().then(() => {
- expect(publisher.publish).toHaveBeenCalledWith(
- {
- publishedAt: 1611141535729,
- units: publishUnits,
- hashed: true,
- sdkVersion: SDK_VERSION,
- goals: [
- {
- achievedAt: 1611141535729,
- name: "goal1",
- properties: { amount: 125, hours: 245 },
- },
- {
- achievedAt: 1611141535729,
- name: "goal2",
- properties: { tries: 7 },
- },
- {
- achievedAt: 1611141535729,
- name: "goal2",
- properties: { tests: 12 },
- },
- ],
- },
- sdk,
- context,
- undefined
- );
-
- done();
- });
- });
-
- it("should call event logger", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
-
- SDK.defaultEventLogger.mockClear();
- context.track("goal1", { amount: 125, hours: 245 });
- expect(SDK.defaultEventLogger).toHaveBeenCalledTimes(1);
- expect(SDK.defaultEventLogger).toHaveBeenCalledWith(context, "goal", {
- achievedAt: timeOrigin,
- name: "goal1",
- properties: { amount: 125, hours: 245 },
- });
-
- done();
- });
-
- it("should not throw when goal property values are numbers or objects with number values", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
- expect(context.pending()).toEqual(0);
-
- expect(() => context.track("goal1", { test: { flt: 1.5, int: 2 } })).not.toThrowError();
- expect(() => context.track("goal1", { test: {} })).not.toThrowError();
- expect(() => context.track("goal1", { test: null })).not.toThrowError();
-
- expect(context.pending()).toEqual(3);
-
- done();
- });
-
- it("should not throw when goal properties is null or undefined", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
- expect(context.pending()).toEqual(0);
-
- expect(() => context.track("goal1")).not.toThrowError();
- expect(() => context.track("goal1", null)).not.toThrowError();
- expect(() => context.track("goal1", undefined)).not.toThrowError();
-
- expect(context.pending()).toEqual(3);
-
- done();
- });
-
- it("should throw when goal properties not object", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
- expect(context.pending()).toEqual(0);
-
- expect(() => context.track("goal1", 125.0)).toThrowError("Goal 'goal1' properties must be of type object.");
- expect(() => context.track("goal1", true)).toThrowError("Goal 'goal1' properties must be of type object.");
- expect(() => context.track("goal1", "testy")).toThrowError(
- "Goal 'goal1' properties must be of type object."
- );
- expect(() => context.track("goal1", [])).toThrowError("Goal 'goal1' properties must be of type object.");
-
- done();
- });
-
- it("should throw after finalized() call", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
- publisher.publish.mockReturnValue(Promise.resolve());
-
- context.treatment("exp_test_ab");
-
- expect(context.pending()).toEqual(1);
-
- context.finalize().then(() => {
- expect(() => context.track("payment", { amount: 125 })).toThrow();
-
- done();
- });
-
- expect(context.isFinalizing()).toEqual(true);
- expect(() => context.track("payment", { amount: 125 })).toThrow();
- });
-
- it("should queue when not ready", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, Promise.resolve(getContextResponse));
- expect(context.pending()).toEqual(0);
- expect(context.isReady()).toEqual(false);
-
- context.track("goal1", { amount: 125 });
-
- expect(context.pending()).toEqual(1);
- expect(context.isReady()).toEqual(false);
-
- context.ready().then(() => {
- expect(context.pending()).toEqual(1);
-
- done();
- });
- });
-
- it("should start timeout after ready if queue is not empty", (done) => {
- jest.useFakeTimers("legacy");
- jest.spyOn(global, "setTimeout");
-
- const publishDelay = 100;
- const context = new Context(
- sdk,
- Object.assign(contextOptions, { publishDelay }),
- contextParams,
- Promise.resolve(getContextResponse)
- );
-
- expect(context.isReady()).toEqual(false);
- expect(context.isFailed()).toEqual(false);
-
- jest.spyOn(Date, "now").mockImplementation(() => timeOrigin);
-
- context.track("goal1", { amount: 125 });
-
- expect(context.pending()).toEqual(1);
-
- context.ready().then(() => {
- expect(setTimeout).toHaveBeenCalledTimes(1);
- expect(setTimeout).toHaveBeenLastCalledWith(expect.anything(), publishDelay);
-
- jest.advanceTimersByTime(publishDelay - 1);
-
- expect(publisher.publish).not.toHaveBeenCalled();
-
- publisher.publish.mockReturnValue(Promise.resolve({}));
-
- jest.spyOn(Date, "now").mockImplementation(() => timeOrigin + 100);
-
- jest.advanceTimersByTime(2);
-
- expect(publisher.publish).toHaveBeenCalledTimes(1);
- expect(publisher.publish).toHaveBeenCalledWith(
- {
- publishedAt: 1611141535829,
- units: publishUnits,
- hashed: true,
- sdkVersion: SDK_VERSION,
- goals: [
- {
- name: "goal1",
- achievedAt: 1611141535729,
- properties: { amount: 125 },
- },
- ],
- },
- sdk,
- context,
- undefined
- );
-
- done();
- });
- });
- });
-
- describe("publish()", () => {
- it("should not call client publish when queue is empty", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
- expect(context.pending()).toEqual(0);
-
- publisher.publish.mockReturnValue(Promise.resolve());
-
- context.publish().then(() => {
- expect(publisher.publish).not.toHaveBeenCalled();
- done();
- });
- });
-
- it("should propagate client error message", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
- expect(context.pending()).toEqual(0);
-
- context.track("goal1", { amount: 125 });
-
- publisher.publish.mockReturnValue(Promise.reject("test"));
-
- context.publish().catch((e) => {
- expect(e).toEqual("test");
-
- done();
- });
- });
-
- it("should call client publish", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
-
- context.treatment("exp_test_ab");
- context.treatment("exp_test_not_eligible");
-
- Date.now.mockImplementation(() => timeOrigin + 1); // ensure that time is kept separately per event
- context.track("goal1", { amount: 125, hours: 245 });
-
- Date.now.mockImplementation(() => timeOrigin + 2);
- context.attribute("attr1", "value1");
-
- Date.now.mockImplementation(() => timeOrigin + 3);
- context.attributes({
- attr2: "value2",
- attr3: 3,
- attr4: 5.0,
- attr5: true,
- attr6: [1, 2, 3, 4],
- attr7: null,
- attr8: [],
- attr9: [null, 1, 2],
- attr10: ["one", null, "two"],
- attr11: [null, null],
- });
-
- expect(context.pending()).toEqual(3);
-
- publisher.publish.mockReturnValue(Promise.resolve());
-
- jest.spyOn(Date, "now").mockImplementation(() => timeOrigin + 100);
-
- context.publish().then(() => {
- expect(publisher.publish).toHaveBeenCalledTimes(1);
- expect(publisher.publish).toHaveBeenCalledWith(
- {
- publishedAt: 1611141535829,
- units: publishUnits,
- hashed: true,
- sdkVersion: SDK_VERSION,
- exposures: [
- {
- id: 1,
- name: "exp_test_ab",
- unit: "session_id",
- exposedAt: 1611141535729,
- variant: 1,
- assigned: true,
- eligible: true,
- overridden: false,
- fullOn: false,
- custom: false,
- audienceMismatch: false,
- },
- {
- id: 3,
- name: "exp_test_not_eligible",
- unit: "user_id",
- exposedAt: 1611141535729,
- variant: 0,
- assigned: true,
- eligible: false,
- overridden: false,
- fullOn: false,
- custom: false,
- audienceMismatch: false,
- },
- ],
- goals: [
- {
- name: "goal1",
- achievedAt: 1611141535730,
- properties: { amount: 125, hours: 245 },
- },
- ],
- attributes: [
- {
- name: "attr1",
- setAt: 1611141535731,
- value: "value1",
- },
- {
- name: "attr2",
- setAt: 1611141535732,
- value: "value2",
- },
- {
- name: "attr3",
- setAt: 1611141535732,
- value: 3,
- },
- {
- name: "attr4",
- setAt: 1611141535732,
- value: 5.0,
- },
- {
- name: "attr5",
- setAt: 1611141535732,
- value: true,
- },
- {
- name: "attr6",
- setAt: 1611141535732,
- value: [1, 2, 3, 4],
- },
- {
- name: "attr7",
- setAt: 1611141535732,
- value: null,
- },
- {
- name: "attr8",
- setAt: 1611141535732,
- value: [],
- },
- {
- name: "attr9",
- setAt: 1611141535732,
- value: [null, 1, 2],
- },
- {
- name: "attr10",
- setAt: 1611141535732,
- value: ["one", null, "two"],
- },
-
- {
- name: "attr11",
- setAt: 1611141535732,
- value: [null, null],
- },
- ],
- },
- sdk,
- context,
- undefined
- );
-
- expect(context.pending()).toEqual(0);
-
- done();
- });
- });
-
- it("should pass through request options", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
-
- context.track("goal1", { amount: 125, hours: 245 });
-
- publisher.publish.mockReturnValue(Promise.resolve());
-
- jest.spyOn(Date, "now").mockImplementation(() => timeOrigin + 100);
-
- context.publish({ timeout: 1234 }).then(() => {
- expect(publisher.publish).toHaveBeenCalledTimes(1);
- expect(publisher.publish).toHaveBeenCalledWith(
- {
- publishedAt: 1611141535829,
- units: publishUnits,
- hashed: true,
- sdkVersion: SDK_VERSION,
- goals: [
- {
- name: "goal1",
- achievedAt: 1611141535729,
- properties: { amount: 125, hours: 245 },
- },
- ],
- },
- sdk,
- context,
- {
- timeout: 1234,
- }
- );
-
- expect(context.pending()).toEqual(0);
-
- done();
- });
- });
-
- it("should call event logger on error", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
-
- context.track("goal1", { amount: 125, hours: 245 });
-
- publisher.publish.mockReturnValue(Promise.reject("test error"));
-
- SDK.defaultEventLogger.mockClear();
- context.publish().catch((error) => {
- expect(SDK.defaultEventLogger).toHaveBeenCalledTimes(1);
- expect(SDK.defaultEventLogger).toHaveBeenCalledWith(context, "error", error);
-
- done();
- });
- });
-
- it("should call event logger on success", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
-
- context.track("goal1", { amount: 125, hours: 245 });
-
- publisher.publish.mockReturnValue(Promise.resolve());
-
- jest.spyOn(Date, "now").mockImplementation(() => timeOrigin + 100);
-
- SDK.defaultEventLogger.mockClear();
- context.publish().then(() => {
- expect(SDK.defaultEventLogger).toHaveBeenCalledTimes(1);
- expect(SDK.defaultEventLogger).toHaveBeenCalledWith(context, "publish", {
- publishedAt: 1611141535829,
- units: publishUnits,
- hashed: true,
- sdkVersion: SDK_VERSION,
- goals: [
- {
- achievedAt: 1611141535729,
- name: "goal1",
- properties: { amount: 125, hours: 245 },
- },
- ],
- });
-
- done();
- });
- });
-
- it("should not call client publish when failed", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, Promise.reject("bad request error text"));
- context.ready().then(() => {
- context.treatment("exp_test_ab");
-
- Date.now.mockImplementation(() => timeOrigin + 1); // ensure that time is kept separately per event
- context.track("goal1", { amount: 125, hours: 245 });
-
- expect(context.pending()).toEqual(2);
-
- context.publish().then(() => {
- expect(publisher.publish).not.toHaveBeenCalled();
- expect(context.pending()).toEqual(0);
-
- done();
- });
- });
- });
-
- it("should reset internal queues and keep attributes overrides and custom assignments", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
-
- context.treatment("exp_test_ab");
- context.track("goal1", { amount: 125, hours: 245 });
- context.attribute("attr1", "value1");
-
- context.override("not_found", 3);
- expect(context.treatment("not_found")).toEqual(3);
-
- context.customAssignment("exp_test_abc", 3);
- expect(context.treatment("exp_test_abc")).toEqual(3);
-
- expect(context.pending()).toEqual(4);
-
- publisher.publish.mockReturnValue(Promise.resolve({}));
-
- jest.spyOn(Date, "now").mockImplementation(() => timeOrigin + 100);
-
- context
- .publish()
- .then(() => {
- expect(publisher.publish).toHaveBeenCalledTimes(1);
- expect(publisher.publish).toHaveBeenCalledWith(
- {
- publishedAt: 1611141535829,
- units: publishUnits,
- hashed: true,
- sdkVersion: SDK_VERSION,
- exposures: [
- {
- id: 1,
- name: "exp_test_ab",
- unit: "session_id",
- exposedAt: 1611141535729,
- variant: 1,
- assigned: true,
- eligible: true,
- overridden: false,
- fullOn: false,
- custom: false,
- audienceMismatch: false,
- },
- {
- id: 0,
- name: "not_found",
- unit: null,
- exposedAt: 1611141535729,
- variant: 3,
- assigned: false,
- eligible: true,
- overridden: true,
- fullOn: false,
- custom: false,
- audienceMismatch: false,
- },
- {
- id: 2,
- name: "exp_test_abc",
- unit: "session_id",
- exposedAt: 1611141535729,
- variant: 3,
- assigned: true,
- eligible: true,
- overridden: false,
- fullOn: false,
- custom: true,
- audienceMismatch: false,
- },
- ],
- goals: [
- {
- name: "goal1",
- achievedAt: 1611141535729,
- properties: { amount: 125, hours: 245 },
- },
- ],
- attributes: [
- {
- name: "attr1",
- setAt: 1611141535729,
- value: "value1",
- },
- ],
- },
- sdk,
- context,
- undefined
- );
-
- expect(context.pending()).toEqual(0);
-
- publisher.publish.mockClear();
- })
- .then(() => {
- context.track("goal2", { test: 999 });
-
- return context.publish();
- })
- .then(() => {
- expect(publisher.publish).toHaveBeenCalledTimes(1);
- expect(publisher.publish).toHaveBeenCalledWith(
- {
- publishedAt: 1611141535829,
- units: publishUnits,
- hashed: true,
- sdkVersion: SDK_VERSION,
- goals: [
- {
- name: "goal2",
- achievedAt: 1611141535829,
- properties: { test: 999 },
- },
- ],
- attributes: [
- {
- name: "attr1",
- setAt: 1611141535729,
- value: "value1",
- },
- ],
- },
- sdk,
- context,
- undefined
- );
-
- expect(context.pending()).toEqual(0);
-
- expect(context.treatment("exp_test_abc")).toEqual(3);
- expect(context.treatment("not_found")).toEqual(3);
-
- expect(context.pending()).toEqual(0);
-
- done();
- });
- });
-
- it("should be called options.publishDelay ms after an exposure being queued", () => {
- jest.useFakeTimers("legacy");
- jest.spyOn(global, "setTimeout");
-
- const publishDelay = 100;
- const context = new Context(
- sdk,
- Object.assign(contextOptions, { publishDelay }),
- contextParams,
- getContextResponse
- );
-
- expect(context.isReady()).toEqual(true);
- expect(context.isFailed()).toEqual(false);
-
- context.treatment("exp_test_ab");
-
- expect(context.pending()).toEqual(1);
- expect(setTimeout).toHaveBeenCalledTimes(1);
- expect(setTimeout).toHaveBeenLastCalledWith(expect.anything(), publishDelay);
-
- context.track("goal1", { amount: 125 });
-
- expect(context.pending()).toEqual(2);
- expect(setTimeout).toHaveBeenCalledTimes(1); // no new calls
- expect(setTimeout).toHaveBeenLastCalledWith(expect.anything(), publishDelay);
-
- jest.advanceTimersByTime(publishDelay - 1);
-
- expect(publisher.publish).not.toHaveBeenCalled();
-
- publisher.publish.mockReturnValue(Promise.resolve({}));
-
- jest.advanceTimersByTime(2);
-
- expect(publisher.publish).toHaveBeenCalledTimes(1);
- });
-
- it("should be called options.publishDelay ms after a goal being queued", () => {
- jest.useFakeTimers("legacy");
- jest.spyOn(global, "setTimeout");
-
- const publishDelay = 100;
- const context = new Context(
- sdk,
- Object.assign(contextOptions, { publishDelay }),
- contextParams,
- getContextResponse
- );
-
- expect(context.isReady()).toEqual(true);
- expect(context.isFailed()).toEqual(false);
-
- context.track("goal1", { amount: 125 });
-
- expect(context.pending()).toEqual(1);
- expect(setTimeout).toHaveBeenCalledTimes(1);
- expect(setTimeout).toHaveBeenLastCalledWith(expect.anything(), publishDelay);
-
- context.treatment("exp_test_ab");
-
- expect(context.pending()).toEqual(2);
- expect(setTimeout).toHaveBeenCalledTimes(1); // no new calls
- expect(setTimeout).toHaveBeenLastCalledWith(expect.anything(), publishDelay);
-
- jest.advanceTimersByTime(publishDelay - 1);
-
- expect(publisher.publish).not.toHaveBeenCalled();
-
- publisher.publish.mockReturnValue(Promise.resolve({}));
-
- jest.advanceTimersByTime(2);
-
- expect(publisher.publish).toHaveBeenCalledTimes(1);
- });
-
- it("should throw after finalized() call", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
- publisher.publish.mockReturnValue(Promise.resolve());
-
- context.treatment("exp_test_ab");
-
- expect(context.pending()).toEqual(1);
-
- context.finalize().then(() => {
- expect(() => context.publish()).toThrow();
-
- done();
- });
-
- expect(context.isFinalizing()).toEqual(true);
- expect(() => context.publish()).toThrow();
- });
- });
-
- describe("finalize()", () => {
- it("should not call client publish when queue is empty", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
- expect(context.pending()).toEqual(0);
-
- publisher.publish.mockReturnValue(Promise.resolve());
-
- context.finalize().then(() => {
- expect(publisher.publish).not.toHaveBeenCalled();
- expect(context.isFinalizing()).toEqual(false);
- expect(context.isFinalized()).toEqual(true);
- done();
- });
-
- expect(context.isFinalizing()).toEqual(false);
- expect(context.isFinalized()).toEqual(true);
- });
-
- it("should propagate client error message", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
- expect(context.pending()).toEqual(0);
-
- context.treatment("exp_test_ab");
-
- publisher.publish.mockReturnValue(Promise.reject("test"));
-
- context.finalize().catch((e) => {
- expect(e).toEqual("test");
- expect(context.isFinalizing()).toEqual(false);
- expect(context.isFinalized()).toEqual(false);
-
- done();
- });
-
- expect(context.isFinalizing()).toEqual(true);
- expect(context.isFinalized()).toEqual(false);
- });
-
- it("should call client publish", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
-
- context.treatment("exp_test_ab");
-
- expect(context.pending()).toEqual(1);
-
- publisher.publish.mockReturnValue(Promise.resolve());
-
- jest.spyOn(Date, "now").mockImplementation(() => timeOrigin + 100);
-
- context.finalize().then(() => {
- expect(publisher.publish).toHaveBeenCalledTimes(1);
- expect(publisher.publish).toHaveBeenCalledWith(
- {
- publishedAt: 1611141535829,
- units: publishUnits,
- hashed: true,
- sdkVersion: SDK_VERSION,
- exposures: [
- {
- id: 1,
- name: "exp_test_ab",
- unit: "session_id",
- exposedAt: 1611141535729,
- variant: 1,
- assigned: true,
- eligible: true,
- overridden: false,
- fullOn: false,
- custom: false,
- audienceMismatch: false,
- },
- ],
- },
- sdk,
- context,
- undefined
- );
-
- expect(context.pending()).toEqual(0);
- expect(context.isFinalizing()).toEqual(false);
- expect(context.isFinalized()).toEqual(true);
-
- done();
- });
-
- expect(context.isFinalizing()).toEqual(true);
- expect(context.isFinalized()).toEqual(false);
- });
-
- it("should pass through request options", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
-
- context.treatment("exp_test_ab");
-
- expect(context.pending()).toEqual(1);
-
- publisher.publish.mockReturnValue(Promise.resolve());
-
- jest.spyOn(Date, "now").mockImplementation(() => timeOrigin + 100);
-
- context.finalize({ timeout: 1234 }).then(() => {
- expect(publisher.publish).toHaveBeenCalledTimes(1);
- expect(publisher.publish).toHaveBeenCalledWith(
- {
- publishedAt: 1611141535829,
- units: publishUnits,
- hashed: true,
- sdkVersion: SDK_VERSION,
- exposures: [
- {
- id: 1,
- name: "exp_test_ab",
- unit: "session_id",
- exposedAt: 1611141535729,
- variant: 1,
- assigned: true,
- eligible: true,
- overridden: false,
- fullOn: false,
- custom: false,
- audienceMismatch: false,
- },
- ],
- },
- sdk,
- context,
- { timeout: 1234 }
- );
-
- expect(context.pending()).toEqual(0);
- expect(context.isFinalizing()).toEqual(false);
- expect(context.isFinalized()).toEqual(true);
-
- done();
- });
-
- expect(context.isFinalizing()).toEqual(true);
- expect(context.isFinalized()).toEqual(false);
- });
-
- it("should call event logger on error", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
-
- context.treatment("exp_test_ab");
-
- publisher.publish.mockReturnValue(Promise.reject("test error"));
-
- SDK.defaultEventLogger.mockClear();
- context.finalize().catch((error) => {
- expect(SDK.defaultEventLogger).toHaveBeenCalledTimes(1);
- expect(SDK.defaultEventLogger).toHaveBeenCalledWith(context, "error", error);
- expect(context.isFinalizing()).toEqual(false);
- expect(context.isFinalized()).toEqual(false);
-
- done();
- });
-
- expect(context.isFinalizing()).toEqual(true);
- expect(context.isFinalized()).toEqual(false);
- });
-
- it("should call event logger on success", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
-
- context.treatment("exp_test_ab");
-
- publisher.publish.mockReturnValue(Promise.resolve());
-
- SDK.defaultEventLogger.mockClear();
- context.finalize().then(() => {
- expect(SDK.defaultEventLogger).toHaveBeenCalledTimes(2);
- expect(SDK.defaultEventLogger).toHaveBeenLastCalledWith(context, "finalize", undefined);
- expect(context.isFinalizing()).toEqual(false);
- expect(context.isFinalized()).toEqual(true);
-
- done();
- });
-
- expect(context.isFinalizing()).toEqual(true);
- expect(context.isFinalized()).toEqual(false);
- });
-
- it("should not call client publish when failed", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, Promise.reject("bad request error text"));
- context.ready().then(() => {
- context.treatment("exp_test_ab");
-
- expect(context.pending()).toEqual(1);
-
- context.finalize().then(() => {
- expect(publisher.publish).not.toHaveBeenCalled();
- expect(context.pending()).toEqual(0);
- expect(context.isFinalizing()).toEqual(false);
- expect(context.isFinalized()).toEqual(true);
-
- done();
- });
-
- expect(context.isFinalizing()).toEqual(false);
- expect(context.isFinalized()).toEqual(true);
- });
- });
-
- it("should return current promise when called twice", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
-
- context.treatment("exp_test_ab");
-
- publisher.publish.mockReturnValue(Promise.resolve());
-
- const firstPromise = context.finalize();
- const secondPromise = context.finalize();
-
- expect(secondPromise).toBe(firstPromise);
-
- secondPromise.then(() => {
- expect(context.isFinalizing()).toEqual(false);
- expect(context.isFinalized()).toEqual(true);
-
- done();
- });
-
- expect(context.isFinalizing()).toEqual(true);
- expect(context.isFinalized()).toEqual(false);
- });
-
- it("should return completed promise when already finalized", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
-
- context.treatment("exp_test_ab");
-
- publisher.publish.mockReturnValue(Promise.resolve());
-
- context.finalize().then(() => {
- expect(context.isFinalizing()).toEqual(false);
- expect(context.isFinalized()).toEqual(true);
-
- context.finalize().then(() => {
- done();
- });
- });
- });
-
- it("should cancel refresh timer", (done) => {
- jest.useFakeTimers("legacy");
- jest.spyOn(global, "setInterval");
- jest.spyOn(global, "clearInterval");
-
- const refreshPeriod = 1000;
- const context = new Context(
- sdk,
- Object.assign(contextOptions, { refreshPeriod }),
- contextParams,
- getContextResponse
- );
-
- expect(context.isReady()).toEqual(true);
- expect(context.isFailed()).toEqual(false);
-
- expect(setInterval).toHaveBeenCalledTimes(1);
- expect(setInterval).toHaveBeenCalledWith(expect.anything(), refreshPeriod);
- const timerId = setInterval.mock.results[0].value;
-
- context.finalize().then(() => {
- expect(context.isFinalizing()).toEqual(false);
- expect(context.isFinalized()).toEqual(true);
-
- expect(clearInterval).toHaveBeenCalledTimes(1);
- expect(clearInterval).toHaveBeenCalledWith(timerId);
-
- done();
- });
- });
- });
-
- describe("override()", () => {
- it("should be callable before ready()", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, Promise.resolve(getContextResponse));
- expect(context.isReady()).toEqual(false);
- expect(context.isFailed()).toEqual(false);
- expect(context.isFinalized()).toEqual(false);
-
- context.override("exp_test_ab", 1);
- context.overrides({
- exp_test_ab: 2,
- exp_test_abc: 2,
- not_found: 3,
- });
-
- context.ready().then(() => {
- expect(context.isReady()).toEqual(true);
- expect(context.data()).toStrictEqual(getContextResponse);
-
- context.treatment("exp_test_ab");
- context.treatment("exp_test_abc");
-
- publisher.publish.mockReturnValue(Promise.resolve());
-
- jest.spyOn(Date, "now").mockImplementation(() => timeOrigin + 100);
-
- context.publish().then(() => {
- expect(publisher.publish).toHaveBeenCalledTimes(1);
- expect(publisher.publish).toHaveBeenCalledWith(
- {
- publishedAt: 1611141535829,
- units: publishUnits,
- hashed: true,
- sdkVersion: SDK_VERSION,
- exposures: [
- {
- id: 1,
- name: "exp_test_ab",
- unit: "session_id",
- exposedAt: 1611141535729,
- variant: 2,
- assigned: false,
- eligible: true,
- overridden: true,
- fullOn: false,
- custom: false,
- audienceMismatch: false,
- },
- {
- id: 2,
- name: "exp_test_abc",
- unit: "session_id",
- exposedAt: 1611141535729,
- variant: 2,
- assigned: false,
- eligible: true,
- overridden: true,
- fullOn: false,
- custom: false,
- audienceMismatch: false,
- },
- ],
- },
- sdk,
- context,
- undefined
- );
-
- done();
- });
- });
- });
- });
-
- describe("customAssignment()", () => {
- it("should override natural assignment and set custom flag", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
- expect(context.pending()).toEqual(0);
-
- context.customAssignment("exp_test_abc", 11);
-
- expect(context.pending()).toEqual(0); // should not queue exposures
-
- context.treatment("exp_test_abc");
-
- expect(context.pending()).toEqual(1);
-
- publisher.publish.mockReturnValue(Promise.resolve());
-
- context.publish().then(() => {
- expect(publisher.publish).toHaveBeenCalledWith(
- {
- publishedAt: 1611141535729,
- units: publishUnits,
- hashed: true,
- sdkVersion: SDK_VERSION,
- exposures: [
- {
- id: 2,
- assigned: true,
- eligible: true,
- exposedAt: 1611141535729,
- name: "exp_test_abc",
- overridden: false,
- unit: "session_id",
- variant: 11,
- fullOn: false,
- custom: true,
- audienceMismatch: false,
- },
- ],
- },
- sdk,
- context,
- undefined
- );
-
- done();
- });
- });
-
- it("should not override full-on or non-eligible assignment", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
- expect(context.pending()).toEqual(0);
-
- context.customAssignment("exp_test_not_eligible", 11);
- context.customAssignment("exp_test_fullon", 11);
-
- expect(context.pending()).toEqual(0); // should not queue exposures
-
- context.treatment("exp_test_not_eligible");
- context.treatment("exp_test_fullon");
-
- expect(context.pending()).toEqual(2);
-
- publisher.publish.mockReturnValue(Promise.resolve());
-
- context.publish().then(() => {
- expect(publisher.publish).toHaveBeenCalledWith(
- {
- publishedAt: 1611141535729,
- units: publishUnits,
- hashed: true,
- sdkVersion: SDK_VERSION,
- exposures: [
- {
- id: 3,
- assigned: true,
- eligible: false,
- exposedAt: 1611141535729,
- name: "exp_test_not_eligible",
- overridden: false,
- unit: "user_id",
- variant: 0,
- fullOn: false,
- custom: false,
- audienceMismatch: false,
- },
- {
- id: 4,
- assigned: true,
- eligible: true,
- exposedAt: 1611141535729,
- name: "exp_test_fullon",
- overridden: false,
- unit: "session_id",
- variant: 2,
- fullOn: true,
- custom: false,
- audienceMismatch: false,
- },
- ],
- },
- sdk,
- context,
- undefined
- );
-
- done();
- });
- });
-
- it("should be callable before ready()", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, Promise.resolve(getContextResponse));
- expect(context.isReady()).toEqual(false);
- expect(context.isFailed()).toEqual(false);
- expect(context.isFinalized()).toEqual(false);
-
- context.customAssignment("exp_test_ab", 1);
- context.customAssignments({
- exp_test_ab: 2,
- exp_test_abc: 2,
- not_found: 3,
- });
-
- context.ready().then(() => {
- expect(context.isReady()).toEqual(true);
- expect(context.data()).toStrictEqual(getContextResponse);
-
- context.treatment("exp_test_ab");
- context.treatment("exp_test_abc");
-
- publisher.publish.mockReturnValue(Promise.resolve());
-
- jest.spyOn(Date, "now").mockImplementation(() => timeOrigin + 100);
-
- context.publish().then(() => {
- expect(publisher.publish).toHaveBeenCalledTimes(1);
- expect(publisher.publish).toHaveBeenCalledWith(
- {
- publishedAt: 1611141535829,
- units: publishUnits,
- hashed: true,
- sdkVersion: SDK_VERSION,
- exposures: [
- {
- id: 1,
- name: "exp_test_ab",
- unit: "session_id",
- exposedAt: 1611141535729,
- variant: 2,
- assigned: true,
- eligible: true,
- overridden: false,
- fullOn: false,
- custom: true,
- audienceMismatch: false,
- },
- {
- id: 2,
- name: "exp_test_abc",
- unit: "session_id",
- exposedAt: 1611141535729,
- variant: 2,
- assigned: true,
- eligible: true,
- overridden: false,
- fullOn: false,
- custom: true,
- audienceMismatch: false,
- },
- ],
- },
- sdk,
- context,
- undefined
- );
-
- done();
- });
- });
- });
-
- it("should throw after finalized() call", (done) => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
- publisher.publish.mockReturnValue(Promise.resolve());
-
- context.treatment("exp_test_ab");
-
- expect(context.pending()).toEqual(1);
-
- context.finalize().then(() => {
- expect(() => context.customAssignment("exp_test_ab", 3)).toThrow(); // finalizing
-
- done();
- });
-
- expect(context.isFinalizing()).toEqual(true);
- expect(() => context.customAssignment("exp_test_ab", 3)).toThrow(); // finalizing
- });
- });
- describe("customFieldKeys()", () => {
- it("should return custom field keys", () => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
- expect(context.pending()).toEqual(0);
- const keys = context.customFieldKeys();
-
- expect(context.isReady()).toEqual(true);
- expect(keys).toEqual([
- "country",
- "json_object",
- "json_array",
- "json_number",
- "json_string",
- "json_boolean",
- "json_null",
- "json_invalid",
- "languages",
- "text_field",
- "string_field",
- "number_field",
- "boolean_field",
- "false_boolean_field",
- "invalid_type_field",
- ]);
- });
- });
-
- describe("customFieldValue()", () => {
- it("should return custom field value", () => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
- expect(context.pending()).toEqual(0);
- const value = context.customFieldValue("exp_test_custom_fields", "country");
-
- expect(context.isReady()).toEqual(true);
- expect(value).toEqual("US,PT,ES");
- });
-
- it("should return parsed JSON fields", () => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
- expect(context.pending()).toEqual(0);
-
- expect(context.customFieldValue("exp_test_abc", "json_object")).toEqual({ 123: 1, 456: 0 });
- expect(context.customFieldValue("exp_test_abc", "json_array")).toEqual(["hello", "world"]);
- expect(context.customFieldValue("exp_test_abc", "json_number")).toEqual(123);
- expect(context.customFieldValue("exp_test_abc", "json_string")).toEqual("hello");
- expect(context.customFieldValue("exp_test_abc", "json_boolean")).toEqual(true);
- expect(context.customFieldValue("exp_test_abc", "json_null")).toEqual(null);
- });
-
- it("should return string and text fields", () => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
- expect(context.pending()).toEqual(0);
-
- expect(context.customFieldValue("exp_test_custom_fields", "text_field")).toEqual("hello text");
- expect(context.customFieldValue("exp_test_custom_fields", "string_field")).toEqual("hello string");
- });
-
- it("should return parsed number fields", () => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
- expect(context.pending()).toEqual(0);
-
- expect(context.customFieldValue("exp_test_custom_fields", "number_field")).toEqual(123);
- });
-
- it("should return parsed boolean fields", () => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
- expect(context.pending()).toEqual(0);
-
- expect(context.customFieldValue("exp_test_custom_fields", "boolean_field")).toEqual(true);
- expect(context.customFieldValue("exp_test_custom_fields", "false_boolean_field")).toEqual(false);
- });
-
- it("should console an error when JSON cannot be parsed", () => {
- const errorSpy = jest.spyOn(console, "error");
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
- expect(context.pending()).toEqual(0);
-
- expect(context.customFieldValue("exp_test_abc", "json_invalid")).toEqual(null);
- expect(errorSpy).toHaveBeenCalledTimes(1);
- expect(errorSpy).toHaveBeenCalledWith(
- "Failed to parse JSON custom field value 'json_invalid' for experiment 'exp_test_abc'"
- );
- });
-
- it("should console an error when a field type is invalid", () => {
- const errorSpy = jest.spyOn(console, "error");
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
- expect(context.pending()).toEqual(0);
-
- expect(context.customFieldValue("exp_test_custom_fields", "invalid_type_field")).toEqual(null);
- expect(errorSpy).toHaveBeenCalledTimes(1);
- expect(errorSpy).toHaveBeenCalledWith(
- "Unknown custom field type 'invalid' for experiment 'exp_test_custom_fields' and key 'invalid_type_field' - you may need to upgrade to the latest SDK version"
- );
- });
- });
-
- describe("customFieldValueType()", () => {
- it("should return custom field value type", () => {
- const context = new Context(sdk, contextOptions, contextParams, getContextResponse);
- expect(context.pending()).toEqual(0);
- const value = context.customFieldValueType("exp_test_custom_fields", "country");
-
- expect(context.isReady()).toEqual(true);
- expect(value).toEqual("string");
- });
- });
-
- describe("includeSystemAttributes", () => {
- it("should not include system attributes by default", (done) => {
- const defaultOptions = {
- publishDelay: -1,
- refreshPeriod: 0,
- };
-
- const context = new Context(sdk, defaultOptions, contextParams, getContextResponse);
- publisher.publish.mockReturnValue(Promise.resolve());
-
- context.treatment("exp_test_ab");
-
- context.publish().then(() => {
- const call = publisher.publish.mock.calls[0];
- const request = call[0];
-
- expect(request.attributes).toBeUndefined();
-
- done();
- });
- });
-
- it("should include system attributes when includeSystemAttributes is true", (done) => {
- const optionsWithSystemAttrs = {
- publishDelay: -1,
- refreshPeriod: 0,
- includeSystemAttributes: true,
- };
-
- const context = new Context(sdk, optionsWithSystemAttrs, contextParams, getContextResponse);
- publisher.publish.mockReturnValue(Promise.resolve());
-
- context.treatment("exp_test_ab");
-
- context.publish().then(() => {
- const call = publisher.publish.mock.calls[0];
- const request = call[0];
-
- expect(request.attributes).toBeDefined();
- expect(request.attributes.length).toBeGreaterThanOrEqual(4);
-
- const sdkNameAttr = request.attributes.find((a) => a.name === "sdk_name");
- const sdkVersionAttr = request.attributes.find((a) => a.name === "sdk_version");
- const applicationAttr = request.attributes.find((a) => a.name === "application");
- const environmentAttr = request.attributes.find((a) => a.name === "environment");
-
- expect(sdkNameAttr).toBeDefined();
- expect(sdkNameAttr.value).toEqual("absmartly-javascript-sdk");
- expect(sdkNameAttr.setAt).toEqual(expect.any(Number));
-
- expect(sdkVersionAttr).toBeDefined();
- expect(sdkVersionAttr.value).toEqual(SDK_VERSION);
- expect(sdkVersionAttr.setAt).toEqual(expect.any(Number));
-
- expect(applicationAttr).toBeDefined();
- expect(applicationAttr.value).toEqual("website");
- expect(applicationAttr.setAt).toEqual(expect.any(Number));
-
- expect(environmentAttr).toBeDefined();
- expect(environmentAttr.value).toEqual("production");
- expect(environmentAttr.setAt).toEqual(expect.any(Number));
-
- done();
- });
- });
-
- it("should prepend system attributes before user attributes", (done) => {
- const optionsWithSystemAttrs = {
- publishDelay: -1,
- refreshPeriod: 0,
- includeSystemAttributes: true,
- };
-
- const context = new Context(sdk, optionsWithSystemAttrs, contextParams, getContextResponse);
- publisher.publish.mockReturnValue(Promise.resolve());
-
- context.attribute("custom_attr", "custom_value");
- context.treatment("exp_test_ab");
-
- context.publish().then(() => {
- const call = publisher.publish.mock.calls[0];
- const request = call[0];
-
- expect(request.attributes[0].name).toEqual("sdk_name");
- expect(request.attributes[1].name).toEqual("sdk_version");
- expect(request.attributes[2].name).toEqual("application");
- expect(request.attributes[3].name).toEqual("environment");
- expect(request.attributes[4].name).toEqual("custom_attr");
- expect(request.attributes[4].value).toEqual("custom_value");
-
- done();
- });
- });
-
- it("should include app_version when application version is set", (done) => {
- client.getApplication.mockReturnValueOnce({ name: "website", version: 3 });
-
- const optionsWithSystemAttrs = {
- publishDelay: -1,
- refreshPeriod: 0,
- includeSystemAttributes: true,
- };
-
- const context = new Context(sdk, optionsWithSystemAttrs, contextParams, getContextResponse);
- publisher.publish.mockReturnValue(Promise.resolve());
-
- context.treatment("exp_test_ab");
-
- context.publish().then(() => {
- const call = publisher.publish.mock.calls[0];
- const request = call[0];
-
- const appVersionAttr = request.attributes.find((a) => a.name === "app_version");
- expect(appVersionAttr).toBeDefined();
- expect(appVersionAttr.value).toEqual(3);
-
- done();
- });
- });
-
- it("should not include app_version when application version is 0", (done) => {
- const optionsWithSystemAttrs = {
- publishDelay: -1,
- refreshPeriod: 0,
- includeSystemAttributes: true,
- };
-
- const context = new Context(sdk, optionsWithSystemAttrs, contextParams, getContextResponse);
- publisher.publish.mockReturnValue(Promise.resolve());
-
- context.treatment("exp_test_ab");
-
- context.publish().then(() => {
- const call = publisher.publish.mock.calls[0];
- const request = call[0];
-
- const appVersionAttr = request.attributes.find((a) => a.name === "app_version");
- expect(appVersionAttr).toBeUndefined();
-
- done();
- });
- });
-
- it("should include app_version when application version is a semver string", (done) => {
- client.getApplication.mockReturnValueOnce({ name: "website", version: "1.2.3" });
-
- const optionsWithSystemAttrs = {
- publishDelay: -1,
- refreshPeriod: 0,
- includeSystemAttributes: true,
- };
-
- const context = new Context(sdk, optionsWithSystemAttrs, contextParams, getContextResponse);
- publisher.publish.mockReturnValue(Promise.resolve());
-
- context.treatment("exp_test_ab");
-
- context.publish().then(() => {
- const call = publisher.publish.mock.calls[0];
- const request = call[0];
-
- const appVersionAttr = request.attributes.find((a) => a.name === "app_version");
- expect(appVersionAttr).toBeDefined();
- expect(appVersionAttr.value).toEqual("1.2.3");
-
- done();
- });
- });
-
- it("should include app_version with application as plain string", (done) => {
- client.getApplication.mockReturnValueOnce({ name: "website", version: 0 });
-
- const optionsWithSystemAttrs = {
- publishDelay: -1,
- refreshPeriod: 0,
- includeSystemAttributes: true,
- };
-
- const context = new Context(sdk, optionsWithSystemAttrs, contextParams, getContextResponse);
- publisher.publish.mockReturnValue(Promise.resolve());
-
- context.treatment("exp_test_ab");
-
- context.publish().then(() => {
- const call = publisher.publish.mock.calls[0];
- const request = call[0];
-
- const applicationAttr = request.attributes.find((a) => a.name === "application");
- expect(applicationAttr).toBeDefined();
- expect(applicationAttr.value).toEqual("website");
-
- const appVersionAttr = request.attributes.find((a) => a.name === "app_version");
- expect(appVersionAttr).toBeUndefined();
-
- done();
- });
- });
-
- it("should only include user attributes when includeSystemAttributes is not set", (done) => {
- const defaultOptions = {
- publishDelay: -1,
- refreshPeriod: 0,
- };
-
- const context = new Context(sdk, defaultOptions, contextParams, getContextResponse);
- publisher.publish.mockReturnValue(Promise.resolve());
-
- context.attribute("custom_attr", "custom_value");
- context.treatment("exp_test_ab");
-
- context.publish().then(() => {
- const call = publisher.publish.mock.calls[0];
- const request = call[0];
-
- expect(request.attributes).toEqual([
- { name: "custom_attr", value: "custom_value", setAt: expect.any(Number) },
- ]);
-
- done();
- });
- });
- });
-});
diff --git a/src/__tests__/context.test.ts b/src/__tests__/context.test.ts
new file mode 100644
index 0000000..4af3f1f
--- /dev/null
+++ b/src/__tests__/context.test.ts
@@ -0,0 +1,3246 @@
+import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
+import { Context } from "../context";
+import { DefaultContextPublisher } from "../publisher";
+import { DefaultContextDataProvider } from "../provider";
+import { hashUnit } from "../hashing";
+import { SDK_VERSION } from "../version";
+import type { ContextPublisher, ContextDataProvider } from "../interfaces";
+
+function clone(obj: T): T {
+ return JSON.parse(JSON.stringify(obj));
+}
+
+describe("Context", () => {
+ const contextParams = {
+ units: {
+ session_id: "e791e240fcd3df7d238cfc285f475e8152fcc0ec",
+ user_id: 12317303,
+ },
+ };
+
+ const publishUnits = Object.entries(contextParams.units).map((x) => ({ type: x[0], uid: hashUnit(x[1]) }));
+
+ const units = {
+ session_id: "e791e240fcd3df7d238cfc285f475e8152fcc0ec",
+ user_id: "123456789",
+ email: "bleh@absmartly.com",
+ };
+
+ const getContextResponse = {
+ experiments: [
+ {
+ id: 1,
+ name: "exp_test_ab",
+ iteration: 1,
+ unitType: "session_id",
+ seedHi: 3603515,
+ seedLo: 233373850,
+ split: [0.5, 0.5],
+ trafficSeedHi: 449867249,
+ trafficSeedLo: 455443629,
+ trafficSplit: [0.0, 1.0],
+ fullOnVariant: 0,
+ applications: [{ name: "website" }],
+ variants: [
+ { name: "A", config: null },
+ { name: "B", config: '{"banner.border":1,"banner.size":"large"}' },
+ ],
+ audience: null,
+ audienceStrict: false,
+ customFieldValues: null,
+ },
+ {
+ id: 2,
+ name: "exp_test_abc",
+ iteration: 1,
+ unitType: "session_id",
+ seedHi: 55006150,
+ seedLo: 47189152,
+ split: [0.34, 0.33, 0.33],
+ trafficSeedHi: 705671872,
+ trafficSeedLo: 212903484,
+ trafficSplit: [0.0, 1.0],
+ fullOnVariant: 0,
+ applications: [{ name: "website" }],
+ variants: [
+ { name: "A", config: null },
+ { name: "B", config: '{"button.color":"blue"}' },
+ { name: "C", config: '{"button.color":"red"}' },
+ ],
+ audience: "",
+ audienceStrict: false,
+ customFieldValues: [
+ { name: "country", value: "US,PT,ES,DE,FR", type: "string" },
+ { name: "json_object", value: '{"123":1,"456":0}', type: "json" },
+ { name: "json_array", value: '["hello", "world"]', type: "json" },
+ { name: "json_number", value: "123", type: "json" },
+ { name: "json_string", value: '"hello"', type: "json" },
+ { name: "json_boolean", value: "true", type: "json" },
+ { name: "json_null", value: "null", type: "json" },
+ { name: "json_invalid", value: "invalid", type: "json" },
+ ],
+ },
+ {
+ id: 3,
+ name: "exp_test_not_eligible",
+ iteration: 1,
+ unitType: "user_id",
+ seedHi: 503266407,
+ seedLo: 144942754,
+ split: [0.34, 0.33, 0.33],
+ trafficSeedHi: 87768905,
+ trafficSeedLo: 511357582,
+ trafficSplit: [0.99, 0.01],
+ fullOnVariant: 0,
+ applications: [{ name: "website" }],
+ variants: [
+ { name: "A", config: null },
+ { name: "B", config: '{"card.width":"80%"}' },
+ { name: "C", config: '{"card.width":"75%"}' },
+ ],
+ audience: "{}",
+ audienceStrict: false,
+ customFieldValues: null,
+ },
+ {
+ id: 4,
+ name: "exp_test_fullon",
+ iteration: 1,
+ unitType: "session_id",
+ seedHi: 856061641,
+ seedLo: 990838475,
+ split: [0.25, 0.25, 0.25, 0.25],
+ trafficSeedHi: 360868579,
+ trafficSeedLo: 330937933,
+ trafficSplit: [0.0, 1.0],
+ fullOnVariant: 2,
+ applications: [{ name: "website" }],
+ variants: [
+ { name: "A", config: null },
+ { name: "B", config: '{"submit.color":"red","submit.shape":"circle"}' },
+ { name: "C", config: '{"submit.color":"blue","submit.shape":"rect"}' },
+ { name: "D", config: '{"submit.color":"green","submit.shape":"square"}' },
+ ],
+ audience: "null",
+ audienceStrict: false,
+ customFieldValues: null,
+ },
+ {
+ id: 5,
+ name: "exp_test_custom_fields",
+ iteration: 1,
+ unitType: "session_id",
+ seedHi: 9372617,
+ seedLo: 121364805,
+ split: [0.5, 0.5],
+ trafficSeedHi: 318746944,
+ trafficSeedLo: 359812364,
+ trafficSplit: [0.0, 1.0],
+ fullOnVariant: 0,
+ applications: [{ name: "website" }],
+ variants: [
+ { name: "A", config: null },
+ { name: "B", config: '{"submit.size":"sm"}' },
+ ],
+ audience: null,
+ audienceStrict: false,
+ customFieldValues: [
+ { name: "country", value: "US,PT,ES", type: "string" },
+ { name: "languages", value: "en-US,en-GB,pt-PT,pt-BR,es-ES,es-MX", type: "string" },
+ { name: "text_field", value: "hello text", type: "text" },
+ { name: "string_field", value: "hello string", type: "string" },
+ { name: "number_field", value: "123", type: "number" },
+ { name: "boolean_field", value: "true", type: "boolean" },
+ { name: "false_boolean_field", value: "false", type: "boolean" },
+ { name: "invalid_type_field", value: "invalid", type: "invalid" },
+ ],
+ },
+ ],
+ };
+
+ const refreshContextResponse = {
+ ...getContextResponse,
+ experiments: [
+ {
+ id: 6,
+ name: "exp_test_new",
+ iteration: 2,
+ unitType: "session_id",
+ seedHi: 934590467,
+ seedLo: 714771373,
+ split: [0.5, 0.5],
+ trafficSeedHi: 940553836,
+ trafficSeedLo: 270705624,
+ trafficSplit: [0.0, 1.0],
+ fullOnVariant: 1,
+ applications: [{ name: "website" }],
+ variants: [
+ { name: "A", config: null },
+ { name: "B", config: '{"show-modal":true}' },
+ ],
+ audience: null,
+ audienceStrict: false,
+ customFieldValues: null,
+ },
+ ...getContextResponse.experiments,
+ ],
+ };
+
+ const audienceContextResponse = {
+ ...getContextResponse,
+ experiments: getContextResponse.experiments.map((x) => {
+ if (x.name === "exp_test_ab") {
+ return {
+ ...x,
+ audience: JSON.stringify({
+ filter: [{ gte: [{ var: "age" }, { value: 20 }] }],
+ }),
+ };
+ }
+ return x;
+ }),
+ };
+
+ const audienceStrictContextResponse = {
+ ...audienceContextResponse,
+ experiments: audienceContextResponse.experiments.map((x) => {
+ if (x.name === "exp_test_ab") {
+ return {
+ ...x,
+ audienceStrict: true,
+ variants: x.variants.map((v) => {
+ if (v.name === "A") {
+ return { name: "A", config: '{"banner.size":"tiny"}' };
+ }
+ return v;
+ }),
+ };
+ }
+ return x;
+ }),
+ };
+
+ const expectedVariants: Record = {
+ exp_test_ab: 1,
+ exp_test_abc: 2,
+ exp_test_not_eligible: 0,
+ exp_test_fullon: 2,
+ exp_test_new: 1,
+ exp_test_custom_fields: 1,
+ };
+
+ const lowestIdConflictingKeyContextResponse = {
+ ...getContextResponse,
+ experiments: getContextResponse.experiments.map((e) => {
+ if (e.name === "exp_test_ab") {
+ return {
+ ...e,
+ id: 99,
+ variants: e.variants.map((v, i) => {
+ if (i === expectedVariants[e.name]) {
+ return { ...v, config: JSON.stringify({ icon: "arrow" }) };
+ }
+ return v;
+ }),
+ };
+ }
+ if (e.name === "exp_test_abc") {
+ return {
+ ...e,
+ id: 1,
+ variants: e.variants.map((v, i) => {
+ if (i === expectedVariants[e.name]) {
+ return { ...v, config: JSON.stringify({ icon: "circle" }) };
+ }
+ return v;
+ }),
+ };
+ }
+ return e;
+ }),
+ };
+
+ const disjointedContextResponse = {
+ ...getContextResponse,
+ experiments: getContextResponse.experiments.map((exp) => {
+ if (exp.name === "exp_test_ab") {
+ return {
+ ...exp,
+ audienceStrict: true,
+ audience: JSON.stringify({
+ filter: [{ gte: [{ var: "age" }, { value: 20 }] }],
+ }),
+ variants: exp.variants.map((v, i) => {
+ if (i === expectedVariants[exp.name]) {
+ return { ...v, config: JSON.stringify({ icon: "arrow" }) };
+ }
+ return v;
+ }),
+ };
+ }
+ if (exp.name === "exp_test_abc") {
+ return {
+ ...exp,
+ audienceStrict: true,
+ audience: JSON.stringify({
+ filter: [{ lt: [{ var: "age" }, { value: 20 }] }],
+ }),
+ variants: exp.variants.map((variant, i) => {
+ if (i === expectedVariants[exp.name]) {
+ return { ...variant, config: JSON.stringify({ icon: "circle" }) };
+ }
+ return variant;
+ }),
+ };
+ }
+ return exp;
+ }),
+ };
+
+ const expectedVariables: Record = {
+ "banner.border": 1,
+ "banner.size": "large",
+ "button.color": "red",
+ "submit.color": "blue",
+ "submit.shape": "rect",
+ "show-modal": true,
+ "submit.size": "sm",
+ };
+
+ const variableExperiments: Record = {
+ "banner.border": ["exp_test_ab"],
+ "banner.size": ["exp_test_ab"],
+ "button.color": ["exp_test_abc"],
+ "card.width": ["exp_test_not_eligible"],
+ "submit.color": ["exp_test_fullon"],
+ "submit.shape": ["exp_test_fullon"],
+ "submit.size": ["exp_test_custom_fields"],
+ "show-modal": ["exp_test_new"],
+ };
+
+ const defaultEventLogger = vi.fn();
+
+ const publisher = {
+ publish: vi.fn(),
+ } as unknown as ContextPublisher & { publish: ReturnType };
+
+ const provider = {
+ getContextData: vi.fn(),
+ } as unknown as ContextDataProvider & { getContextData: ReturnType };
+
+ const client = {
+ getAgent: vi.fn().mockReturnValue("absmartly-javascript-sdk"),
+ getApplication: vi.fn().mockReturnValue({ name: "website", version: 0 }),
+ getEnvironment: vi.fn().mockReturnValue("production"),
+ };
+
+ const sdk = {
+ getContextPublisher: vi.fn().mockReturnValue(publisher),
+ getContextDataProvider: vi.fn().mockReturnValue(provider),
+ getClient: vi.fn().mockReturnValue(client),
+ getEventLogger: vi.fn().mockReturnValue(defaultEventLogger),
+ };
+
+ const contextOptions = {
+ publishDelay: -1,
+ refreshPeriod: 0,
+ };
+
+ const timeOrigin = 1611141535729;
+
+ beforeEach(() => {
+ vi.spyOn(Date, "now").mockImplementation(() => timeOrigin);
+ vi.clearAllMocks();
+ sdk.getContextPublisher.mockReturnValue(publisher);
+ sdk.getContextDataProvider.mockReturnValue(provider);
+ sdk.getClient.mockReturnValue(client);
+ sdk.getEventLogger.mockReturnValue(defaultEventLogger);
+ client.getAgent.mockReturnValue("absmartly-javascript-sdk");
+ client.getApplication.mockReturnValue({ name: "website", version: 0 });
+ client.getEnvironment.mockReturnValue("production");
+ });
+
+ afterEach(() => {
+ vi.restoreAllMocks();
+ });
+
+ describe("Context", () => {
+ it("should be ready with data", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ expect(context.isReady()).toEqual(true);
+ expect(context.isFailed()).toEqual(false);
+
+ await context.ready();
+ expect(context.isReady()).toEqual(true);
+ expect(context.data()).toStrictEqual(getContextResponse);
+ expect(context.eventLogger()).toBe(defaultEventLogger);
+ expect(context.provider()).toBe(provider);
+ expect(context.publisher()).toBe(publisher);
+ });
+
+ it("should use custom publisher, dataProvider and eventLogger", async () => {
+ const customPublisher = { publish: vi.fn() } as unknown as ContextPublisher;
+ const customDataProvider = { getContextData: vi.fn() } as unknown as ContextDataProvider;
+ const customEventLogger = vi.fn();
+
+ const context = new Context(
+ sdk,
+ {
+ ...contextOptions,
+ publisher: customPublisher,
+ dataProvider: customDataProvider,
+ eventLogger: customEventLogger,
+ },
+ contextParams,
+ getContextResponse as any
+ );
+ expect(context.isReady()).toEqual(true);
+ expect(context.isFailed()).toEqual(false);
+
+ await context.ready();
+ expect(context.isReady()).toEqual(true);
+ expect(context.data()).toStrictEqual(getContextResponse);
+ expect(context.eventLogger()).toBe(customEventLogger);
+ expect(context.provider()).toBe(customDataProvider);
+ expect(context.publisher()).toBe(customPublisher);
+ });
+
+ it("should become ready and call handler", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, Promise.resolve(getContextResponse as any));
+ expect(context.isReady()).toEqual(false);
+ expect(context.isFailed()).toEqual(false);
+
+ await context.ready();
+ expect(context.isReady()).toEqual(true);
+ expect(context.data()).toStrictEqual(getContextResponse);
+ expect(context.eventLogger()).toBe(defaultEventLogger);
+ expect(context.provider()).toBe(provider);
+ expect(context.publisher()).toBe(publisher);
+ });
+
+ it("should become ready and failed, and call handler on failure", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, Promise.reject("bad request error text") as any);
+ expect(context.isReady()).toEqual(false);
+ expect(context.isFailed()).toEqual(false);
+
+ await context.ready();
+ expect(context.isReady()).toEqual(true);
+ expect(context.isFailed()).toEqual(true);
+ expect(context.data()).toStrictEqual({});
+ expect(context.eventLogger()).toBe(defaultEventLogger);
+ expect(context.provider()).toBe(provider);
+ expect(context.publisher()).toBe(publisher);
+ });
+
+ it("ready() should resolve true even when context fails", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, Promise.reject(new Error("network error")) as any);
+ const result = await context.ready();
+ expect(result).toBe(true);
+ expect(context.isFailed()).toBe(true);
+ expect(context.isReady()).toBe(true);
+ });
+
+ it("should return control variant (0) for all experiments after failure", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, Promise.reject(new Error("server error")) as any);
+ await context.ready();
+ expect(context.isFailed()).toBe(true);
+
+ expect(context.treatment("exp_test_ab")).toBe(0);
+ expect(context.treatment("exp_test_abc")).toBe(0);
+ expect(context.treatment("any_unknown_experiment")).toBe(0);
+ expect(context.peek("exp_test_ab")).toBe(0);
+ });
+
+ it("ready() should resolve true on success", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, Promise.resolve(getContextResponse as any));
+ const result = await context.ready();
+ expect(result).toBe(true);
+ expect(context.isFailed()).toBe(false);
+ });
+
+ it("should call event logger on error", async () => {
+ defaultEventLogger.mockClear();
+
+ const context = new Context(sdk, contextOptions, contextParams, Promise.reject("bad request error text") as any);
+ await context.ready();
+ expect(defaultEventLogger).toHaveBeenCalledTimes(1);
+ expect(defaultEventLogger).toHaveBeenCalledWith(context, "error", "bad request error text");
+ });
+
+ it("should call event logger on success", async () => {
+ defaultEventLogger.mockClear();
+
+ const context = new Context(sdk, contextOptions, contextParams, Promise.resolve(getContextResponse as any));
+ await context.ready();
+ expect(defaultEventLogger).toHaveBeenCalledTimes(1);
+ expect(defaultEventLogger).toHaveBeenCalledWith(context, "ready", getContextResponse);
+ });
+
+ it("should call event logger on pre-fetched experiment data", async () => {
+ defaultEventLogger.mockClear();
+
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ await context.ready();
+ expect(defaultEventLogger).toHaveBeenCalledTimes(1);
+ expect(defaultEventLogger).toHaveBeenCalledWith(context, "ready", getContextResponse);
+ });
+
+ it("should throw when not ready", () => {
+ const context = new Context(sdk, contextOptions, contextParams, Promise.resolve(getContextResponse as any));
+ expect(context.isReady()).toEqual(false);
+ expect(context.isFailed()).toEqual(false);
+ expect(context.isFinalized()).toEqual(false);
+
+ expect(() => context.data()).toThrow();
+ expect(() => context.treatment("test")).toThrow();
+ expect(() => context.peek("test")).toThrow();
+ expect(() => context.experiments()).toThrow();
+ expect(() => context.variableKeys()).toThrow();
+ expect(() => context.variableValue("a", "17")).toThrow();
+ expect(() => context.peekVariableValue("a", "17")).toThrow();
+ });
+
+ it("should load experiment data", () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+
+ expect(context.experiments()).toEqual(getContextResponse.experiments.map((x) => x.name));
+ for (const experiment of getContextResponse.experiments) {
+ expect(context.peek(experiment.name)).toEqual(expectedVariants[experiment.name]);
+ expect(context.treatment(experiment.name)).toEqual(expectedVariants[experiment.name]);
+ }
+ expect(context.data()).toEqual(getContextResponse);
+ });
+ });
+
+ describe("unit()", () => {
+ it("should set a unit", () => {
+ const context = new Context(sdk, contextOptions, { units: {} }, getContextResponse as any);
+
+ context.units(units);
+
+ for (const [key, value] of Object.entries(units)) {
+ expect(context.getUnit(key)).toEqual(value);
+ }
+
+ expect(context.getUnits()).toEqual(units);
+ });
+
+ it("should throw on duplicate unit type set", () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ expect(context.isReady()).toEqual(true);
+
+ expect(() => context.unit("session_id", "new_id")).toThrow();
+ expect(() => context.unit("session_id", "e791e240fcd3df7d238cfc285f475e8152fcc0ec")).not.toThrow();
+ });
+
+ it("should throw on invalid uid", () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ expect(context.isReady()).toEqual(true);
+
+ expect(() => context.unit("session_id", "")).toThrow();
+ expect(() => context.unit("session_id", null as any)).toThrow();
+ expect(() => context.unit("session_id", undefined as any)).toThrow();
+ expect(() => context.unit("session_id", true as any)).toThrow();
+ expect(() => context.unit("session_id", {} as any)).toThrow();
+ expect(() => context.unit("session_id", [] as any)).toThrow();
+ });
+
+ it("should be callable before ready()", async () => {
+ const context = new Context(sdk, contextOptions, { units: {} } as any, Promise.resolve(getContextResponse as any));
+
+ context.units(contextParams.units);
+
+ await context.ready();
+ expect(context.isReady()).toEqual(true);
+
+ context.treatment("exp_test_ab");
+
+ (publisher.publish as ReturnType).mockReturnValue(Promise.resolve());
+
+ vi.spyOn(Date, "now").mockImplementation(() => timeOrigin + 100);
+
+ await context.publish();
+ expect(publisher.publish).toHaveBeenCalledTimes(1);
+ expect(publisher.publish).toHaveBeenCalledWith(
+ {
+ publishedAt: 1611141535829,
+ units: publishUnits,
+ hashed: true,
+ sdkVersion: SDK_VERSION,
+ exposures: [
+ {
+ id: 1,
+ name: "exp_test_ab",
+ unit: "session_id",
+ exposedAt: 1611141535729,
+ variant: 1,
+ assigned: true,
+ eligible: true,
+ overridden: false,
+ fullOn: false,
+ custom: false,
+ audienceMismatch: false,
+ },
+ ],
+ },
+ sdk,
+ context,
+ undefined
+ );
+ });
+
+ it("should throw after finalized() call", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ (publisher.publish as ReturnType).mockReturnValue(Promise.resolve());
+
+ context.treatment("exp_test_ab");
+
+ expect(context.pending()).toEqual(1);
+
+ const finalizePromise = context.finalize();
+
+ expect(context.isFinalizing()).toEqual(true);
+ expect(() => context.unit("test", "test")).toThrow();
+
+ await finalizePromise;
+
+ expect(() => context.unit("test", "test")).toThrow();
+ });
+ });
+
+ describe("getAttribute()", () => {
+ it("should get the last set attribute", () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+
+ context.attribute("attr1", "value1");
+ context.attribute("attr1", "value2");
+
+ expect(context.getAttribute("attr1")).toEqual("value2");
+ });
+ });
+
+ describe("attribute()", () => {
+ it("should set an attribute", () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+
+ context.attribute("attr1", "value1");
+ context.attributes({
+ attr2: "value2",
+ attr3: 15,
+ });
+
+ expect(context.getAttribute("attr1")).toEqual("value1");
+ expect(context.getAttributes()).toEqual({
+ attr1: "value1",
+ attr2: "value2",
+ attr3: 15,
+ });
+ });
+
+ it("should be callable before ready()", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, Promise.resolve(getContextResponse as any));
+ expect(context.isReady()).toEqual(false);
+ expect(context.isFailed()).toEqual(false);
+ expect(context.isFinalized()).toEqual(false);
+
+ context.attribute("attr1", "value1");
+ context.attributes({
+ attr2: "value2",
+ attr3: 3,
+ });
+
+ expect(context.getAttribute("attr1")).toEqual("value1");
+ expect(context.getAttributes()).toEqual({
+ attr1: "value1",
+ attr2: "value2",
+ attr3: 3,
+ });
+
+ await context.ready();
+ expect(context.isReady()).toEqual(true);
+
+ context.treatment("exp_test_ab");
+
+ (publisher.publish as ReturnType).mockReturnValue(Promise.resolve());
+
+ vi.spyOn(Date, "now").mockImplementation(() => timeOrigin + 100);
+
+ await context.publish();
+ expect(publisher.publish).toHaveBeenCalledTimes(1);
+ expect(publisher.publish).toHaveBeenCalledWith(
+ {
+ publishedAt: 1611141535829,
+ units: publishUnits,
+ hashed: true,
+ sdkVersion: SDK_VERSION,
+ exposures: [
+ {
+ id: 1,
+ name: "exp_test_ab",
+ unit: "session_id",
+ exposedAt: 1611141535729,
+ variant: 1,
+ assigned: true,
+ eligible: true,
+ overridden: false,
+ fullOn: false,
+ custom: false,
+ audienceMismatch: false,
+ },
+ ],
+ attributes: [
+ { name: "attr1", setAt: 1611141535729, value: "value1" },
+ { name: "attr2", setAt: 1611141535729, value: "value2" },
+ { name: "attr3", setAt: 1611141535729, value: 3 },
+ ],
+ },
+ sdk,
+ context,
+ undefined
+ );
+ });
+ });
+
+ describe("refresh()", () => {
+ it("should call client and load new data", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+
+ (provider.getContextData as ReturnType).mockReturnValue(Promise.resolve(refreshContextResponse));
+
+ await context.refresh();
+ expect(provider.getContextData).toHaveBeenCalledTimes(1);
+ expect(provider.getContextData).toHaveBeenCalledWith(sdk, undefined);
+
+ expect(context.experiments()).toEqual(refreshContextResponse.experiments.map((x) => x.name));
+ for (const experiment of refreshContextResponse.experiments) {
+ expect(context.treatment(experiment.name)).toEqual(expectedVariants[experiment.name]);
+ }
+ expect(context.data()).toEqual(refreshContextResponse);
+ });
+
+ it("should pass through request options", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+
+ (provider.getContextData as ReturnType).mockReturnValue(Promise.resolve(refreshContextResponse));
+
+ await context.refresh({ timeout: 1234 } as any);
+ expect(provider.getContextData).toHaveBeenCalledTimes(1);
+ expect(provider.getContextData).toHaveBeenCalledWith(sdk, { timeout: 1234 });
+
+ expect(context.experiments()).toEqual(refreshContextResponse.experiments.map((x) => x.name));
+ for (const experiment of refreshContextResponse.experiments) {
+ expect(context.treatment(experiment.name)).toEqual(expectedVariants[experiment.name]);
+ }
+ expect(context.data()).toEqual(refreshContextResponse);
+ });
+
+ it("should reject promise on error", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+
+ (provider.getContextData as ReturnType).mockReturnValueOnce(Promise.reject(new Error("test error")));
+
+ await expect(context.refresh()).rejects.toThrow("test error");
+ });
+
+ it("should not re-queue exposures after refresh when not changed", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+
+ for (const experiment of getContextResponse.experiments) {
+ context.treatment(experiment.name);
+ }
+
+ expect(context.pending()).toEqual(getContextResponse.experiments.length);
+
+ (provider.getContextData as ReturnType).mockReturnValue(Promise.resolve(refreshContextResponse));
+
+ await context.refresh();
+ expect(context.pending()).toEqual(getContextResponse.experiments.length);
+
+ expect(provider.getContextData).toHaveBeenCalledTimes(1);
+ expect(provider.getContextData).toHaveBeenCalledWith(sdk, undefined);
+
+ for (const experiment of getContextResponse.experiments) {
+ context.treatment(experiment.name);
+ }
+
+ expect(context.pending()).toEqual(getContextResponse.experiments.length);
+
+ for (const experiment of refreshContextResponse.experiments) {
+ context.treatment(experiment.name);
+ }
+
+ expect(context.pending()).toEqual(refreshContextResponse.experiments.length);
+ });
+
+ it("should not re-queue when not changed on audience mismatch", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, audienceStrictContextResponse as any);
+
+ expect(context.treatment("exp_test_ab")).toEqual(0);
+ expect(context.pending()).toEqual(1);
+
+ (provider.getContextData as ReturnType).mockReturnValue(Promise.resolve(audienceStrictContextResponse));
+
+ await context.refresh();
+ expect(context.treatment("exp_test_ab")).toEqual(0);
+ expect(context.pending()).toEqual(1);
+ });
+
+ it("should not re-queue when not changed with override", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, audienceStrictContextResponse as any);
+
+ context.override("exp_test_ab", 3);
+ expect(context.treatment("exp_test_ab")).toEqual(3);
+ expect(context.pending()).toEqual(1);
+
+ (provider.getContextData as ReturnType).mockReturnValue(Promise.resolve(audienceStrictContextResponse));
+
+ await context.refresh();
+ expect(context.treatment("exp_test_ab")).toEqual(3);
+ expect(context.pending()).toEqual(1);
+ });
+
+ it("should not call client publish when failed", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, Promise.reject("bad request error text") as any);
+
+ await context.ready();
+ await context.refresh();
+ expect(provider.getContextData).not.toHaveBeenCalled();
+ });
+
+ it("should call event logger when failed", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, Promise.resolve(getContextResponse as any));
+ await context.ready();
+ (provider.getContextData as ReturnType).mockReturnValueOnce(Promise.reject(new Error("test error")));
+
+ defaultEventLogger.mockClear();
+ await expect(context.refresh()).rejects.toThrow("test error");
+ expect(defaultEventLogger).toHaveBeenCalledTimes(1);
+ expect(defaultEventLogger).toHaveBeenCalledWith(context, "error", expect.any(Error));
+ });
+
+ it("should call event logger on success", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, Promise.resolve(getContextResponse as any));
+
+ (provider.getContextData as ReturnType).mockReturnValueOnce(Promise.resolve(refreshContextResponse));
+
+ await context.ready();
+ defaultEventLogger.mockClear();
+ await context.refresh();
+ expect(defaultEventLogger).toHaveBeenCalledTimes(1);
+ expect(defaultEventLogger).toHaveBeenCalledWith(context, "refresh", refreshContextResponse);
+ });
+
+ it("should throw after finalized() call", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ (publisher.publish as ReturnType).mockReturnValue(Promise.resolve());
+
+ context.treatment("exp_test_ab");
+
+ expect(context.pending()).toEqual(1);
+
+ const finalizePromise = context.finalize();
+
+ expect(context.isFinalizing()).toEqual(true);
+ expect(() => context.refresh()).toThrow();
+
+ await finalizePromise;
+
+ expect(() => context.refresh()).toThrow();
+ });
+
+ it("should keep overrides", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+
+ (provider.getContextData as ReturnType).mockReturnValue(Promise.resolve(refreshContextResponse));
+
+ context.override("not_found", 3);
+ expect(context.peek("not_found")).toEqual(3);
+
+ await context.refresh();
+ expect(context.peek("not_found")).toEqual(3);
+ });
+
+ it("should keep custom assignments", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+
+ (provider.getContextData as ReturnType).mockReturnValue(Promise.resolve(refreshContextResponse));
+
+ context.customAssignment("exp_test_ab", 3);
+ expect(context.peek("exp_test_ab")).toEqual(3);
+
+ await context.refresh();
+ expect(context.peek("exp_test_ab")).toEqual(3);
+ });
+
+ it("should pick up changes in experiment stopped", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ const experimentName = "exp_test_abc";
+
+ expect(context.treatment(experimentName)).toEqual(expectedVariants[experimentName]);
+ expect(context.pending()).toEqual(1);
+
+ const stoppedRefreshContextResponse = clone(getContextResponse);
+ stoppedRefreshContextResponse.experiments = stoppedRefreshContextResponse.experiments.filter(
+ (x) => x.name !== experimentName
+ );
+
+ (provider.getContextData as ReturnType).mockReturnValue(Promise.resolve(stoppedRefreshContextResponse));
+
+ await context.refresh();
+ expect(context.treatment(experimentName)).toEqual(0);
+ expect(context.pending()).toEqual(2);
+ });
+
+ it("should pick up changes in experiment started", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ const experimentName = "exp_test_new";
+
+ expect(context.treatment(experimentName)).toEqual(0);
+ expect(context.pending()).toEqual(1);
+
+ (provider.getContextData as ReturnType).mockReturnValue(Promise.resolve(refreshContextResponse));
+
+ await context.refresh();
+ expect(context.treatment(experimentName)).toEqual(1);
+ expect(context.pending()).toEqual(2);
+ });
+
+ it("should pick up changes in experiment fullon", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ const experimentName = "exp_test_abc";
+
+ expect(context.treatment(experimentName)).toEqual(expectedVariants[experimentName]);
+ expect(context.pending()).toEqual(1);
+
+ const fullOnRefreshContextResponse = clone(getContextResponse);
+ for (const experiment of fullOnRefreshContextResponse.experiments) {
+ if (experiment.name === experimentName) {
+ expect(experiment.fullOnVariant).toEqual(0);
+ experiment.fullOnVariant = 1;
+ expect(expectedVariants[experimentName]).not.toEqual(experiment.fullOnVariant);
+ }
+ }
+
+ (provider.getContextData as ReturnType).mockReturnValue(Promise.resolve(fullOnRefreshContextResponse));
+
+ await context.refresh();
+ expect(context.treatment(experimentName)).toEqual(1);
+ expect(context.pending()).toEqual(2);
+ });
+
+ it("should pick up changes in experiment traffic split", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ const experimentName = "exp_test_not_eligible";
+
+ expect(context.treatment(experimentName)).toEqual(expectedVariants[experimentName]);
+ expect(context.pending()).toEqual(1);
+
+ const scaledUpRefreshContextResponse = clone(getContextResponse);
+ for (const experiment of scaledUpRefreshContextResponse.experiments) {
+ if (experiment.name === experimentName) {
+ experiment.trafficSplit = [0.0, 1.0];
+ }
+ }
+
+ (provider.getContextData as ReturnType).mockReturnValue(Promise.resolve(scaledUpRefreshContextResponse));
+
+ await context.refresh();
+ expect(context.treatment(experimentName)).toEqual(2);
+ expect(context.pending()).toEqual(2);
+ });
+
+ it("should pick up changes in experiment iteration", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ const experimentName = "exp_test_abc";
+
+ expect(context.treatment(experimentName)).toEqual(expectedVariants[experimentName]);
+ expect(context.pending()).toEqual(1);
+
+ const iteratedRefreshContextResponse = clone(getContextResponse);
+ for (const experiment of iteratedRefreshContextResponse.experiments) {
+ if (experiment.name === experimentName) {
+ experiment.iteration = 2;
+ experiment.trafficSeedHi = 398724581;
+ experiment.seedHi = 34737352;
+ }
+ }
+
+ (provider.getContextData as ReturnType).mockReturnValue(Promise.resolve(iteratedRefreshContextResponse));
+
+ await context.refresh();
+ expect(context.treatment(experimentName)).toEqual(1);
+ expect(context.pending()).toEqual(2);
+ });
+
+ it("should pick up changes in experiment id", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ const experimentName = "exp_test_abc";
+
+ expect(context.treatment(experimentName)).toEqual(expectedVariants[experimentName]);
+ expect(context.pending()).toEqual(1);
+
+ const iteratedRefreshContextResponse = clone(getContextResponse);
+ for (const experiment of iteratedRefreshContextResponse.experiments) {
+ if (experiment.name === experimentName) {
+ experiment.id = 11;
+ experiment.trafficSeedHi = 398724581;
+ experiment.seedHi = 34737352;
+ }
+ }
+
+ (provider.getContextData as ReturnType).mockReturnValue(Promise.resolve(iteratedRefreshContextResponse));
+
+ await context.refresh();
+ expect(context.treatment(experimentName)).toEqual(1);
+ expect(context.pending()).toEqual(2);
+ });
+ });
+
+ describe("peek()", () => {
+ it("should not queue exposures", () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ expect(context.pending()).toEqual(0);
+
+ for (const experiment of getContextResponse.experiments) {
+ expect(context.peek(experiment.name)).toEqual(expectedVariants[experiment.name]);
+ }
+
+ expect(context.pending()).toEqual(0);
+ });
+
+ it("should return override variant", () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ expect(context.pending()).toEqual(0);
+
+ for (const experiment of getContextResponse.experiments) {
+ context.override(experiment.name, expectedVariants[experiment.name] + 11);
+ }
+ context.override("not_found", 3);
+
+ for (const experiment of getContextResponse.experiments) {
+ expect(context.peek(experiment.name)).toEqual(expectedVariants[experiment.name] + 11);
+ }
+
+ expect(context.peek("not_found")).toEqual(3);
+ expect(context.pending()).toEqual(0);
+ });
+
+ it("should return assigned variant on audience mismatch in non-strict mode", () => {
+ const context = new Context(sdk, contextOptions, contextParams, audienceContextResponse as any);
+ expect(context.peek("exp_test_ab")).toEqual(1);
+ });
+
+ it("should return control variant on audience mismatch in strict mode", () => {
+ const context = new Context(sdk, contextOptions, contextParams, audienceStrictContextResponse as any);
+ expect(context.peek("exp_test_ab")).toEqual(0);
+ });
+
+ it("should re-evaluate audience expression when attributes change in strict mode", () => {
+ const context = new Context(sdk, contextOptions, contextParams, audienceStrictContextResponse as any);
+
+ expect(context.peek("exp_test_ab")).toEqual(0);
+
+ context.attribute("age", 25);
+
+ expect(context.peek("exp_test_ab")).toEqual(1);
+ expect(context.pending()).toEqual(0);
+ });
+
+ it("should re-evaluate audience expression when attributes change in non-strict mode", () => {
+ const context = new Context(sdk, contextOptions, contextParams, audienceContextResponse as any);
+
+ expect(context.peek("exp_test_ab")).toEqual(1);
+
+ context.attribute("age", 25);
+
+ expect(context.peek("exp_test_ab")).toEqual(1);
+ expect(context.pending()).toEqual(0);
+ });
+
+ it("should not re-evaluate audience when no new attributes set", () => {
+ const context = new Context(sdk, contextOptions, contextParams, audienceStrictContextResponse as any);
+
+ context.attribute("age", 15);
+
+ expect(context.peek("exp_test_ab")).toEqual(0);
+ expect(context.peek("exp_test_ab")).toEqual(0);
+ expect(context.pending()).toEqual(0);
+ });
+ });
+
+ describe("treatment()", () => {
+ it("should queue exposures", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ expect(context.pending()).toEqual(0);
+
+ for (const experiment of getContextResponse.experiments) {
+ context.treatment(experiment.name);
+ }
+
+ expect(context.pending()).toEqual(getContextResponse.experiments.length);
+
+ for (const experiment of getContextResponse.experiments) {
+ context.treatment(experiment.name);
+ }
+
+ expect(context.pending()).toEqual(getContextResponse.experiments.length);
+
+ (publisher.publish as ReturnType).mockReturnValue(Promise.resolve());
+
+ await context.publish();
+ expect(publisher.publish).toHaveBeenCalledWith(
+ {
+ publishedAt: 1611141535729,
+ units: publishUnits,
+ hashed: true,
+ sdkVersion: SDK_VERSION,
+ exposures: [
+ {
+ id: 1,
+ assigned: true,
+ eligible: true,
+ exposedAt: 1611141535729,
+ name: "exp_test_ab",
+ overridden: false,
+ unit: "session_id",
+ variant: 1,
+ fullOn: false,
+ custom: false,
+ audienceMismatch: false,
+ },
+ {
+ id: 2,
+ assigned: true,
+ eligible: true,
+ exposedAt: 1611141535729,
+ name: "exp_test_abc",
+ overridden: false,
+ unit: "session_id",
+ variant: 2,
+ fullOn: false,
+ custom: false,
+ audienceMismatch: false,
+ },
+ {
+ id: 3,
+ assigned: true,
+ eligible: false,
+ exposedAt: 1611141535729,
+ name: "exp_test_not_eligible",
+ overridden: false,
+ unit: "user_id",
+ variant: 0,
+ fullOn: false,
+ custom: false,
+ audienceMismatch: true,
+ },
+ {
+ id: 4,
+ assigned: true,
+ eligible: true,
+ exposedAt: 1611141535729,
+ name: "exp_test_fullon",
+ overridden: false,
+ unit: "session_id",
+ variant: 2,
+ fullOn: true,
+ custom: false,
+ audienceMismatch: true,
+ },
+ {
+ id: 5,
+ assigned: true,
+ eligible: true,
+ exposedAt: 1611141535729,
+ name: "exp_test_custom_fields",
+ overridden: false,
+ unit: "session_id",
+ variant: 1,
+ fullOn: false,
+ custom: false,
+ audienceMismatch: false,
+ },
+ ],
+ },
+ sdk,
+ context,
+ undefined
+ );
+ });
+
+ it("should queue exposures only once", () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ expect(context.pending()).toEqual(0);
+
+ for (const experiment of getContextResponse.experiments) {
+ context.treatment(experiment.name);
+ }
+
+ expect(context.pending()).toEqual(getContextResponse.experiments.length);
+
+ for (const experiment of getContextResponse.experiments) {
+ context.treatment(experiment.name);
+ }
+
+ expect(context.pending()).toEqual(getContextResponse.experiments.length);
+ });
+
+ it("should call event logger", () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ for (const experiment of getContextResponse.experiments) {
+ defaultEventLogger.mockClear();
+ context.treatment(experiment.name);
+ expect(defaultEventLogger).toHaveBeenCalledTimes(1);
+ expect(defaultEventLogger).toHaveBeenCalledWith(context, "exposure", {
+ exposedAt: timeOrigin,
+ eligible: experiment.name !== "exp_test_not_eligible",
+ assigned: true,
+ overridden: false,
+ id: experiment.id,
+ name: experiment.name,
+ unit: experiment.unitType,
+ variant: expectedVariants[experiment.name],
+ fullOn: experiment.name === "exp_test_fullon",
+ custom: false,
+ audienceMismatch: experiment.name === "exp_test_not_eligible" || experiment.name === "exp_test_fullon",
+ });
+ }
+
+ for (const experiment of getContextResponse.experiments) {
+ defaultEventLogger.mockClear();
+ context.treatment(experiment.name);
+ expect(defaultEventLogger).not.toHaveBeenCalled();
+ }
+ });
+
+ it("should queue exposure with base variant on unknown/stopped experiment", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ expect(context.pending()).toEqual(0);
+
+ expect(context.treatment("not_found")).toEqual(0);
+ expect(context.pending()).toEqual(1);
+
+ (publisher.publish as ReturnType).mockReturnValue(Promise.resolve());
+
+ await context.publish();
+ expect(publisher.publish).toHaveBeenCalledWith(
+ {
+ publishedAt: 1611141535729,
+ units: publishUnits,
+ hashed: true,
+ sdkVersion: SDK_VERSION,
+ exposures: [
+ {
+ id: 0,
+ assigned: false,
+ eligible: true,
+ exposedAt: 1611141535729,
+ name: "not_found",
+ overridden: false,
+ unit: null,
+ variant: 0,
+ fullOn: false,
+ custom: false,
+ audienceMismatch: false,
+ },
+ ],
+ },
+ sdk,
+ context,
+ undefined
+ );
+ });
+
+ it("should queue exposure with audienceMatch true on audience match", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, audienceContextResponse as any);
+ context.attribute("age", 21);
+
+ expect(context.treatment("exp_test_ab")).toEqual(1);
+ expect(context.pending()).toEqual(1);
+
+ (publisher.publish as ReturnType).mockReturnValue(Promise.resolve());
+
+ await context.publish();
+ expect(publisher.publish).toHaveBeenCalledWith(
+ {
+ publishedAt: 1611141535729,
+ units: publishUnits,
+ hashed: true,
+ sdkVersion: SDK_VERSION,
+ attributes: [{ name: "age", setAt: 1611141535729, value: 21 }],
+ exposures: [
+ {
+ id: 1,
+ assigned: true,
+ eligible: true,
+ exposedAt: 1611141535729,
+ name: "exp_test_ab",
+ overridden: false,
+ unit: "session_id",
+ variant: 1,
+ fullOn: false,
+ custom: false,
+ audienceMismatch: false,
+ },
+ ],
+ },
+ sdk,
+ context,
+ undefined
+ );
+ });
+
+ it("should queue exposure with audienceMatch false on audience mismatch", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, audienceContextResponse as any);
+
+ expect(context.treatment("exp_test_ab")).toEqual(1);
+ expect(context.pending()).toEqual(1);
+
+ (publisher.publish as ReturnType).mockReturnValue(Promise.resolve());
+
+ await context.publish();
+ expect(publisher.publish).toHaveBeenCalledWith(
+ {
+ publishedAt: 1611141535729,
+ units: publishUnits,
+ hashed: true,
+ sdkVersion: SDK_VERSION,
+ exposures: [
+ {
+ id: 1,
+ assigned: true,
+ eligible: true,
+ exposedAt: 1611141535729,
+ name: "exp_test_ab",
+ overridden: false,
+ unit: "session_id",
+ variant: 1,
+ fullOn: false,
+ custom: false,
+ audienceMismatch: true,
+ },
+ ],
+ },
+ sdk,
+ context,
+ undefined
+ );
+ });
+
+ it("should queue exposure with audienceMatch false and control variant on audience mismatch in strict mode", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, audienceStrictContextResponse as any);
+
+ expect(context.treatment("exp_test_ab")).toEqual(0);
+ expect(context.pending()).toEqual(1);
+
+ (publisher.publish as ReturnType).mockReturnValue(Promise.resolve());
+
+ await context.publish();
+ expect(publisher.publish).toHaveBeenCalledWith(
+ {
+ publishedAt: 1611141535729,
+ units: publishUnits,
+ hashed: true,
+ sdkVersion: SDK_VERSION,
+ exposures: [
+ {
+ id: 1,
+ assigned: false,
+ eligible: true,
+ exposedAt: 1611141535729,
+ name: "exp_test_ab",
+ overridden: false,
+ unit: "session_id",
+ variant: 0,
+ fullOn: false,
+ custom: false,
+ audienceMismatch: true,
+ },
+ ],
+ },
+ sdk,
+ context,
+ undefined
+ );
+ });
+
+ it("should not re-queue exposure on unknown experiment", () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+
+ expect(context.pending()).toEqual(0);
+ expect(context.treatment("not_found")).toEqual(0);
+ expect(context.pending()).toEqual(1);
+ expect(context.treatment("not_found")).toEqual(0);
+ expect(context.pending()).toEqual(1);
+ });
+
+ it("should queue exposure with override variant", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ expect(context.pending()).toEqual(0);
+
+ context.override("exp_test_ab", 5);
+ context.override("not_found", 3);
+
+ expect(context.treatment("exp_test_ab")).toEqual(5);
+ expect(context.treatment("not_found")).toEqual(3);
+
+ expect(context.pending()).toEqual(2);
+
+ (publisher.publish as ReturnType).mockReturnValue(Promise.resolve());
+
+ await context.publish();
+ expect(publisher.publish).toHaveBeenCalledWith(
+ {
+ publishedAt: 1611141535729,
+ units: publishUnits,
+ hashed: true,
+ sdkVersion: SDK_VERSION,
+ exposures: [
+ {
+ id: 1,
+ assigned: false,
+ eligible: true,
+ exposedAt: 1611141535729,
+ name: "exp_test_ab",
+ overridden: true,
+ unit: "session_id",
+ variant: 5,
+ fullOn: false,
+ custom: false,
+ audienceMismatch: false,
+ },
+ {
+ id: 0,
+ assigned: false,
+ eligible: true,
+ exposedAt: 1611141535729,
+ name: "not_found",
+ overridden: true,
+ unit: null,
+ variant: 3,
+ fullOn: false,
+ custom: false,
+ audienceMismatch: false,
+ },
+ ],
+ },
+ sdk,
+ context,
+ undefined
+ );
+ });
+
+ it("should throw after finalized() call", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ (publisher.publish as ReturnType).mockReturnValue(Promise.resolve());
+
+ context.treatment("exp_test_ab");
+
+ expect(context.pending()).toEqual(1);
+
+ const finalizePromise = context.finalize();
+
+ expect(context.isFinalizing()).toEqual(true);
+ expect(() => context.treatment("exp_test_ab")).toThrow();
+
+ await finalizePromise;
+
+ expect(() => context.treatment("exp_test_ab")).toThrow();
+ });
+
+ it("should re-evaluate audience expression when attributes change in strict mode", () => {
+ const context = new Context(sdk, contextOptions, contextParams, audienceStrictContextResponse as any);
+
+ expect(context.treatment("exp_test_ab")).toEqual(0);
+ expect(context.pending()).toEqual(1);
+
+ context.attribute("age", 25);
+
+ expect(context.treatment("exp_test_ab")).toEqual(1);
+ expect(context.pending()).toEqual(2);
+ });
+
+ it("should re-evaluate audience expression when attributes change in non-strict mode", () => {
+ const context = new Context(sdk, contextOptions, contextParams, audienceContextResponse as any);
+
+ expect(context.treatment("exp_test_ab")).toEqual(1);
+ expect(context.pending()).toEqual(1);
+
+ context.attribute("age", 25);
+
+ expect(context.treatment("exp_test_ab")).toEqual(1);
+ expect(context.pending()).toEqual(2);
+ });
+
+ it("should not re-evaluate audience when no new attributes set", () => {
+ const context = new Context(sdk, contextOptions, contextParams, audienceStrictContextResponse as any);
+
+ context.attribute("age", 15);
+
+ expect(context.treatment("exp_test_ab")).toEqual(0);
+ expect(context.pending()).toEqual(1);
+
+ expect(context.treatment("exp_test_ab")).toEqual(0);
+ expect(context.pending()).toEqual(1);
+ });
+
+ it("should not invalidate cache when audience result unchanged after attribute change", () => {
+ const context = new Context(sdk, contextOptions, contextParams, audienceStrictContextResponse as any);
+
+ context.attribute("age", 15);
+
+ expect(context.treatment("exp_test_ab")).toEqual(0);
+ expect(context.pending()).toEqual(1);
+
+ context.attribute("age", 18);
+
+ expect(context.treatment("exp_test_ab")).toEqual(0);
+ expect(context.pending()).toEqual(1);
+ });
+ });
+
+ describe("variableValue()", () => {
+ it("should not return variable values when unassigned", () => {
+ const context = new Context(sdk, contextOptions, contextParams, audienceStrictContextResponse as any);
+ expect(context.pending()).toEqual(0);
+ expect(context.variableValue("banner.size", "17")).toEqual("17");
+ });
+
+ it("should return variable values when overridden", () => {
+ const context = new Context(sdk, contextOptions, contextParams, audienceStrictContextResponse as any);
+ expect(context.pending()).toEqual(0);
+ context.override("exp_test_ab", 0);
+ expect(context.variableValue("banner.size", "17")).toEqual("tiny");
+ });
+
+ it("conflicting key disjoint audiences", () => {
+ const context1 = new Context(sdk, contextOptions, contextParams, disjointedContextResponse as any);
+ const context2 = new Context(sdk, contextOptions, contextParams, disjointedContextResponse as any);
+
+ expect(context1.pending()).toEqual(0);
+ expect(context2.pending()).toEqual(0);
+
+ expect(expectedVariants["exp_test_ab"]).not.toEqual(0);
+ expect(expectedVariants["exp_test_abc"]).not.toEqual(0);
+
+ context1.attribute("age", 20);
+ expect(context1.variableValue("icon", "square")).toEqual("arrow");
+
+ context2.attribute("age", 19);
+ expect(context2.variableValue("icon", "square")).toEqual("circle");
+ });
+
+ it("should queue exposures", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ expect(context.pending()).toEqual(0);
+
+ const experiments = context.experiments()!;
+
+ for (const [key, experimentNames] of Object.entries(variableExperiments)) {
+ const experimentName = experimentNames[0];
+ const actual = context.variableValue(key, "17");
+ const eligible = experimentName !== "exp_test_not_eligible";
+
+ if (eligible && experiments.indexOf(experimentName) !== -1) {
+ expect(actual).toEqual(expectedVariables[key]);
+ } else {
+ expect(actual).toBe("17");
+ }
+ }
+
+ expect(context.pending()).toEqual(getContextResponse.experiments.length);
+
+ (publisher.publish as ReturnType).mockReturnValue(Promise.resolve());
+
+ await context.publish();
+ expect(publisher.publish).toHaveBeenCalledWith(
+ {
+ publishedAt: 1611141535729,
+ units: publishUnits,
+ hashed: true,
+ sdkVersion: SDK_VERSION,
+ exposures: [
+ {
+ id: 1,
+ assigned: true,
+ eligible: true,
+ exposedAt: 1611141535729,
+ name: "exp_test_ab",
+ overridden: false,
+ unit: "session_id",
+ variant: 1,
+ fullOn: false,
+ custom: false,
+ audienceMismatch: false,
+ },
+ {
+ id: 2,
+ assigned: true,
+ eligible: true,
+ exposedAt: 1611141535729,
+ name: "exp_test_abc",
+ overridden: false,
+ unit: "session_id",
+ variant: 2,
+ fullOn: false,
+ custom: false,
+ audienceMismatch: false,
+ },
+ {
+ id: 3,
+ assigned: true,
+ eligible: false,
+ exposedAt: 1611141535729,
+ name: "exp_test_not_eligible",
+ overridden: false,
+ unit: "user_id",
+ variant: 0,
+ fullOn: false,
+ custom: false,
+ audienceMismatch: true,
+ },
+ {
+ id: 4,
+ assigned: true,
+ eligible: true,
+ exposedAt: 1611141535729,
+ name: "exp_test_fullon",
+ overridden: false,
+ unit: "session_id",
+ variant: 2,
+ fullOn: true,
+ custom: false,
+ audienceMismatch: true,
+ },
+ {
+ id: 5,
+ assigned: true,
+ eligible: true,
+ exposedAt: 1611141535729,
+ name: "exp_test_custom_fields",
+ overridden: false,
+ unit: "session_id",
+ variant: 1,
+ fullOn: false,
+ custom: false,
+ audienceMismatch: false,
+ },
+ ],
+ },
+ sdk,
+ context,
+ undefined
+ );
+ });
+
+ it("should return defaultValue on unknown variable", () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ expect(context.pending()).toEqual(0);
+ expect(context.variableValue("not.found", "17")).toBe("17");
+ });
+ });
+
+ describe("peekVariableValue()", () => {
+ it("should not return variable values when unassigned", () => {
+ const context = new Context(sdk, contextOptions, contextParams, audienceStrictContextResponse as any);
+ expect(context.pending()).toEqual(0);
+ expect(context.peekVariableValue("banner.size", "17")).toEqual("17");
+ });
+
+ it("should return variable values when overridden", () => {
+ const context = new Context(sdk, contextOptions, contextParams, audienceStrictContextResponse as any);
+ expect(context.pending()).toEqual(0);
+ context.override("exp_test_ab", 0);
+ expect(context.peekVariableValue("banner.size", "17")).toEqual("tiny");
+ });
+
+ it("conflicting key disjoint audiences", () => {
+ const context1 = new Context(sdk, contextOptions, contextParams, disjointedContextResponse as any);
+ const context2 = new Context(sdk, contextOptions, contextParams, disjointedContextResponse as any);
+
+ expect(context1.pending()).toEqual(0);
+ expect(context2.pending()).toEqual(0);
+
+ context1.attribute("age", 20);
+ expect(context1.peekVariableValue("icon", "square")).toEqual("arrow");
+
+ context2.attribute("age", 19);
+ expect(context2.peekVariableValue("icon", "square")).toEqual("circle");
+
+ expect(context1.pending()).toEqual(0);
+ expect(context2.pending()).toEqual(0);
+ });
+
+ it("should pick lowest experiment id on conflicting key", () => {
+ const context = new Context(sdk, contextOptions, contextParams, lowestIdConflictingKeyContextResponse as any);
+ expect(context.pending()).toEqual(0);
+
+ expect(expectedVariants["exp_test_ab"]).not.toEqual(0);
+ expect(expectedVariants["exp_test_abc"]).not.toEqual(0);
+
+ expect(context.peekVariableValue("icon", "square")).toEqual("circle");
+ });
+
+ it("should not queue exposures", () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ expect(context.pending()).toEqual(0);
+
+ const experiments = context.experiments()!;
+
+ for (const [key, experimentNames] of Object.entries(variableExperiments)) {
+ const experimentName = experimentNames[0];
+ const actual = context.peekVariableValue(key, "17");
+ const eligible = experimentName !== "exp_test_not_eligible";
+
+ if (eligible && experiments.indexOf(experimentName) !== -1) {
+ expect(actual).toEqual(expectedVariables[key]);
+ } else {
+ expect(actual).toBe("17");
+ }
+ }
+
+ expect(context.pending()).toEqual(0);
+ });
+ });
+
+ describe("variableKeys()", () => {
+ it("should return all active keys", () => {
+ const context = new Context(sdk, contextOptions, contextParams, refreshContextResponse as any);
+ expect(context.pending()).toEqual(0);
+
+ expect(context.variableKeys()).toMatchObject(variableExperiments);
+ expect(context.pending()).toEqual(0);
+ });
+ });
+
+ describe("track()", () => {
+ it("should queue goals", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ expect(context.pending()).toEqual(0);
+
+ context.track("goal1", { amount: 125, hours: 245 });
+ context.track("goal2", { tries: 7 });
+
+ expect(context.pending()).toEqual(2);
+
+ context.track("goal2", { tests: 12 });
+
+ expect(context.pending()).toEqual(3);
+
+ (publisher.publish as ReturnType).mockReturnValue(Promise.resolve());
+
+ await context.publish();
+ expect(publisher.publish).toHaveBeenCalledWith(
+ {
+ publishedAt: 1611141535729,
+ units: publishUnits,
+ hashed: true,
+ sdkVersion: SDK_VERSION,
+ goals: [
+ { achievedAt: 1611141535729, name: "goal1", properties: { amount: 125, hours: 245 } },
+ { achievedAt: 1611141535729, name: "goal2", properties: { tries: 7 } },
+ { achievedAt: 1611141535729, name: "goal2", properties: { tests: 12 } },
+ ],
+ },
+ sdk,
+ context,
+ undefined
+ );
+ });
+
+ it("should call event logger", () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+
+ defaultEventLogger.mockClear();
+ context.track("goal1", { amount: 125, hours: 245 });
+ expect(defaultEventLogger).toHaveBeenCalledTimes(1);
+ expect(defaultEventLogger).toHaveBeenCalledWith(context, "goal", {
+ achievedAt: timeOrigin,
+ name: "goal1",
+ properties: { amount: 125, hours: 245 },
+ });
+ });
+
+ it("should not throw when goal property values are numbers or objects with number values", () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ expect(context.pending()).toEqual(0);
+
+ expect(() => context.track("goal1", { test: { flt: 1.5, int: 2 } })).not.toThrowError();
+ expect(() => context.track("goal1", { test: {} })).not.toThrowError();
+ expect(() => context.track("goal1", { test: null })).not.toThrowError();
+
+ expect(context.pending()).toEqual(3);
+ });
+
+ it("should not throw when goal properties is null or undefined", () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ expect(context.pending()).toEqual(0);
+
+ expect(() => context.track("goal1")).not.toThrowError();
+ expect(() => context.track("goal1", null as any)).not.toThrowError();
+ expect(() => context.track("goal1", undefined)).not.toThrowError();
+
+ expect(context.pending()).toEqual(3);
+ });
+
+ it("should throw when goal properties not object", () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ expect(context.pending()).toEqual(0);
+
+ expect(() => context.track("goal1", 125.0 as any)).toThrowError("Goal 'goal1' properties must be of type object.");
+ expect(() => context.track("goal1", true as any)).toThrowError("Goal 'goal1' properties must be of type object.");
+ expect(() => context.track("goal1", "testy" as any)).toThrowError("Goal 'goal1' properties must be of type object.");
+ expect(() => context.track("goal1", [] as any)).toThrowError("Goal 'goal1' properties must be of type object.");
+ });
+
+ it("should throw after finalized() call", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ (publisher.publish as ReturnType).mockReturnValue(Promise.resolve());
+
+ context.treatment("exp_test_ab");
+
+ expect(context.pending()).toEqual(1);
+
+ const finalizePromise = context.finalize();
+
+ expect(context.isFinalizing()).toEqual(true);
+ expect(() => context.track("payment", { amount: 125 })).toThrow();
+
+ await finalizePromise;
+
+ expect(() => context.track("payment", { amount: 125 })).toThrow();
+ });
+
+ it("should queue when not ready", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, Promise.resolve(getContextResponse as any));
+ expect(context.pending()).toEqual(0);
+ expect(context.isReady()).toEqual(false);
+
+ context.track("goal1", { amount: 125 });
+
+ expect(context.pending()).toEqual(1);
+ expect(context.isReady()).toEqual(false);
+
+ await context.ready();
+ expect(context.pending()).toEqual(1);
+ });
+ });
+
+ describe("publish()", () => {
+ it("should not call client publish when queue is empty", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ expect(context.pending()).toEqual(0);
+
+ (publisher.publish as ReturnType).mockReturnValue(Promise.resolve());
+
+ await context.publish();
+ expect(publisher.publish).not.toHaveBeenCalled();
+ });
+
+ it("should propagate client error message", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ expect(context.pending()).toEqual(0);
+
+ context.track("goal1", { amount: 125 });
+
+ (publisher.publish as ReturnType).mockReturnValue(Promise.reject("test"));
+
+ await expect(context.publish()).rejects.toEqual("test");
+ });
+
+ it("should call client publish", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+
+ context.treatment("exp_test_ab");
+ context.treatment("exp_test_not_eligible");
+
+ vi.spyOn(Date, "now").mockImplementation(() => timeOrigin + 1);
+ context.track("goal1", { amount: 125, hours: 245 });
+
+ vi.spyOn(Date, "now").mockImplementation(() => timeOrigin + 2);
+ context.attribute("attr1", "value1");
+
+ vi.spyOn(Date, "now").mockImplementation(() => timeOrigin + 3);
+ context.attributes({
+ attr2: "value2",
+ attr3: 3,
+ attr4: 5.0,
+ attr5: true,
+ attr6: [1, 2, 3, 4],
+ attr7: null,
+ attr8: [],
+ attr9: [null, 1, 2],
+ attr10: ["one", null, "two"],
+ attr11: [null, null],
+ });
+
+ expect(context.pending()).toEqual(3);
+
+ (publisher.publish as ReturnType).mockReturnValue(Promise.resolve());
+
+ vi.spyOn(Date, "now").mockImplementation(() => timeOrigin + 100);
+
+ await context.publish();
+ expect(publisher.publish).toHaveBeenCalledTimes(1);
+ expect(publisher.publish).toHaveBeenCalledWith(
+ {
+ publishedAt: 1611141535829,
+ units: publishUnits,
+ hashed: true,
+ sdkVersion: SDK_VERSION,
+ exposures: [
+ {
+ id: 1,
+ name: "exp_test_ab",
+ unit: "session_id",
+ exposedAt: 1611141535729,
+ variant: 1,
+ assigned: true,
+ eligible: true,
+ overridden: false,
+ fullOn: false,
+ custom: false,
+ audienceMismatch: false,
+ },
+ {
+ id: 3,
+ name: "exp_test_not_eligible",
+ unit: "user_id",
+ exposedAt: 1611141535729,
+ variant: 0,
+ assigned: true,
+ eligible: false,
+ overridden: false,
+ fullOn: false,
+ custom: false,
+ audienceMismatch: true,
+ },
+ ],
+ goals: [
+ {
+ name: "goal1",
+ achievedAt: 1611141535730,
+ properties: { amount: 125, hours: 245 },
+ },
+ ],
+ attributes: [
+ { name: "attr1", setAt: 1611141535731, value: "value1" },
+ { name: "attr2", setAt: 1611141535732, value: "value2" },
+ { name: "attr3", setAt: 1611141535732, value: 3 },
+ { name: "attr4", setAt: 1611141535732, value: 5.0 },
+ { name: "attr5", setAt: 1611141535732, value: true },
+ { name: "attr6", setAt: 1611141535732, value: [1, 2, 3, 4] },
+ { name: "attr7", setAt: 1611141535732, value: null },
+ { name: "attr8", setAt: 1611141535732, value: [] },
+ { name: "attr9", setAt: 1611141535732, value: [null, 1, 2] },
+ { name: "attr10", setAt: 1611141535732, value: ["one", null, "two"] },
+ { name: "attr11", setAt: 1611141535732, value: [null, null] },
+ ],
+ },
+ sdk,
+ context,
+ undefined
+ );
+
+ expect(context.pending()).toEqual(0);
+ });
+
+ it("should pass through request options", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+
+ context.track("goal1", { amount: 125, hours: 245 });
+
+ (publisher.publish as ReturnType).mockReturnValue(Promise.resolve());
+
+ vi.spyOn(Date, "now").mockImplementation(() => timeOrigin + 100);
+
+ await context.publish({ timeout: 1234 } as any);
+ expect(publisher.publish).toHaveBeenCalledTimes(1);
+ expect(publisher.publish).toHaveBeenCalledWith(
+ {
+ publishedAt: 1611141535829,
+ units: publishUnits,
+ hashed: true,
+ sdkVersion: SDK_VERSION,
+ goals: [
+ {
+ name: "goal1",
+ achievedAt: 1611141535729,
+ properties: { amount: 125, hours: 245 },
+ },
+ ],
+ },
+ sdk,
+ context,
+ { timeout: 1234 }
+ );
+
+ expect(context.pending()).toEqual(0);
+ });
+
+ it("should call event logger on error", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+
+ context.track("goal1", { amount: 125, hours: 245 });
+
+ (publisher.publish as ReturnType).mockReturnValue(Promise.reject("test error"));
+
+ defaultEventLogger.mockClear();
+ await expect(context.publish()).rejects.toEqual("test error");
+ expect(defaultEventLogger).toHaveBeenCalledTimes(1);
+ expect(defaultEventLogger).toHaveBeenCalledWith(context, "error", "test error");
+ });
+
+ it("should call event logger on success", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+
+ context.track("goal1", { amount: 125, hours: 245 });
+
+ (publisher.publish as ReturnType).mockReturnValue(Promise.resolve());
+
+ vi.spyOn(Date, "now").mockImplementation(() => timeOrigin + 100);
+
+ defaultEventLogger.mockClear();
+ await context.publish();
+ expect(defaultEventLogger).toHaveBeenCalledTimes(1);
+ expect(defaultEventLogger).toHaveBeenCalledWith(context, "publish", {
+ publishedAt: 1611141535829,
+ units: publishUnits,
+ hashed: true,
+ sdkVersion: SDK_VERSION,
+ goals: [
+ {
+ achievedAt: 1611141535729,
+ name: "goal1",
+ properties: { amount: 125, hours: 245 },
+ },
+ ],
+ });
+ });
+
+ it("should not call client publish when failed", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, Promise.reject("bad request error text") as any);
+ await context.ready();
+ context.treatment("exp_test_ab");
+
+ vi.spyOn(Date, "now").mockImplementation(() => timeOrigin + 1);
+ context.track("goal1", { amount: 125, hours: 245 });
+
+ expect(context.pending()).toEqual(2);
+
+ await context.publish();
+ expect(publisher.publish).not.toHaveBeenCalled();
+ expect(context.pending()).toEqual(0);
+ });
+
+ it("should reset internal queues and keep attributes overrides and custom assignments", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+
+ context.treatment("exp_test_ab");
+ context.track("goal1", { amount: 125, hours: 245 });
+ context.attribute("attr1", "value1");
+
+ context.override("not_found", 3);
+ expect(context.treatment("not_found")).toEqual(3);
+
+ context.customAssignment("exp_test_abc", 3);
+ expect(context.treatment("exp_test_abc")).toEqual(3);
+
+ expect(context.pending()).toEqual(4);
+
+ (publisher.publish as ReturnType).mockReturnValue(Promise.resolve({}));
+
+ vi.spyOn(Date, "now").mockImplementation(() => timeOrigin + 100);
+
+ await context.publish();
+ expect(publisher.publish).toHaveBeenCalledTimes(1);
+ expect(publisher.publish).toHaveBeenCalledWith(
+ {
+ publishedAt: 1611141535829,
+ units: publishUnits,
+ hashed: true,
+ sdkVersion: SDK_VERSION,
+ exposures: [
+ {
+ id: 1,
+ name: "exp_test_ab",
+ unit: "session_id",
+ exposedAt: 1611141535729,
+ variant: 1,
+ assigned: true,
+ eligible: true,
+ overridden: false,
+ fullOn: false,
+ custom: false,
+ audienceMismatch: false,
+ },
+ {
+ id: 0,
+ name: "not_found",
+ unit: null,
+ exposedAt: 1611141535729,
+ variant: 3,
+ assigned: false,
+ eligible: true,
+ overridden: true,
+ fullOn: false,
+ custom: false,
+ audienceMismatch: false,
+ },
+ {
+ id: 2,
+ name: "exp_test_abc",
+ unit: "session_id",
+ exposedAt: 1611141535729,
+ variant: 3,
+ assigned: true,
+ eligible: true,
+ overridden: false,
+ fullOn: false,
+ custom: true,
+ audienceMismatch: false,
+ },
+ ],
+ goals: [
+ {
+ name: "goal1",
+ achievedAt: 1611141535729,
+ properties: { amount: 125, hours: 245 },
+ },
+ ],
+ attributes: [
+ { name: "attr1", setAt: 1611141535729, value: "value1" },
+ ],
+ },
+ sdk,
+ context,
+ undefined
+ );
+
+ expect(context.pending()).toEqual(0);
+
+ (publisher.publish as ReturnType).mockClear();
+
+ context.track("goal2", { test: 999 });
+
+ await context.publish();
+ expect(publisher.publish).toHaveBeenCalledTimes(1);
+ expect(publisher.publish).toHaveBeenCalledWith(
+ {
+ publishedAt: 1611141535829,
+ units: publishUnits,
+ hashed: true,
+ sdkVersion: SDK_VERSION,
+ goals: [
+ {
+ name: "goal2",
+ achievedAt: 1611141535829,
+ properties: { test: 999 },
+ },
+ ],
+ attributes: [
+ { name: "attr1", setAt: 1611141535729, value: "value1" },
+ ],
+ },
+ sdk,
+ context,
+ undefined
+ );
+
+ expect(context.pending()).toEqual(0);
+
+ expect(context.treatment("exp_test_abc")).toEqual(3);
+ expect(context.treatment("not_found")).toEqual(3);
+
+ expect(context.pending()).toEqual(0);
+ });
+
+ it("should throw after finalized() call", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ (publisher.publish as ReturnType).mockReturnValue(Promise.resolve());
+
+ context.treatment("exp_test_ab");
+
+ expect(context.pending()).toEqual(1);
+
+ const finalizePromise = context.finalize();
+
+ expect(context.isFinalizing()).toEqual(true);
+ expect(() => context.publish()).toThrow();
+
+ await finalizePromise;
+
+ expect(() => context.publish()).toThrow();
+ });
+ });
+
+ describe("finalize()", () => {
+ it("should not call client publish when queue is empty", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ expect(context.pending()).toEqual(0);
+
+ (publisher.publish as ReturnType).mockReturnValue(Promise.resolve());
+
+ expect(context.isFinalizing()).toEqual(false);
+
+ await context.finalize();
+ expect(publisher.publish).not.toHaveBeenCalled();
+ expect(context.isFinalizing()).toEqual(false);
+ expect(context.isFinalized()).toEqual(true);
+ });
+
+ it("should propagate client error message", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ expect(context.pending()).toEqual(0);
+
+ context.treatment("exp_test_ab");
+
+ (publisher.publish as ReturnType).mockReturnValue(Promise.reject("test"));
+
+ const finalizePromise = context.finalize();
+
+ expect(context.isFinalizing()).toEqual(true);
+ expect(context.isFinalized()).toEqual(false);
+
+ await expect(finalizePromise).rejects.toEqual("test");
+ expect(context.isFinalizing()).toEqual(false);
+ expect(context.isFinalized()).toEqual(false);
+ });
+
+ it("should call client publish", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+
+ context.treatment("exp_test_ab");
+
+ expect(context.pending()).toEqual(1);
+
+ (publisher.publish as ReturnType).mockReturnValue(Promise.resolve());
+
+ vi.spyOn(Date, "now").mockImplementation(() => timeOrigin + 100);
+
+ const finalizePromise = context.finalize();
+
+ expect(context.isFinalizing()).toEqual(true);
+ expect(context.isFinalized()).toEqual(false);
+
+ await finalizePromise;
+ expect(publisher.publish).toHaveBeenCalledTimes(1);
+ expect(publisher.publish).toHaveBeenCalledWith(
+ {
+ publishedAt: 1611141535829,
+ units: publishUnits,
+ hashed: true,
+ sdkVersion: SDK_VERSION,
+ exposures: [
+ {
+ id: 1,
+ name: "exp_test_ab",
+ unit: "session_id",
+ exposedAt: 1611141535729,
+ variant: 1,
+ assigned: true,
+ eligible: true,
+ overridden: false,
+ fullOn: false,
+ custom: false,
+ audienceMismatch: false,
+ },
+ ],
+ },
+ sdk,
+ context,
+ undefined
+ );
+
+ expect(context.pending()).toEqual(0);
+ expect(context.isFinalizing()).toEqual(false);
+ expect(context.isFinalized()).toEqual(true);
+ });
+
+ it("should pass through request options", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+
+ context.treatment("exp_test_ab");
+
+ expect(context.pending()).toEqual(1);
+
+ (publisher.publish as ReturnType).mockReturnValue(Promise.resolve());
+
+ vi.spyOn(Date, "now").mockImplementation(() => timeOrigin + 100);
+
+ const finalizePromise = context.finalize({ timeout: 1234 } as any);
+
+ expect(context.isFinalizing()).toEqual(true);
+ expect(context.isFinalized()).toEqual(false);
+
+ await finalizePromise;
+ expect(publisher.publish).toHaveBeenCalledTimes(1);
+ expect(publisher.publish).toHaveBeenCalledWith(
+ {
+ publishedAt: 1611141535829,
+ units: publishUnits,
+ hashed: true,
+ sdkVersion: SDK_VERSION,
+ exposures: [
+ {
+ id: 1,
+ name: "exp_test_ab",
+ unit: "session_id",
+ exposedAt: 1611141535729,
+ variant: 1,
+ assigned: true,
+ eligible: true,
+ overridden: false,
+ fullOn: false,
+ custom: false,
+ audienceMismatch: false,
+ },
+ ],
+ },
+ sdk,
+ context,
+ { timeout: 1234 }
+ );
+
+ expect(context.pending()).toEqual(0);
+ expect(context.isFinalizing()).toEqual(false);
+ expect(context.isFinalized()).toEqual(true);
+ });
+
+ it("should call event logger on error", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+
+ context.treatment("exp_test_ab");
+
+ (publisher.publish as ReturnType).mockReturnValue(Promise.reject("test error"));
+
+ defaultEventLogger.mockClear();
+ const finalizePromise = context.finalize();
+
+ expect(context.isFinalizing()).toEqual(true);
+ expect(context.isFinalized()).toEqual(false);
+
+ await expect(finalizePromise).rejects.toEqual("test error");
+ expect(defaultEventLogger).toHaveBeenCalledTimes(1);
+ expect(defaultEventLogger).toHaveBeenCalledWith(context, "error", "test error");
+ expect(context.isFinalizing()).toEqual(false);
+ expect(context.isFinalized()).toEqual(false);
+ });
+
+ it("should call event logger on success", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+
+ context.treatment("exp_test_ab");
+
+ (publisher.publish as ReturnType).mockReturnValue(Promise.resolve());
+
+ defaultEventLogger.mockClear();
+ const finalizePromise = context.finalize();
+
+ expect(context.isFinalizing()).toEqual(true);
+ expect(context.isFinalized()).toEqual(false);
+
+ await finalizePromise;
+ expect(defaultEventLogger).toHaveBeenCalledTimes(2);
+ expect(defaultEventLogger).toHaveBeenLastCalledWith(context, "finalize", undefined);
+ expect(context.isFinalizing()).toEqual(false);
+ expect(context.isFinalized()).toEqual(true);
+ });
+
+ it("should not call client publish when failed", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, Promise.reject("bad request error text") as any);
+ await context.ready();
+ context.treatment("exp_test_ab");
+
+ expect(context.pending()).toEqual(1);
+
+ expect(context.isFinalizing()).toEqual(false);
+
+ await context.finalize();
+ expect(publisher.publish).not.toHaveBeenCalled();
+ expect(context.pending()).toEqual(0);
+ expect(context.isFinalizing()).toEqual(false);
+ expect(context.isFinalized()).toEqual(true);
+ });
+
+ it("should return current promise when called twice", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+
+ context.treatment("exp_test_ab");
+
+ (publisher.publish as ReturnType).mockReturnValue(Promise.resolve());
+
+ const firstPromise = context.finalize();
+ const secondPromise = context.finalize();
+
+ expect(secondPromise).toBe(firstPromise);
+
+ expect(context.isFinalizing()).toEqual(true);
+ expect(context.isFinalized()).toEqual(false);
+
+ await secondPromise;
+
+ expect(context.isFinalizing()).toEqual(false);
+ expect(context.isFinalized()).toEqual(true);
+ });
+
+ it("should return completed promise when already finalized", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+
+ context.treatment("exp_test_ab");
+
+ (publisher.publish as ReturnType).mockReturnValue(Promise.resolve());
+
+ await context.finalize();
+ expect(context.isFinalizing()).toEqual(false);
+ expect(context.isFinalized()).toEqual(true);
+
+ await context.finalize();
+ });
+ });
+
+ describe("override()", () => {
+ it("should be callable before ready()", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, Promise.resolve(getContextResponse as any));
+ expect(context.isReady()).toEqual(false);
+ expect(context.isFailed()).toEqual(false);
+ expect(context.isFinalized()).toEqual(false);
+
+ context.override("exp_test_ab", 1);
+ context.overrides({
+ exp_test_ab: 2,
+ exp_test_abc: 2,
+ not_found: 3,
+ });
+
+ await context.ready();
+ expect(context.isReady()).toEqual(true);
+ expect(context.data()).toStrictEqual(getContextResponse);
+
+ context.treatment("exp_test_ab");
+ context.treatment("exp_test_abc");
+
+ (publisher.publish as ReturnType).mockReturnValue(Promise.resolve());
+
+ vi.spyOn(Date, "now").mockImplementation(() => timeOrigin + 100);
+
+ await context.publish();
+ expect(publisher.publish).toHaveBeenCalledTimes(1);
+ expect(publisher.publish).toHaveBeenCalledWith(
+ {
+ publishedAt: 1611141535829,
+ units: publishUnits,
+ hashed: true,
+ sdkVersion: SDK_VERSION,
+ exposures: [
+ {
+ id: 1,
+ name: "exp_test_ab",
+ unit: "session_id",
+ exposedAt: 1611141535729,
+ variant: 2,
+ assigned: false,
+ eligible: true,
+ overridden: true,
+ fullOn: false,
+ custom: false,
+ audienceMismatch: false,
+ },
+ {
+ id: 2,
+ name: "exp_test_abc",
+ unit: "session_id",
+ exposedAt: 1611141535729,
+ variant: 2,
+ assigned: false,
+ eligible: true,
+ overridden: true,
+ fullOn: false,
+ custom: false,
+ audienceMismatch: false,
+ },
+ ],
+ },
+ sdk,
+ context,
+ undefined
+ );
+ });
+ });
+
+ describe("customAssignment()", () => {
+ it("should override natural assignment and set custom flag", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ expect(context.pending()).toEqual(0);
+
+ context.customAssignment("exp_test_abc", 11);
+
+ expect(context.pending()).toEqual(0);
+
+ context.treatment("exp_test_abc");
+
+ expect(context.pending()).toEqual(1);
+
+ (publisher.publish as ReturnType).mockReturnValue(Promise.resolve());
+
+ await context.publish();
+ expect(publisher.publish).toHaveBeenCalledWith(
+ {
+ publishedAt: 1611141535729,
+ units: publishUnits,
+ hashed: true,
+ sdkVersion: SDK_VERSION,
+ exposures: [
+ {
+ id: 2,
+ assigned: true,
+ eligible: true,
+ exposedAt: 1611141535729,
+ name: "exp_test_abc",
+ overridden: false,
+ unit: "session_id",
+ variant: 11,
+ fullOn: false,
+ custom: true,
+ audienceMismatch: false,
+ },
+ ],
+ },
+ sdk,
+ context,
+ undefined
+ );
+ });
+
+ it("should not override full-on or non-eligible assignment", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ expect(context.pending()).toEqual(0);
+
+ context.customAssignment("exp_test_not_eligible", 11);
+ context.customAssignment("exp_test_fullon", 11);
+
+ expect(context.pending()).toEqual(0);
+
+ context.treatment("exp_test_not_eligible");
+ context.treatment("exp_test_fullon");
+
+ expect(context.pending()).toEqual(2);
+
+ (publisher.publish as ReturnType).mockReturnValue(Promise.resolve());
+
+ await context.publish();
+ expect(publisher.publish).toHaveBeenCalledWith(
+ {
+ publishedAt: 1611141535729,
+ units: publishUnits,
+ hashed: true,
+ sdkVersion: SDK_VERSION,
+ exposures: [
+ {
+ id: 3,
+ assigned: true,
+ eligible: false,
+ exposedAt: 1611141535729,
+ name: "exp_test_not_eligible",
+ overridden: false,
+ unit: "user_id",
+ variant: 0,
+ fullOn: false,
+ custom: false,
+ audienceMismatch: true,
+ },
+ {
+ id: 4,
+ assigned: true,
+ eligible: true,
+ exposedAt: 1611141535729,
+ name: "exp_test_fullon",
+ overridden: false,
+ unit: "session_id",
+ variant: 2,
+ fullOn: true,
+ custom: false,
+ audienceMismatch: true,
+ },
+ ],
+ },
+ sdk,
+ context,
+ undefined
+ );
+ });
+
+ it("should be callable before ready()", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, Promise.resolve(getContextResponse as any));
+ expect(context.isReady()).toEqual(false);
+ expect(context.isFailed()).toEqual(false);
+ expect(context.isFinalized()).toEqual(false);
+
+ context.customAssignment("exp_test_ab", 1);
+ context.customAssignments({
+ exp_test_ab: 2,
+ exp_test_abc: 2,
+ not_found: 3,
+ });
+
+ await context.ready();
+ expect(context.isReady()).toEqual(true);
+ expect(context.data()).toStrictEqual(getContextResponse);
+
+ context.treatment("exp_test_ab");
+ context.treatment("exp_test_abc");
+
+ (publisher.publish as ReturnType).mockReturnValue(Promise.resolve());
+
+ vi.spyOn(Date, "now").mockImplementation(() => timeOrigin + 100);
+
+ await context.publish();
+ expect(publisher.publish).toHaveBeenCalledTimes(1);
+ expect(publisher.publish).toHaveBeenCalledWith(
+ {
+ publishedAt: 1611141535829,
+ units: publishUnits,
+ hashed: true,
+ sdkVersion: SDK_VERSION,
+ exposures: [
+ {
+ id: 1,
+ name: "exp_test_ab",
+ unit: "session_id",
+ exposedAt: 1611141535729,
+ variant: 2,
+ assigned: true,
+ eligible: true,
+ overridden: false,
+ fullOn: false,
+ custom: true,
+ audienceMismatch: false,
+ },
+ {
+ id: 2,
+ name: "exp_test_abc",
+ unit: "session_id",
+ exposedAt: 1611141535729,
+ variant: 2,
+ assigned: true,
+ eligible: true,
+ overridden: false,
+ fullOn: false,
+ custom: true,
+ audienceMismatch: false,
+ },
+ ],
+ },
+ sdk,
+ context,
+ undefined
+ );
+ });
+
+ it("should throw after finalized() call", async () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ (publisher.publish as ReturnType).mockReturnValue(Promise.resolve());
+
+ context.treatment("exp_test_ab");
+
+ expect(context.pending()).toEqual(1);
+
+ const finalizePromise = context.finalize();
+
+ expect(context.isFinalizing()).toEqual(true);
+ expect(() => context.customAssignment("exp_test_ab", 3)).toThrow();
+
+ await finalizePromise;
+
+ expect(() => context.customAssignment("exp_test_ab", 3)).toThrow();
+ });
+ });
+
+ describe("customFieldKeys()", () => {
+ it("should return custom field keys", () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ expect(context.pending()).toEqual(0);
+ const keys = context.customFieldKeys();
+
+ expect(context.isReady()).toEqual(true);
+ expect(keys).toEqual([
+ "country",
+ "json_object",
+ "json_array",
+ "json_number",
+ "json_string",
+ "json_boolean",
+ "json_null",
+ "json_invalid",
+ "languages",
+ "text_field",
+ "string_field",
+ "number_field",
+ "boolean_field",
+ "false_boolean_field",
+ "invalid_type_field",
+ ]);
+ });
+ });
+
+ describe("customFieldValue()", () => {
+ it("should return custom field value", () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ expect(context.pending()).toEqual(0);
+ const value = context.customFieldValue("exp_test_custom_fields", "country");
+
+ expect(context.isReady()).toEqual(true);
+ expect(value).toEqual("US,PT,ES");
+ });
+
+ it("should return parsed JSON fields", () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ expect(context.pending()).toEqual(0);
+
+ expect(context.customFieldValue("exp_test_abc", "json_object")).toEqual({ 123: 1, 456: 0 });
+ expect(context.customFieldValue("exp_test_abc", "json_array")).toEqual(["hello", "world"]);
+ expect(context.customFieldValue("exp_test_abc", "json_number")).toEqual(123);
+ expect(context.customFieldValue("exp_test_abc", "json_string")).toEqual("hello");
+ expect(context.customFieldValue("exp_test_abc", "json_boolean")).toEqual(true);
+ expect(context.customFieldValue("exp_test_abc", "json_null")).toEqual(null);
+ });
+
+ it("should return string and text fields", () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ expect(context.pending()).toEqual(0);
+
+ expect(context.customFieldValue("exp_test_custom_fields", "text_field")).toEqual("hello text");
+ expect(context.customFieldValue("exp_test_custom_fields", "string_field")).toEqual("hello string");
+ });
+
+ it("should return parsed number fields", () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ expect(context.pending()).toEqual(0);
+
+ expect(context.customFieldValue("exp_test_custom_fields", "number_field")).toEqual(123);
+ });
+
+ it("should return parsed boolean fields", () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ expect(context.pending()).toEqual(0);
+
+ expect(context.customFieldValue("exp_test_custom_fields", "boolean_field")).toEqual(true);
+ expect(context.customFieldValue("exp_test_custom_fields", "false_boolean_field")).toEqual(false);
+ });
+
+ it("should log an error when JSON cannot be parsed", () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ expect(context.pending()).toEqual(0);
+
+ expect(context.customFieldValue("exp_test_abc", "json_invalid")).toEqual(null);
+ expect(defaultEventLogger).toHaveBeenCalledWith(
+ context,
+ "error",
+ expect.objectContaining({
+ message: expect.stringContaining("Failed to parse JSON custom field value 'json_invalid' for experiment 'exp_test_abc'")
+ })
+ );
+ });
+
+ it("should log an error when a field type is invalid", () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ expect(context.pending()).toEqual(0);
+
+ expect(context.customFieldValue("exp_test_custom_fields", "invalid_type_field")).toEqual(null);
+ expect(defaultEventLogger).toHaveBeenCalledWith(
+ context,
+ "error",
+ expect.objectContaining({
+ message: "Unknown custom field type 'invalid' for experiment 'exp_test_custom_fields' and key 'invalid_type_field' - you may need to upgrade to the latest SDK version"
+ })
+ );
+ });
+ });
+
+ describe("customFieldValueType()", () => {
+ it("should return custom field value type", () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ expect(context.pending()).toEqual(0);
+ const value = context.customFieldValueType("exp_test_custom_fields", "country");
+
+ expect(context.isReady()).toEqual(true);
+ expect(value).toEqual("string");
+ });
+ });
+
+ describe("includeSystemAttributes", () => {
+ it("should not include system attributes by default", async () => {
+ const defaultOptions = { publishDelay: -1, refreshPeriod: 0 };
+
+ const context = new Context(sdk, defaultOptions, contextParams, getContextResponse as any);
+ (publisher.publish as ReturnType).mockReturnValue(Promise.resolve());
+
+ context.treatment("exp_test_ab");
+
+ await context.publish();
+ const call = (publisher.publish as ReturnType).mock.calls[0];
+ const request = call[0];
+
+ expect(request.attributes).toBeUndefined();
+ });
+
+ it("should include system attributes when includeSystemAttributes is true", async () => {
+ const optionsWithSystemAttrs = {
+ publishDelay: -1,
+ refreshPeriod: 0,
+ includeSystemAttributes: true,
+ };
+
+ const context = new Context(sdk, optionsWithSystemAttrs, contextParams, getContextResponse as any);
+ (publisher.publish as ReturnType).mockReturnValue(Promise.resolve());
+
+ context.treatment("exp_test_ab");
+
+ await context.publish();
+ const call = (publisher.publish as ReturnType).mock.calls[0];
+ const request = call[0];
+
+ expect(request.attributes).toBeDefined();
+ expect(request.attributes.length).toBeGreaterThanOrEqual(4);
+
+ const sdkNameAttr = request.attributes.find((a: any) => a.name === "sdk_name");
+ const sdkVersionAttr = request.attributes.find((a: any) => a.name === "sdk_version");
+ const applicationAttr = request.attributes.find((a: any) => a.name === "application");
+ const environmentAttr = request.attributes.find((a: any) => a.name === "environment");
+
+ expect(sdkNameAttr).toBeDefined();
+ expect(sdkNameAttr.value).toEqual("absmartly-javascript-sdk");
+ expect(sdkNameAttr.setAt).toEqual(expect.any(Number));
+
+ expect(sdkVersionAttr).toBeDefined();
+ expect(sdkVersionAttr.value).toEqual(SDK_VERSION);
+ expect(sdkVersionAttr.setAt).toEqual(expect.any(Number));
+
+ expect(applicationAttr).toBeDefined();
+ expect(applicationAttr.value).toEqual("website");
+ expect(applicationAttr.setAt).toEqual(expect.any(Number));
+
+ expect(environmentAttr).toBeDefined();
+ expect(environmentAttr.value).toEqual("production");
+ expect(environmentAttr.setAt).toEqual(expect.any(Number));
+ });
+
+ it("should prepend system attributes before user attributes", async () => {
+ const optionsWithSystemAttrs = {
+ publishDelay: -1,
+ refreshPeriod: 0,
+ includeSystemAttributes: true,
+ };
+
+ const context = new Context(sdk, optionsWithSystemAttrs, contextParams, getContextResponse as any);
+ (publisher.publish as ReturnType).mockReturnValue(Promise.resolve());
+
+ context.attribute("custom_attr", "custom_value");
+ context.treatment("exp_test_ab");
+
+ await context.publish();
+ const call = (publisher.publish as ReturnType).mock.calls[0];
+ const request = call[0];
+
+ expect(request.attributes[0].name).toEqual("sdk_name");
+ expect(request.attributes[1].name).toEqual("sdk_version");
+ expect(request.attributes[2].name).toEqual("application");
+ expect(request.attributes[3].name).toEqual("environment");
+ expect(request.attributes[4].name).toEqual("custom_attr");
+ expect(request.attributes[4].value).toEqual("custom_value");
+ });
+
+ it("should include app_version when application version is set", async () => {
+ client.getApplication.mockReturnValueOnce({ name: "website", version: 3 });
+
+ const optionsWithSystemAttrs = {
+ publishDelay: -1,
+ refreshPeriod: 0,
+ includeSystemAttributes: true,
+ };
+
+ const context = new Context(sdk, optionsWithSystemAttrs, contextParams, getContextResponse as any);
+ (publisher.publish as ReturnType).mockReturnValue(Promise.resolve());
+
+ context.treatment("exp_test_ab");
+
+ await context.publish();
+ const call = (publisher.publish as ReturnType).mock.calls[0];
+ const request = call[0];
+
+ const appVersionAttr = request.attributes.find((a: any) => a.name === "app_version");
+ expect(appVersionAttr).toBeDefined();
+ expect(appVersionAttr.value).toEqual(3);
+ });
+
+ it("should not include app_version when application version is 0", async () => {
+ const optionsWithSystemAttrs = {
+ publishDelay: -1,
+ refreshPeriod: 0,
+ includeSystemAttributes: true,
+ };
+
+ const context = new Context(sdk, optionsWithSystemAttrs, contextParams, getContextResponse as any);
+ (publisher.publish as ReturnType).mockReturnValue(Promise.resolve());
+
+ context.treatment("exp_test_ab");
+
+ await context.publish();
+ const call = (publisher.publish as ReturnType).mock.calls[0];
+ const request = call[0];
+
+ const appVersionAttr = request.attributes.find((a: any) => a.name === "app_version");
+ expect(appVersionAttr).toBeUndefined();
+ });
+
+ it("should include app_version when application version is a semver string", async () => {
+ client.getApplication.mockReturnValueOnce({ name: "website", version: "1.2.3" });
+
+ const optionsWithSystemAttrs = {
+ publishDelay: -1,
+ refreshPeriod: 0,
+ includeSystemAttributes: true,
+ };
+
+ const context = new Context(sdk, optionsWithSystemAttrs, contextParams, getContextResponse as any);
+ (publisher.publish as ReturnType).mockReturnValue(Promise.resolve());
+
+ context.treatment("exp_test_ab");
+
+ await context.publish();
+ const call = (publisher.publish as ReturnType).mock.calls[0];
+ const request = call[0];
+
+ const appVersionAttr = request.attributes.find((a: any) => a.name === "app_version");
+ expect(appVersionAttr).toBeDefined();
+ expect(appVersionAttr.value).toEqual("1.2.3");
+ });
+
+ it("should only include user attributes when includeSystemAttributes is not set", async () => {
+ const defaultOptions = { publishDelay: -1, refreshPeriod: 0 };
+
+ const context = new Context(sdk, defaultOptions, contextParams, getContextResponse as any);
+ (publisher.publish as ReturnType).mockReturnValue(Promise.resolve());
+
+ context.attribute("custom_attr", "custom_value");
+ context.treatment("exp_test_ab");
+
+ await context.publish();
+ const call = (publisher.publish as ReturnType).mock.calls[0];
+ const request = call[0];
+
+ expect(request.attributes).toEqual([
+ { name: "custom_attr", value: "custom_value", setAt: expect.any(Number) },
+ ]);
+ });
+ });
+
+ describe("publishDelay auto-flush", () => {
+ beforeEach(() => {
+ vi.useFakeTimers({ shouldAdvanceTime: false });
+ vi.spyOn(Date, "now").mockImplementation(() => timeOrigin);
+ });
+
+ afterEach(() => {
+ vi.useRealTimers();
+ });
+
+ it("should auto-flush after publishDelay ms when treatment is called", async () => {
+ const options = { publishDelay: 100, refreshPeriod: 0 };
+ (publisher.publish as ReturnType).mockReturnValue(Promise.resolve());
+
+ const context = new Context(sdk, options, contextParams, getContextResponse as any);
+ context.treatment("exp_test_ab");
+ expect(publisher.publish).not.toHaveBeenCalled();
+
+ await vi.advanceTimersByTimeAsync(100);
+ expect(publisher.publish).toHaveBeenCalledTimes(1);
+ });
+
+ it("should auto-flush after publishDelay ms when track is called", async () => {
+ const options = { publishDelay: 100, refreshPeriod: 0 };
+ (publisher.publish as ReturnType).mockReturnValue(Promise.resolve());
+
+ const context = new Context(sdk, options, contextParams, getContextResponse as any);
+ context.track("goal1", { amount: 100 });
+ expect(publisher.publish).not.toHaveBeenCalled();
+
+ await vi.advanceTimersByTimeAsync(100);
+ expect(publisher.publish).toHaveBeenCalledTimes(1);
+ });
+
+ it("should not create multiple timers for multiple queued events", async () => {
+ const options = { publishDelay: 100, refreshPeriod: 0 };
+ (publisher.publish as ReturnType).mockReturnValue(Promise.resolve());
+
+ const context = new Context(sdk, options, contextParams, getContextResponse as any);
+ context.treatment("exp_test_ab");
+ context.treatment("exp_test_abc");
+ context.track("goal1");
+
+ await vi.advanceTimersByTimeAsync(100);
+ expect(publisher.publish).toHaveBeenCalledTimes(1);
+ });
+
+ it("should start auto-flush timer after ready if events queued before ready", async () => {
+ const options = { publishDelay: 100, refreshPeriod: 0 };
+ (publisher.publish as ReturnType).mockReturnValue(Promise.resolve());
+
+ let resolveData: (data: any) => void;
+ const dataPromise = new Promise((resolve) => { resolveData = resolve; });
+
+ const context = new Context(sdk, options, contextParams, dataPromise);
+ expect(context.isReady()).toBe(false);
+
+ // Resolve the promise to make context ready
+ resolveData!(getContextResponse);
+ await context.ready();
+ expect(context.isReady()).toBe(true);
+
+ // Queue events after ready
+ context.treatment("exp_test_ab");
+
+ // Timer should fire after publishDelay
+ await vi.advanceTimersByTimeAsync(100);
+ expect(publisher.publish).toHaveBeenCalledTimes(1);
+ });
+ });
+
+ describe("refreshPeriod auto-refresh", () => {
+ beforeEach(() => {
+ vi.useFakeTimers({ shouldAdvanceTime: false });
+ vi.spyOn(Date, "now").mockImplementation(() => timeOrigin);
+ });
+
+ afterEach(() => {
+ vi.useRealTimers();
+ });
+
+ it("should start refresh timer when refreshPeriod > 0", async () => {
+ const options = { publishDelay: -1, refreshPeriod: 1000 };
+ (provider.getContextData as ReturnType).mockReturnValue(Promise.resolve(getContextResponse));
+
+ const context = new Context(sdk, options, contextParams, getContextResponse as any);
+ expect(context.isReady()).toBe(true);
+
+ await vi.advanceTimersByTimeAsync(1000);
+ expect(provider.getContextData).toHaveBeenCalledTimes(1);
+ });
+
+ it("should call refresh multiple times on interval", async () => {
+ const options = { publishDelay: -1, refreshPeriod: 1000 };
+ (provider.getContextData as ReturnType).mockReturnValue(Promise.resolve(getContextResponse));
+
+ const context = new Context(sdk, options, contextParams, getContextResponse as any);
+
+ await vi.advanceTimersByTimeAsync(3000);
+ expect(provider.getContextData).toHaveBeenCalledTimes(3);
+ });
+
+ it("should stop refresh timer on finalize", async () => {
+ const options = { publishDelay: -1, refreshPeriod: 1000 };
+ (provider.getContextData as ReturnType).mockReturnValue(Promise.resolve(getContextResponse));
+
+ const context = new Context(sdk, options, contextParams, getContextResponse as any);
+
+ await context.finalize();
+
+ await vi.advanceTimersByTimeAsync(3000);
+ expect(provider.getContextData).not.toHaveBeenCalled();
+ });
+ });
+
+ describe("event logger resilience", () => {
+ it("should not crash when event logger throws on treatment", () => {
+ const throwingLogger = vi.fn().mockImplementation(() => { throw new Error("logger broken"); });
+ const context = new Context(sdk, { ...contextOptions, eventLogger: throwingLogger }, contextParams, getContextResponse as any);
+ expect(() => context.treatment("exp_test_ab")).not.toThrow();
+ });
+
+ it("should not crash when event logger throws on track", () => {
+ const throwingLogger = vi.fn().mockImplementation(() => { throw new Error("logger broken"); });
+ const context = new Context(sdk, { ...contextOptions, eventLogger: throwingLogger }, contextParams, getContextResponse as any);
+ expect(() => context.track("goal1", { amount: 1 })).not.toThrow();
+ });
+
+ it("should not crash when event logger throws on publish", async () => {
+ const throwingLogger = vi.fn().mockImplementation(() => { throw new Error("logger broken"); });
+ (publisher.publish as ReturnType).mockReturnValue(Promise.resolve());
+ const context = new Context(sdk, { ...contextOptions, eventLogger: throwingLogger }, contextParams, getContextResponse as any);
+ context.treatment("exp_test_ab");
+ await expect(context.publish()).resolves.toBeUndefined();
+ });
+ });
+
+ describe("flush data preservation on failure", () => {
+ it("should preserve events on publish failure and retry", async () => {
+ (publisher.publish as ReturnType)
+ .mockReturnValueOnce(Promise.reject(new Error("network error")))
+ .mockReturnValueOnce(Promise.resolve());
+
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ context.treatment("exp_test_ab");
+
+ // First publish fails
+ await expect(context.publish()).rejects.toThrow("network error");
+
+ // Events should still be pending
+ expect(context.pending()).toBe(1);
+
+ // Second publish succeeds with the preserved events
+ await context.publish();
+ expect(context.pending()).toBe(0);
+ expect(publisher.publish).toHaveBeenCalledTimes(2);
+ });
+
+ it("should not lose new events queued during in-flight publish", async () => {
+ let resolvePublish: () => void;
+ (publisher.publish as ReturnType).mockReturnValue(new Promise((resolve) => { resolvePublish = resolve; }));
+
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ context.treatment("exp_test_ab");
+
+ const publishPromise = context.publish();
+
+ // Queue new event while publish is in-flight
+ context.track("goal1");
+ expect(context.pending()).toBe(1); // new event pending
+
+ // Resolve the first publish
+ resolvePublish!();
+ await publishPromise;
+
+ // New event should still be pending
+ expect(context.pending()).toBe(1);
+ });
+ });
+
+ describe("override cache invalidation", () => {
+ it("should queue new exposure when override value changes", () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ context.override("exp_test_ab", 2);
+ context.treatment("exp_test_ab");
+ expect(context.pending()).toBe(1);
+
+ // Same override value — no new exposure
+ context.override("exp_test_ab", 2);
+ context.treatment("exp_test_ab");
+ expect(context.pending()).toBe(1);
+
+ // Different override value — new exposure
+ context.override("exp_test_ab", 3);
+ context.treatment("exp_test_ab");
+ expect(context.pending()).toBe(2);
+ });
+ });
+
+ describe("input validation", () => {
+ it("treatment() should throw for empty experiment name", () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ expect(() => context.treatment("")).toThrow("Experiment name must be a non-empty string");
+ });
+
+ it("peek() should throw for empty experiment name", () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ expect(() => context.peek("")).toThrow("Experiment name must be a non-empty string");
+ });
+
+ it("track() should throw for empty goal name", () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ expect(() => context.track("")).toThrow("Goal name must be a non-empty string");
+ });
+
+ it("attribute() should throw for empty attribute name", () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ expect(() => context.attribute("", "value")).toThrow("Attribute name must be a non-empty string");
+ });
+
+ it("variableValue() should throw for empty key", () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ expect(() => context.variableValue("", "default")).toThrow("Variable key must be a non-empty string");
+ });
+
+ it("override() should throw for empty experiment name", () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ expect(() => context.override("", 1)).toThrow("Experiment name must be a non-empty string");
+ });
+
+ it("override() should throw for negative variant", () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ expect(() => context.override("exp_test_ab", -1)).toThrow("Variant must be a non-negative integer");
+ });
+
+ it("override() should throw for non-integer variant", () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ expect(() => context.override("exp_test_ab", 1.5)).toThrow("Variant must be a non-negative integer");
+ });
+
+ it("customAssignment() should throw for empty experiment name", () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ expect(() => context.customAssignment("", 1)).toThrow("Experiment name must be a non-empty string");
+ });
+
+ it("customAssignment() should throw for negative variant", () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ expect(() => context.customAssignment("exp_test_ab", -1)).toThrow("Variant must be a non-negative integer");
+ });
+
+ it("customFieldValue() should throw for empty experiment name", () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ expect(() => context.customFieldValue("", "key")).toThrow("Experiment name must be a non-empty string");
+ });
+
+ it("customFieldValue() should throw for empty key", () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ expect(() => context.customFieldValue("exp_test_ab", "")).toThrow("Key must be a non-empty string");
+ });
+ });
+
+ describe("readyError()", () => {
+ it("should return null when context succeeds", () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ expect(context.readyError()).toBe(null);
+ });
+
+ it("should return the error when context fails", async () => {
+ const error = new Error("network failure");
+ const context = new Context(sdk, contextOptions, contextParams, Promise.reject(error) as any);
+ await context.ready();
+ expect(context.readyError()).toBe(error);
+ });
+ });
+
+ describe("getSDK() and getOptions()", () => {
+ it("getSDK() should return the sdk", () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ expect(context.getSDK()).toBe(sdk);
+ });
+
+ it("getOptions() should return a copy of options", () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ const options = context.getOptions();
+ expect(options.publishDelay).toBe(contextOptions.publishDelay);
+ expect(options.refreshPeriod).toBe(contextOptions.refreshPeriod);
+ expect(options).not.toBe(contextOptions); // should be a copy
+ });
+ });
+
+ describe("getUnits() defensive copy", () => {
+ it("should return a copy that does not mutate internal state", () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ const units = context.getUnits();
+ units["hacked"] = "value";
+ expect(context.getUnit("hacked")).toBeUndefined();
+ });
+ });
+
+ describe("peek then treatment", () => {
+ it("should queue exposure on treatment after peek", () => {
+ const context = new Context(sdk, contextOptions, contextParams, getContextResponse as any);
+ context.peek("exp_test_ab");
+ expect(context.pending()).toBe(0);
+ context.treatment("exp_test_ab");
+ expect(context.pending()).toBe(1);
+ });
+ });
+});
diff --git a/src/__tests__/errors.test.ts b/src/__tests__/errors.test.ts
new file mode 100644
index 0000000..1d74064
--- /dev/null
+++ b/src/__tests__/errors.test.ts
@@ -0,0 +1,72 @@
+import { describe, expect, test } from "vitest";
+import { ABSmartlyError, AbortError, ContextFinalizedError, ContextNotReadyError, RetryError, TimeoutError } from "../errors";
+
+describe("ABSmartlyError", () => {
+ test("has correct name and message", () => {
+ const error = new ABSmartlyError("test message");
+ expect(error).toBeInstanceOf(Error);
+ expect(error).toBeInstanceOf(ABSmartlyError);
+ expect(error.name).toBe("ABSmartlyError");
+ expect(error.message).toBe("test message");
+ });
+});
+
+describe("ContextNotReadyError", () => {
+ test("has correct name, message, and extends ABSmartlyError", () => {
+ const error = new ContextNotReadyError();
+ expect(error).toBeInstanceOf(Error);
+ expect(error).toBeInstanceOf(ABSmartlyError);
+ expect(error).toBeInstanceOf(ContextNotReadyError);
+ expect(error.name).toBe("ContextNotReadyError");
+ expect(error.message).toBe("Context is not yet ready");
+ });
+});
+
+describe("ContextFinalizedError", () => {
+ test("has correct name, message, and extends ABSmartlyError", () => {
+ const error = new ContextFinalizedError();
+ expect(error).toBeInstanceOf(Error);
+ expect(error).toBeInstanceOf(ABSmartlyError);
+ expect(error).toBeInstanceOf(ContextFinalizedError);
+ expect(error.name).toBe("ContextFinalizedError");
+ expect(error.message).toBe("Context has been finalized");
+ });
+});
+
+describe("TimeoutError", () => {
+ test("has correct name, message, and timeout", () => {
+ const error = new TimeoutError(3000);
+ expect(error).toBeInstanceOf(Error);
+ expect(error).toBeInstanceOf(TimeoutError);
+ expect(error.name).toBe("TimeoutError");
+ expect(error.message).toBe("Timeout exceeded.");
+ expect(error.timeout).toBe(3000);
+ });
+});
+
+describe("RetryError", () => {
+ test("has correct name, message, retries, and exception", () => {
+ const cause = new Error("connection refused");
+ const error = new RetryError(5, cause, "https://example.com/api");
+ expect(error).toBeInstanceOf(Error);
+ expect(error).toBeInstanceOf(RetryError);
+ expect(error.name).toBe("RetryError");
+ expect(error.message).toBe("Retries exhausted. URL: https://example.com/api - Last Error: connection refused");
+ expect(error.retries).toBe(5);
+ expect(error.exception).toBe(cause);
+ });
+});
+
+describe("AbortError", () => {
+ test("has correct name and default message", () => {
+ const error = new AbortError();
+ expect(error).toBeInstanceOf(Error);
+ expect(error).toBeInstanceOf(AbortError);
+ expect(error.name).toBe("AbortError");
+ });
+
+ test("accepts custom message", () => {
+ const error = new AbortError("user cancelled");
+ expect(error.message).toBe("user cancelled");
+ });
+});
diff --git a/src/__tests__/fetch-shim.test.js b/src/__tests__/fetch-shim.test.js
deleted file mode 100644
index d214b7a..0000000
--- a/src/__tests__/fetch-shim.test.js
+++ /dev/null
@@ -1,135 +0,0 @@
-// eslint-disable-next-line no-shadow
-import { fetch } from "../fetch-shim";
-// eslint-disable-next-line no-shadow
-import { AbortController } from "../abort";
-
-describe("fetch", () => {
- it("should be a function", () => {
- expect(fetch).toEqual(expect.any(Function));
- });
-
- describe("fetch()", () => {
- let xhr;
-
- beforeEach(() => {
- xhr = {
- setRequestHeader: jest.fn(),
- getAllResponseHeaders: jest.fn().mockReturnValue("X-Foo: bar\nX-Foo:baz"),
- open: jest.fn(),
- send: jest.fn(),
- status: 200,
- statusText: "OK",
- responseText: '{"a":"b"}',
- responseURL: "/foo?redirect",
- abort: jest.fn(),
- };
-
- global.XMLHttpRequest = jest.fn(() => xhr);
- });
-
- afterEach(() => {
- delete global.XMLHttpRequest;
- });
-
- it("sanity test", async () => {
- fetch("/foo", { headers: { a: "b" } })
- .then((response) => {
- expect(response).toMatchObject({
- text: expect.any(Function),
- json: expect.any(Function),
- blob: expect.any(Function),
- clone: expect.any(Function),
- headers: expect.any(Object),
- });
- expect(response.clone()).not.toBe(response);
- expect(response.clone().url).toEqual("/foo?redirect");
- expect(response.headers.get).toEqual(expect.any(Function));
- expect(response.headers.get("x-foo")).toEqual("bar,baz");
- return response.json();
- })
- .then((data) => {
- expect(data).toEqual({ a: "b" });
-
- expect(xhr.setRequestHeader).toHaveBeenCalledTimes(1);
- expect(xhr.setRequestHeader).toHaveBeenCalledWith("a", "b");
- expect(xhr.open).toHaveBeenCalledTimes(1);
- expect(xhr.open).toHaveBeenCalledWith("get", "/foo", true);
- expect(xhr.send).toHaveBeenCalledTimes(1);
- expect(xhr.send).toHaveBeenCalledWith(null);
- });
-
- expect(xhr.onload).toEqual(expect.any(Function));
- expect(xhr.onerror).toEqual(expect.any(Function));
- expect(xhr.onabort).toEqual(expect.any(Function));
-
- xhr.onload();
- });
-
- it("handles empty header values", async () => {
- xhr.getAllResponseHeaders = jest.fn().mockReturnValue("Server: \nX-Foo:baz");
- fetch("/foo").then((response) => {
- expect(response.headers.get("server")).toEqual("");
- expect(response.headers.get("X-foo")).toEqual("baz");
- });
-
- xhr.onload();
- });
-
- it("adds and removes the abort event listener", async () => {
- const controller = new AbortController();
- jest.spyOn(controller.signal, "addEventListener");
- jest.spyOn(controller.signal, "removeEventListener");
-
- fetch("/foo", {
- signal: controller.signal,
- })
- .then((response) => {
- return response.json();
- })
- .then((data) => {
- expect(xhr.abort).not.toHaveBeenCalled();
- expect(data).toEqual({ a: "b" });
- expect(controller.signal.addEventListener).toHaveBeenCalledTimes(1);
- expect(controller.signal.removeEventListener).toHaveBeenCalledTimes(1);
- });
-
- xhr.onload();
- });
-
- it("adds and removes the abort event listener on abort", async () => {
- const controller = new AbortController();
-
- jest.spyOn(controller.signal, "addEventListener");
- jest.spyOn(controller.signal, "removeEventListener");
-
- fetch("/foo", {
- signal: controller.signal,
- }).catch((error) => {
- expect(error.name).toBe("AbortError");
- expect(xhr.abort).toHaveBeenCalledTimes(1);
- expect(controller.signal.addEventListener).toHaveBeenCalledTimes(1);
- expect(controller.signal.removeEventListener).toHaveBeenCalledTimes(1);
- });
-
- controller.abort();
- xhr.onabort();
- });
-
- it("adds and removes the abort event listener on error", async () => {
- const controller = new AbortController();
-
- jest.spyOn(controller.signal, "addEventListener");
- jest.spyOn(controller.signal, "removeEventListener");
-
- fetch("/foo", {
- signal: controller.signal,
- }).catch(() => {
- expect(xhr.abort).not.toHaveBeenCalled();
- expect(controller.signal.addEventListener).toHaveBeenCalledTimes(1);
- expect(controller.signal.removeEventListener).toHaveBeenCalledTimes(1);
- });
-
- xhr.onerror();
- });
- });
-});
diff --git a/src/__tests__/hashing.test.ts b/src/__tests__/hashing.test.ts
new file mode 100644
index 0000000..f312c4f
--- /dev/null
+++ b/src/__tests__/hashing.test.ts
@@ -0,0 +1,80 @@
+import { describe, expect, test } from "vitest";
+import { base64UrlNoPadding, hashUnit, stringToUint8Array } from "../hashing";
+
+describe("stringToUint8Array", () => {
+ test("encodes ASCII", () => {
+ const result = stringToUint8Array("abc");
+ expect(Array.from(result)).toEqual([97, 98, 99]);
+ });
+
+ test("encodes multi-byte characters", () => {
+ const result = stringToUint8Array("\u00e9");
+ expect(Array.from(result)).toEqual([0xc3, 0xa9]);
+ });
+
+ test("encodes empty string", () => {
+ const result = stringToUint8Array("");
+ expect(result.length).toBe(0);
+ });
+
+ test("encodes 4-byte characters (emoji/surrogate pairs)", () => {
+ const result = stringToUint8Array("\u{1F600}");
+ // U+1F600 = F0 9F 98 80 in UTF-8
+ expect(Array.from(result)).toEqual([0xf0, 0x9f, 0x98, 0x80]);
+ });
+});
+
+describe("base64UrlNoPadding", () => {
+ test("encodes empty", () => {
+ expect(base64UrlNoPadding(new Uint8Array([]))).toBe("");
+ });
+
+ test("encodes 1 byte", () => {
+ expect(base64UrlNoPadding(new Uint8Array([0]))).toBe("AA");
+ });
+
+ test("encodes 2 bytes", () => {
+ expect(base64UrlNoPadding(new Uint8Array([0, 0]))).toBe("AAA");
+ });
+
+ test("encodes 3 bytes", () => {
+ expect(base64UrlNoPadding(new Uint8Array([0, 0, 0]))).toBe("AAAA");
+ });
+
+ test("uses URL-safe characters (no +, /, =)", () => {
+ const result = base64UrlNoPadding(new Uint8Array([255, 254, 253, 252, 251, 250]));
+ expect(result).not.toContain("+");
+ expect(result).not.toContain("/");
+ expect(result).not.toContain("=");
+ });
+});
+
+describe("hashUnit", () => {
+ test("hashes string unit", () => {
+ const result = hashUnit("test_unit");
+ expect(typeof result).toBe("string");
+ expect(result.length).toBeGreaterThan(0);
+ });
+
+ test("hashes numeric unit", () => {
+ const result = hashUnit(12345);
+ expect(typeof result).toBe("string");
+ expect(result.length).toBeGreaterThan(0);
+ });
+
+ test("produces consistent results", () => {
+ expect(hashUnit("abc")).toBe(hashUnit("abc"));
+ expect(hashUnit(123)).toBe(hashUnit(123));
+ });
+
+ test("produces different results for different inputs", () => {
+ expect(hashUnit("abc")).not.toBe(hashUnit("def"));
+ });
+
+ test("returns exactly 22 chars (MD5 = 16 bytes = 22 base64url chars)", () => {
+ expect(hashUnit("a").length).toBe(22);
+ expect(hashUnit("abcdefghijklmnopqrstuvwxyz").length).toBe(22);
+ expect(hashUnit("bleh@absmartly.com").length).toBe(22);
+ expect(hashUnit(123456789).length).toBe(22);
+ });
+});
diff --git a/src/__tests__/jsonexpr/evaluator.test.js b/src/__tests__/jsonexpr/evaluator.test.js
deleted file mode 100644
index 53b1927..0000000
--- a/src/__tests__/jsonexpr/evaluator.test.js
+++ /dev/null
@@ -1,470 +0,0 @@
-import { Evaluator } from "../../jsonexpr/evaluator";
-
-describe("Evaluator", () => {
- describe("evaluate", () => {
- it("should consider an array as implicit AND combinator", () => {
- const and = { evaluate: jest.fn().mockReturnValue(true) };
- const or = { evaluate: jest.fn().mockReturnValue(true) };
-
- const evaluator = new Evaluator({ and, or }, {});
- const args = [{ value: true }, { value: false }];
- expect(evaluator.evaluate(args)).not.toBe(null);
-
- expect(and.evaluate).toHaveBeenCalledTimes(1);
- expect(and.evaluate).toHaveBeenCalledWith(evaluator, args);
- expect(or.evaluate).not.toHaveBeenCalled();
- });
-
- it("should return null if operator not found", () => {
- const value = { evaluate: jest.fn().mockReturnValue(true) };
-
- const evaluator = new Evaluator({ value }, {});
- expect(evaluator.evaluate({ not_found: true })).toBe(null);
-
- expect(value.evaluate).not.toHaveBeenCalled();
- });
-
- it("should call operator evaluate will args", () => {
- const value = { evaluate: jest.fn().mockReturnValue(true) };
-
- const evaluator = new Evaluator({ value }, {});
- const args = [1, 2, 3];
- expect(evaluator.evaluate({ value: args })).toBe(true);
-
- expect(value.evaluate).toHaveBeenCalledTimes(1);
- expect(value.evaluate).toHaveBeenCalledWith(evaluator, args);
- });
- });
-
- describe("booleanConvert()", () => {
- it("should convert all types of values to boolean", () => {
- const evaluator = new Evaluator({}, {});
-
- expect(evaluator.booleanConvert({})).toBe(true);
- expect(evaluator.booleanConvert([])).toBe(true);
- expect(evaluator.booleanConvert(null)).toBe(false);
-
- expect(evaluator.booleanConvert(true)).toBe(true);
- expect(evaluator.booleanConvert(1)).toBe(true);
- expect(evaluator.booleanConvert(2)).toBe(true);
- expect(evaluator.booleanConvert("abc")).toBe(true);
- expect(evaluator.booleanConvert("1")).toBe(true);
-
- expect(evaluator.booleanConvert(false)).toBe(false);
- expect(evaluator.booleanConvert(0)).toBe(false);
- expect(evaluator.booleanConvert("")).toBe(false);
- expect(evaluator.booleanConvert("0")).toBe(false);
- expect(evaluator.booleanConvert("false")).toBe(false);
- });
- });
-
- describe("numberConvert()", () => {
- it("should convert boolean, and numeric strings to number", () => {
- const evaluator = new Evaluator({}, {});
-
- expect(evaluator.numberConvert(null)).toBe(null);
- expect(evaluator.numberConvert({})).toBe(null);
- expect(evaluator.numberConvert([])).toBe(null);
- expect(evaluator.numberConvert("")).toBe(null);
- expect(evaluator.numberConvert("abc")).toBe(null);
- expect(evaluator.numberConvert("x1234")).toBe(null);
-
- expect(evaluator.numberConvert(true)).toBe(1.0);
- expect(evaluator.numberConvert(false)).toBe(0.0);
-
- expect(evaluator.numberConvert(-1.0)).toBe(-1.0);
- expect(evaluator.numberConvert(0.0)).toBe(0.0);
- expect(evaluator.numberConvert(1.0)).toBe(1.0);
- expect(evaluator.numberConvert(1.5)).toBe(1.5);
- expect(evaluator.numberConvert(2.0)).toBe(2.0);
- expect(evaluator.numberConvert(3.0)).toBe(3.0);
-
- expect(evaluator.numberConvert(-1)).toBe(-1.0);
- expect(evaluator.numberConvert(0)).toBe(0.0);
- expect(evaluator.numberConvert(1)).toBe(1.0);
- expect(evaluator.numberConvert(2)).toBe(2.0);
- expect(evaluator.numberConvert(3)).toBe(3.0);
-
- expect(evaluator.numberConvert(0x7fffffff)).toBe(2147483647.0);
- expect(evaluator.numberConvert(-0x7fffffff)).toBe(-2147483647.0);
- expect(evaluator.numberConvert(Number.MAX_SAFE_INTEGER)).toBe(9007199254740991.0);
- expect(evaluator.numberConvert(-Number.MAX_SAFE_INTEGER)).toBe(-9007199254740991.0);
-
- expect(evaluator.numberConvert("-1")).toBe(-1.0);
- expect(evaluator.numberConvert("0")).toBe(0.0);
- expect(evaluator.numberConvert("1")).toBe(1.0);
- expect(evaluator.numberConvert("1.5")).toBe(1.5);
- expect(evaluator.numberConvert("2")).toBe(2.0);
- expect(evaluator.numberConvert("3.0")).toBe(3.0);
- });
- });
-
- describe("stringConvert()", () => {
- const evaluator = new Evaluator({}, {});
-
- expect(evaluator.stringConvert(null)).toBe(null);
- expect(evaluator.stringConvert({})).toBe(null);
- expect(evaluator.stringConvert([])).toBe(null);
-
- expect(evaluator.stringConvert(true)).toBe("true");
- expect(evaluator.stringConvert(false)).toBe("false");
-
- expect(evaluator.stringConvert("")).toBe("");
- expect(evaluator.stringConvert("abc")).toBe("abc");
-
- expect(evaluator.stringConvert(-1.0)).toBe("-1");
- expect(evaluator.stringConvert(0.0)).toBe("0");
- expect(evaluator.stringConvert(1.0)).toBe("1");
- expect(evaluator.stringConvert(2.0)).toBe("2");
- expect(evaluator.stringConvert(3.0)).toBe("3");
- expect(evaluator.stringConvert(2147483647.0)).toBe("2147483647");
- expect(evaluator.stringConvert(-2147483647.0)).toBe("-2147483647");
- expect(evaluator.stringConvert(9007199254740991)).toBe("9007199254740991");
- expect(evaluator.stringConvert(-9007199254740991)).toBe("-9007199254740991");
- expect(evaluator.stringConvert(0.9007199254740991)).toBe("0.900719925474099");
- expect(evaluator.stringConvert(-0.9007199254740991)).toBe("-0.900719925474099");
- expect(evaluator.stringConvert(-1)).toBe("-1");
- expect(evaluator.stringConvert(0)).toBe("0");
- expect(evaluator.stringConvert(1)).toBe("1");
- expect(evaluator.stringConvert(2)).toBe("2");
- expect(evaluator.stringConvert(3)).toBe("3");
- expect(evaluator.stringConvert(2147483647)).toBe("2147483647");
- expect(evaluator.stringConvert(-2147483647)).toBe("-2147483647");
- expect(evaluator.stringConvert(9007199254740991)).toBe("9007199254740991");
- expect(evaluator.stringConvert(-9007199254740991)).toBe("-9007199254740991");
- });
-
- describe("extractVar()", () => {
- it("should find data by paths delimited by /", () => {
- const vars = {
- a: 1,
- b: true,
- c: false,
- d: [1, 2, 3],
- e: [1, { z: 2 }, 3],
- f: { y: { x: 3, 0: 10 } },
- };
-
- const evaluator = new Evaluator({}, vars);
-
- expect(evaluator.extractVar("a")).toBe(1);
- expect(evaluator.extractVar("b")).toBe(true);
- expect(evaluator.extractVar("c")).toBe(false);
- expect(evaluator.extractVar("d")).toEqual([1, 2, 3]);
- expect(evaluator.extractVar("e")).toEqual([1, { z: 2 }, 3]);
- expect(evaluator.extractVar("f")).toEqual({ y: { x: 3, 0: 10 } });
-
- expect(evaluator.extractVar("a/0")).toBe(null);
- expect(evaluator.extractVar("a/b")).toBe(null);
- expect(evaluator.extractVar("b/0")).toBe(null);
- expect(evaluator.extractVar("b/e")).toBe(null);
-
- expect(evaluator.extractVar("d/0")).toBe(1);
- expect(evaluator.extractVar("d/1")).toBe(2);
- expect(evaluator.extractVar("d/2")).toBe(3);
- expect(evaluator.extractVar("d/3")).toBe(null);
-
- expect(evaluator.extractVar("e/0")).toBe(1);
- expect(evaluator.extractVar("e/1/z")).toBe(2);
- expect(evaluator.extractVar("e/2")).toBe(3);
- expect(evaluator.extractVar("e/1/0")).toBe(null);
-
- expect(evaluator.extractVar("f/y")).toMatchObject({ x: 3 });
- expect(evaluator.extractVar("f/y/x")).toBe(3);
- expect(evaluator.extractVar("f/y/0")).toBe(10);
- });
- });
-
- describe("compare()", () => {
- it("should return null if comparing non-null with null", () => {
- const evaluator = new Evaluator({}, {});
-
- expect(evaluator.compare(null, null)).toBe(0);
-
- expect(evaluator.compare(null, 0)).toBe(null);
- expect(evaluator.compare(null, 1)).toBe(null);
- expect(evaluator.compare(null, true)).toBe(null);
- expect(evaluator.compare(null, false)).toBe(null);
- expect(evaluator.compare(null, "")).toBe(null);
- expect(evaluator.compare(null, "abc")).toBe(null);
- expect(evaluator.compare(null, {})).toBe(null);
- expect(evaluator.compare(null, [])).toBe(null);
-
- expect(evaluator.compare(0, null)).toBe(null);
- expect(evaluator.compare(1, null)).toBe(null);
- expect(evaluator.compare(true, null)).toBe(null);
- expect(evaluator.compare(false, null)).toBe(null);
- expect(evaluator.compare("", null)).toBe(null);
- expect(evaluator.compare("abc", null)).toBe(null);
- expect(evaluator.compare({}, null)).toBe(null);
- expect(evaluator.compare([], null)).toBe(null);
- });
-
- it("should return null if comparing non-object with object", () => {
- const evaluator = new Evaluator({}, {});
-
- expect(evaluator.compare({}, 0)).toBe(null);
- expect(evaluator.compare({}, 1)).toBe(null);
- expect(evaluator.compare({}, true)).toBe(null);
- expect(evaluator.compare({}, false)).toBe(null);
- expect(evaluator.compare({}, "")).toBe(null);
- expect(evaluator.compare({}, "abc")).toBe(null);
- expect(evaluator.compare({}, {})).toBe(0);
- expect(evaluator.compare({ a: 1 }, { a: 1 })).toBe(0);
- expect(evaluator.compare({ a: 1 }, { b: 2 })).toBe(null);
- expect(evaluator.compare({}, [])).toBe(null);
-
- expect(evaluator.compare([], 0)).toBe(null);
- expect(evaluator.compare([], 1)).toBe(null);
- expect(evaluator.compare([], true)).toBe(null);
- expect(evaluator.compare([], false)).toBe(null);
- expect(evaluator.compare([], "")).toBe(null);
- expect(evaluator.compare([], "abc")).toBe(null);
- expect(evaluator.compare([], {})).toBe(null);
- expect(evaluator.compare([], [])).toBe(0);
- expect(evaluator.compare([1, 2], [1, 2])).toBe(0);
- expect(evaluator.compare([1, 2], [3, 4])).toBe(null);
- });
-
- it("should coerce right-side argument to boolean and compare", () => {
- const evaluator = new Evaluator({}, {});
-
- expect(evaluator.compare(false, 0)).toBe(0);
- expect(evaluator.compare(false, 1)).toBe(-1);
- expect(evaluator.compare(false, true)).toBe(-1);
- expect(evaluator.compare(false, false)).toBe(0);
- expect(evaluator.compare(false, "")).toBe(0);
- expect(evaluator.compare(false, "abc")).toBe(-1);
- expect(evaluator.compare(false, {})).toBe(-1);
- expect(evaluator.compare(false, [])).toBe(-1);
-
- expect(evaluator.compare(true, 0)).toBe(1);
- expect(evaluator.compare(true, 1)).toBe(0);
- expect(evaluator.compare(true, true)).toBe(0);
- expect(evaluator.compare(true, false)).toBe(1);
- expect(evaluator.compare(true, "")).toBe(1);
- expect(evaluator.compare(true, "abc")).toBe(0);
- expect(evaluator.compare(true, {})).toBe(0);
- expect(evaluator.compare(true, [])).toBe(0);
- });
-
- it("should coerce right-side argument to boolean and compare", () => {
- const evaluator = new Evaluator({}, {});
-
- expect(evaluator.compare(0, 0)).toBe(0);
- expect(evaluator.compare(0, 1)).toBe(-1);
- expect(evaluator.compare(0, true)).toBe(-1);
- expect(evaluator.compare(0, false)).toBe(0);
- expect(evaluator.compare(0, "")).toBe(null);
- expect(evaluator.compare(0, "abc")).toBe(null);
- expect(evaluator.compare(0, {})).toBe(null);
- expect(evaluator.compare(0, [])).toBe(null);
-
- expect(evaluator.compare(1, 0)).toBe(1);
- expect(evaluator.compare(1, 1)).toBe(0);
- expect(evaluator.compare(1, true)).toBe(0);
- expect(evaluator.compare(1, false)).toBe(1);
- expect(evaluator.compare(1, "")).toBe(null);
- expect(evaluator.compare(1, "abc")).toBe(null);
- expect(evaluator.compare(1, {})).toBe(null);
- expect(evaluator.compare(1, [])).toBe(null);
-
- expect(evaluator.compare(1.0, 1)).toBe(0);
- expect(evaluator.compare(1.5, 1)).toBe(1);
- expect(evaluator.compare(2.0, 1)).toBe(1);
- expect(evaluator.compare(3.0, 1)).toBe(1);
-
- expect(evaluator.compare(1, 1.0)).toBe(0);
- expect(evaluator.compare(1, 1.5)).toBe(-1);
- expect(evaluator.compare(1, 2.0)).toBe(-1);
- expect(evaluator.compare(1, 3.0)).toBe(-1);
-
- expect(evaluator.compare(9007199254740991, 9007199254740991)).toBe(0);
- expect(evaluator.compare(0, 9007199254740991)).toBe(-1);
- expect(evaluator.compare(9007199254740991, 0)).toBe(1);
-
- expect(evaluator.compare(9007199254740991.0, 9007199254740991.0)).toBe(0);
- expect(evaluator.compare(0, 9007199254740991.0)).toBe(-1);
- expect(evaluator.compare(9007199254740991.0, 0)).toBe(1);
- });
-
- it("should coerce right-hand side argument to string and compare", () => {
- const evaluator = new Evaluator({}, {});
-
- expect(evaluator.compare("", "")).toBe(0);
- expect(evaluator.compare("abc", "abc")).toBe(0);
- expect(evaluator.compare("0", 0)).toBe(0);
- expect(evaluator.compare("1", 1)).toBe(0);
- expect(evaluator.compare("true", true)).toBe(0);
- expect(evaluator.compare("false", false)).toBe(0);
- expect(evaluator.compare("", {})).toBe(null);
- expect(evaluator.compare("abc", {})).toBe(null);
- expect(evaluator.compare("", [])).toBe(null);
- expect(evaluator.compare("abc", [])).toBe(null);
-
- expect(evaluator.compare("abc", "bcd")).toBe(-1);
- expect(evaluator.compare("bcd", "abc")).toBe(1);
- expect(evaluator.compare("0", "1")).toBe(-1);
- expect(evaluator.compare("1", "0")).toBe(1);
- expect(evaluator.compare("9", "100")).toBe(1);
- expect(evaluator.compare("100", "9")).toBe(-1);
- });
- });
-
- describe("versionCompare()", () => {
- it("should return 0 for equal versions", () => {
- const evaluator = new Evaluator({}, {});
-
- expect(evaluator.versionCompare("1.0.0", "1.0.0")).toBe(0);
- expect(evaluator.versionCompare("0.0.0", "0.0.0")).toBe(0);
- expect(evaluator.versionCompare("999.999.999", "999.999.999")).toBe(0);
- });
-
- it("should compare major versions", () => {
- const evaluator = new Evaluator({}, {});
-
- expect(evaluator.versionCompare("2.0.0", "1.0.0")).toBe(1);
- expect(evaluator.versionCompare("1.0.0", "2.0.0")).toBe(-1);
- });
-
- it("should compare minor versions", () => {
- const evaluator = new Evaluator({}, {});
-
- expect(evaluator.versionCompare("1.2.0", "1.1.0")).toBe(1);
- expect(evaluator.versionCompare("1.1.0", "1.2.0")).toBe(-1);
- });
-
- it("should compare patch versions", () => {
- const evaluator = new Evaluator({}, {});
-
- expect(evaluator.versionCompare("1.0.2", "1.0.1")).toBe(1);
- expect(evaluator.versionCompare("1.0.1", "1.0.2")).toBe(-1);
- });
-
- it("should compare numerically not lexicographically", () => {
- const evaluator = new Evaluator({}, {});
-
- expect(evaluator.versionCompare("1.10.0", "1.9.0")).toBe(1);
- expect(evaluator.versionCompare("1.9.0", "1.10.0")).toBe(-1);
- expect(evaluator.versionCompare("10.0.0", "9.0.0")).toBe(1);
- });
-
- it("should treat missing parts as 0", () => {
- const evaluator = new Evaluator({}, {});
-
- expect(evaluator.versionCompare("1.2", "1.2.0")).toBe(0);
- expect(evaluator.versionCompare("1", "1.0.0")).toBe(0);
- expect(evaluator.versionCompare("1.2.0", "1.2")).toBe(0);
- expect(evaluator.versionCompare("1.0.0", "1")).toBe(0);
- });
-
- it("should handle leading zeros in version parts", () => {
- const evaluator = new Evaluator({}, {});
-
- expect(evaluator.versionCompare("1.02.0", "1.2.0")).toBe(0);
- expect(evaluator.versionCompare("1.002.030", "1.2.30")).toBe(0);
- expect(evaluator.versionCompare("01.0.0", "1.0.0")).toBe(0);
- expect(evaluator.versionCompare("1.02.0", "1.3.0")).toBe(-1);
- });
-
- it("should handle pre-release versions", () => {
- const evaluator = new Evaluator({}, {});
-
- expect(evaluator.versionCompare("1.0.0", "1.0.0-alpha")).toBe(1);
- expect(evaluator.versionCompare("1.0.0-alpha", "1.0.0")).toBe(-1);
- expect(evaluator.versionCompare("1.0.0-alpha", "1.0.0-alpha")).toBe(0);
- expect(evaluator.versionCompare("1.0.0-alpha", "1.0.0-beta")).toBe(-1);
- expect(evaluator.versionCompare("1.0.0-beta", "1.0.0-alpha")).toBe(1);
- expect(evaluator.versionCompare("1.0.0-alpha.1", "1.0.0-alpha.2")).toBe(-1);
- expect(evaluator.versionCompare("1.0.0-alpha.2", "1.0.0-alpha.1")).toBe(1);
- expect(evaluator.versionCompare("1.0.0-1", "1.0.0-2")).toBe(-1);
- expect(evaluator.versionCompare("1.0.0-2", "1.0.0-1")).toBe(1);
- });
-
- it("should compare numeric pre-release identifiers as less than string identifiers", () => {
- const evaluator = new Evaluator({}, {});
-
- expect(evaluator.versionCompare("1.0.0-1", "1.0.0-alpha")).toBe(-1);
- expect(evaluator.versionCompare("1.0.0-alpha", "1.0.0-1")).toBe(1);
- });
-
- it("should compare pre-release with fewer identifiers as less", () => {
- const evaluator = new Evaluator({}, {});
-
- expect(evaluator.versionCompare("1.0.0-alpha", "1.0.0-alpha.1")).toBe(-1);
- expect(evaluator.versionCompare("1.0.0-alpha.1", "1.0.0-alpha")).toBe(1);
- });
-
- it("should strip v prefix", () => {
- const evaluator = new Evaluator({}, {});
-
- expect(evaluator.versionCompare("v1.0.0", "1.0.0")).toBe(0);
- expect(evaluator.versionCompare("V1.0.0", "1.0.0")).toBe(0);
- expect(evaluator.versionCompare("v1.0.0", "V1.0.0")).toBe(0);
- });
-
- it("should return null for null inputs", () => {
- const evaluator = new Evaluator({}, {});
-
- expect(evaluator.versionCompare(null, "1.0.0")).toBe(null);
- expect(evaluator.versionCompare("1.0.0", null)).toBe(null);
- expect(evaluator.versionCompare(null, null)).toBe(null);
- });
-
- it("should coerce non-string inputs via stringConvert", () => {
- const evaluator = new Evaluator({}, {});
-
- expect(evaluator.versionCompare(1, "1.0.0")).toBe(0);
- expect(evaluator.versionCompare("1.0.0", 1)).toBe(0);
- expect(evaluator.versionCompare(true, "true")).toBe(0);
- });
-
- it("should return null for unconvertible inputs", () => {
- const evaluator = new Evaluator({}, {});
-
- expect(evaluator.versionCompare({}, "1.0.0")).toBe(null);
- expect(evaluator.versionCompare("1.0.0", {})).toBe(null);
- expect(evaluator.versionCompare([], "1.0.0")).toBe(null);
- });
-
- it("should ignore build metadata", () => {
- const evaluator = new Evaluator({}, {});
-
- expect(evaluator.versionCompare("1.0.0+build1", "1.0.0+build2")).toBe(0);
- expect(evaluator.versionCompare("1.0.0+build1", "1.0.0")).toBe(0);
- });
-
- it("should handle pre-release combined with build metadata", () => {
- const evaluator = new Evaluator({}, {});
-
- expect(evaluator.versionCompare("1.0.0-alpha+build1", "1.0.0-alpha+build2")).toBe(0);
- expect(evaluator.versionCompare("1.0.0-alpha+build1", "1.0.0-beta")).toBe(-1);
- expect(evaluator.versionCompare("1.0.0-alpha+build1", "1.0.0")).toBe(-1);
- });
-
- it("should return null for empty string inputs", () => {
- const evaluator = new Evaluator({}, {});
-
- expect(evaluator.versionCompare("", "1.0.0")).toBe(null);
- expect(evaluator.versionCompare("1.0.0", "")).toBe(null);
- expect(evaluator.versionCompare("", "")).toBe(null);
- });
-
- it("should return null for undefined inputs", () => {
- const evaluator = new Evaluator({}, {});
-
- expect(evaluator.versionCompare(undefined, "1.0.0")).toBe(null);
- expect(evaluator.versionCompare("1.0.0", undefined)).toBe(null);
- });
-
- it("should return null for inputs that normalize to empty core", () => {
- const evaluator = new Evaluator({}, {});
-
- expect(evaluator.versionCompare("v", "1.0.0")).toBe(null);
- expect(evaluator.versionCompare("V", "1.0.0")).toBe(null);
- expect(evaluator.versionCompare("+build", "1.0.0")).toBe(null);
- expect(evaluator.versionCompare("v+build", "1.0.0")).toBe(null);
- expect(evaluator.versionCompare("1.0.0", "v")).toBe(null);
- });
- });
-});
diff --git a/src/__tests__/jsonexpr/evaluator.test.ts b/src/__tests__/jsonexpr/evaluator.test.ts
new file mode 100644
index 0000000..0122340
--- /dev/null
+++ b/src/__tests__/jsonexpr/evaluator.test.ts
@@ -0,0 +1,167 @@
+import { describe, expect, test } from "vitest";
+import { Evaluator } from "../../jsonexpr/evaluator";
+
+function createEvaluator(vars: Record = {}) {
+ return new Evaluator({}, vars);
+}
+
+describe("Evaluator", () => {
+ describe("booleanConvert", () => {
+ const evaluator = createEvaluator();
+
+ test("boolean values", () => {
+ expect(evaluator.booleanConvert(true)).toBe(true);
+ expect(evaluator.booleanConvert(false)).toBe(false);
+ });
+
+ test("number values", () => {
+ expect(evaluator.booleanConvert(1)).toBe(true);
+ expect(evaluator.booleanConvert(0)).toBe(false);
+ expect(evaluator.booleanConvert(-1)).toBe(true);
+ });
+
+ test("string values", () => {
+ expect(evaluator.booleanConvert("true")).toBe(true);
+ expect(evaluator.booleanConvert("false")).toBe(false);
+ expect(evaluator.booleanConvert("0")).toBe(false);
+ expect(evaluator.booleanConvert("")).toBe(false);
+ expect(evaluator.booleanConvert("abc")).toBe(true);
+ });
+
+ test("null/undefined", () => {
+ expect(evaluator.booleanConvert(null)).toBe(false);
+ expect(evaluator.booleanConvert(undefined)).toBe(false);
+ });
+ });
+
+ describe("numberConvert", () => {
+ const evaluator = createEvaluator();
+
+ test("number values", () => {
+ expect(evaluator.numberConvert(42)).toBe(42);
+ expect(evaluator.numberConvert(0)).toBe(0);
+ expect(evaluator.numberConvert(-1.5)).toBe(-1.5);
+ });
+
+ test("boolean values", () => {
+ expect(evaluator.numberConvert(true)).toBe(1);
+ expect(evaluator.numberConvert(false)).toBe(0);
+ });
+
+ test("string values", () => {
+ expect(evaluator.numberConvert("42")).toBe(42);
+ expect(evaluator.numberConvert("3.14")).toBe(3.14);
+ expect(evaluator.numberConvert("abc")).toBe(null);
+ });
+
+ test("other types", () => {
+ expect(evaluator.numberConvert(null)).toBe(null);
+ expect(evaluator.numberConvert({})).toBe(null);
+ });
+ });
+
+ describe("stringConvert", () => {
+ const evaluator = createEvaluator();
+
+ test("string values", () => {
+ expect(evaluator.stringConvert("hello")).toBe("hello");
+ });
+
+ test("boolean values", () => {
+ expect(evaluator.stringConvert(true)).toBe("true");
+ expect(evaluator.stringConvert(false)).toBe("false");
+ });
+
+ test("number values", () => {
+ expect(evaluator.stringConvert(42)).toBe("42");
+ expect(evaluator.stringConvert(0)).toBe("0");
+ });
+
+ test("other types", () => {
+ expect(evaluator.stringConvert(null)).toBe(null);
+ expect(evaluator.stringConvert({})).toBe(null);
+ });
+ });
+
+ describe("extractVar", () => {
+ test("extracts top-level variable", () => {
+ const evaluator = createEvaluator({ name: "John" });
+ expect(evaluator.extractVar("name")).toBe("John");
+ });
+
+ test("extracts nested variable", () => {
+ const evaluator = createEvaluator({ user: { name: "John" } });
+ expect(evaluator.extractVar("user/name")).toBe("John");
+ });
+
+ test("returns null for missing path", () => {
+ const evaluator = createEvaluator({ name: "John" });
+ expect(evaluator.extractVar("missing")).toBe(null);
+ });
+ });
+
+ describe("compare", () => {
+ const evaluator = createEvaluator();
+
+ test("numbers", () => {
+ expect(evaluator.compare(1, 2)).toBe(-1);
+ expect(evaluator.compare(2, 1)).toBe(1);
+ expect(evaluator.compare(1, 1)).toBe(0);
+ });
+
+ test("strings", () => {
+ expect(evaluator.compare("a", "b")).toBe(-1);
+ expect(evaluator.compare("b", "a")).toBe(1);
+ expect(evaluator.compare("a", "a")).toBe(0);
+ });
+
+ test("booleans", () => {
+ expect(evaluator.compare(true, true)).toBe(0);
+ expect(evaluator.compare(false, false)).toBe(0);
+ });
+
+ test("null handling", () => {
+ expect(evaluator.compare(null, null)).toBe(0);
+ expect(evaluator.compare(null, 1)).toBe(null);
+ expect(evaluator.compare(1, null)).toBe(null);
+ });
+ });
+
+ describe("versionCompare", () => {
+ const evaluator = createEvaluator();
+
+ test("equal versions", () => {
+ expect(evaluator.versionCompare("1.0.0", "1.0.0")).toBe(0);
+ });
+
+ test("greater version", () => {
+ expect(evaluator.versionCompare("2.0.0", "1.0.0")).toBe(1);
+ });
+
+ test("lesser version", () => {
+ expect(evaluator.versionCompare("1.0.0", "2.0.0")).toBe(-1);
+ });
+
+ test("prerelease is less than release", () => {
+ expect(evaluator.versionCompare("1.0.0-alpha", "1.0.0")).toBe(-1);
+ });
+
+ test("v prefix", () => {
+ expect(evaluator.versionCompare("v1.0.0", "1.0.0")).toBe(0);
+ });
+
+ test("build metadata ignored", () => {
+ expect(evaluator.versionCompare("1.0.0+build1", "1.0.0+build2")).toBe(0);
+ });
+
+ test("null inputs", () => {
+ expect(evaluator.versionCompare(null, "1.0.0")).toBe(null);
+ expect(evaluator.versionCompare("1.0.0", null)).toBe(null);
+ });
+
+ test("empty inputs", () => {
+ expect(evaluator.versionCompare("", "1.0.0")).toBe(null);
+ expect(evaluator.versionCompare("1.0.0", "")).toBe(null);
+ });
+ });
+});
diff --git a/src/__tests__/jsonexpr/jsonexpr.test.js b/src/__tests__/jsonexpr/jsonexpr.test.js
deleted file mode 100644
index b8bd3cf..0000000
--- a/src/__tests__/jsonexpr/jsonexpr.test.js
+++ /dev/null
@@ -1,69 +0,0 @@
-import { JsonExpr } from "../../jsonexpr/jsonexpr";
-
-describe("jsonexpr", () => {
- const valueFor = (x) => ({ value: x });
- const varFor = (p) => ({ var: { path: p } });
- const unaryOp = (op, arg) => ({ [op]: arg });
- const binaryOp = (op, arg0, arg1) => ({ [op]: [arg0, arg1] });
-
- const jsonExpr = new JsonExpr();
-
- const John = { age: 20, language: "en-US", returning: false };
- const Terry = { age: 20, language: "en-GB", returning: true };
- const Kate = { age: 50, language: "es-ES", returning: false };
- const Maria = { age: 52, language: "pt-PT", returning: true };
-
- const AgeTwentyAndUS = [
- binaryOp("eq", varFor("age"), valueFor(20)),
- binaryOp("eq", varFor("language"), valueFor("en-US")),
- ];
- const AgeOverFifty = [binaryOp("gte", varFor("age"), valueFor(50))];
- const AgeTwentyAndUS_Or_AgeOverFifty = [{ or: [AgeTwentyAndUS, AgeOverFifty] }];
- const Returning = [binaryOp("eq", varFor("returning"), valueFor(true))];
- const Returning_And_AgeTwentyAndUS_Or_AgeOverFifty = [Returning, AgeTwentyAndUS_Or_AgeOverFifty];
- const NotReturning_And_Spanish = [unaryOp("not", Returning), binaryOp("eq", varFor("language"), valueFor("es-ES"))];
-
- describe("evaluateBooleanExpr()", () => {
- test("AgeTwentyAndUS", () => {
- expect(jsonExpr.evaluateBooleanExpr(AgeTwentyAndUS, John)).toEqual(true);
- expect(jsonExpr.evaluateBooleanExpr(AgeTwentyAndUS, Terry)).toEqual(false);
- expect(jsonExpr.evaluateBooleanExpr(AgeTwentyAndUS, Kate)).toEqual(false);
- expect(jsonExpr.evaluateBooleanExpr(AgeTwentyAndUS, Maria)).toEqual(false);
- });
-
- test("AgeOverFifty", () => {
- expect(jsonExpr.evaluateBooleanExpr(AgeOverFifty, John)).toEqual(false);
- expect(jsonExpr.evaluateBooleanExpr(AgeOverFifty, Terry)).toEqual(false);
- expect(jsonExpr.evaluateBooleanExpr(AgeOverFifty, Kate)).toEqual(true);
- expect(jsonExpr.evaluateBooleanExpr(AgeOverFifty, Maria)).toEqual(true);
- });
-
- test("AgeTwentyAndUS_Or_AgeOverFifty", () => {
- expect(jsonExpr.evaluateBooleanExpr(AgeTwentyAndUS_Or_AgeOverFifty, John)).toEqual(true);
- expect(jsonExpr.evaluateBooleanExpr(AgeTwentyAndUS_Or_AgeOverFifty, Terry)).toEqual(false);
- expect(jsonExpr.evaluateBooleanExpr(AgeTwentyAndUS_Or_AgeOverFifty, Kate)).toEqual(true);
- expect(jsonExpr.evaluateBooleanExpr(AgeTwentyAndUS_Or_AgeOverFifty, Maria)).toEqual(true);
- });
-
- test("Returning", () => {
- expect(jsonExpr.evaluateBooleanExpr(Returning, John)).toEqual(false);
- expect(jsonExpr.evaluateBooleanExpr(Returning, Terry)).toEqual(true);
- expect(jsonExpr.evaluateBooleanExpr(Returning, Kate)).toEqual(false);
- expect(jsonExpr.evaluateBooleanExpr(Returning, Maria)).toEqual(true);
- });
-
- test("Returning_And_AgeTwentyAndUS_Or_AgeOverFifty", () => {
- expect(jsonExpr.evaluateBooleanExpr(Returning_And_AgeTwentyAndUS_Or_AgeOverFifty, John)).toEqual(false);
- expect(jsonExpr.evaluateBooleanExpr(Returning_And_AgeTwentyAndUS_Or_AgeOverFifty, Terry)).toEqual(false);
- expect(jsonExpr.evaluateBooleanExpr(Returning_And_AgeTwentyAndUS_Or_AgeOverFifty, Kate)).toEqual(false);
- expect(jsonExpr.evaluateBooleanExpr(Returning_And_AgeTwentyAndUS_Or_AgeOverFifty, Maria)).toEqual(true);
- });
-
- test("NotReturning_And_Spanish", () => {
- expect(jsonExpr.evaluateBooleanExpr(NotReturning_And_Spanish, John)).toEqual(false);
- expect(jsonExpr.evaluateBooleanExpr(NotReturning_And_Spanish, Terry)).toEqual(false);
- expect(jsonExpr.evaluateBooleanExpr(NotReturning_And_Spanish, Kate)).toEqual(true);
- expect(jsonExpr.evaluateBooleanExpr(NotReturning_And_Spanish, Maria)).toEqual(false);
- });
- });
-});
diff --git a/src/__tests__/jsonexpr/jsonexpr.test.ts b/src/__tests__/jsonexpr/jsonexpr.test.ts
new file mode 100644
index 0000000..95ff21a
--- /dev/null
+++ b/src/__tests__/jsonexpr/jsonexpr.test.ts
@@ -0,0 +1,31 @@
+import { describe, expect, test } from "vitest";
+import { JsonExpr } from "../../jsonexpr/jsonexpr";
+
+describe("JsonExpr", () => {
+ const jsonExpr = new JsonExpr();
+
+ test("evaluateBooleanExpr with and-array", () => {
+ expect(jsonExpr.evaluateBooleanExpr([{ value: true }, { value: 1 }], {})).toBe(true);
+ expect(jsonExpr.evaluateBooleanExpr([{ value: true }, { value: false }], {})).toBe(false);
+ });
+
+ test("evaluateBooleanExpr with object expr", () => {
+ expect(jsonExpr.evaluateBooleanExpr({ value: true }, {})).toBe(true);
+ expect(jsonExpr.evaluateBooleanExpr({ value: false }, {})).toBe(false);
+ });
+
+ test("evaluateExpr returns raw value", () => {
+ expect(jsonExpr.evaluateExpr({ value: 42 }, {})).toBe(42);
+ expect(jsonExpr.evaluateExpr({ value: "hello" }, {})).toBe("hello");
+ });
+
+ test("var operator extracts from vars", () => {
+ expect(jsonExpr.evaluateExpr({ var: "name" }, { name: "Alice" })).toBe("Alice");
+ });
+
+ test("complex expression with eq and var", () => {
+ const expr = { eq: [{ var: "age" }, { value: 25 }] };
+ expect(jsonExpr.evaluateBooleanExpr(expr, { age: 25 })).toBe(true);
+ expect(jsonExpr.evaluateBooleanExpr(expr, { age: 30 })).toBe(false);
+ });
+});
diff --git a/src/__tests__/jsonexpr/operators/and.test.js b/src/__tests__/jsonexpr/operators/and.test.js
deleted file mode 100644
index 6b8dfd5..0000000
--- a/src/__tests__/jsonexpr/operators/and.test.js
+++ /dev/null
@@ -1,54 +0,0 @@
-import { AndCombinator } from "../../../jsonexpr/operators/and";
-import { mockEvaluator } from "./evaluator";
-
-describe("AndCombinator", () => {
- const combinator = new AndCombinator();
-
- describe("evaluate", () => {
- const evaluator = mockEvaluator();
-
- it("should return true if all arguments evaluate to true", () => {
- expect(combinator.evaluate(evaluator, [true])).toBe(true);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(1);
- expect(evaluator.evaluate).toHaveBeenCalledWith(true);
- expect(evaluator.booleanConvert).toHaveBeenCalledTimes(1);
- expect(evaluator.booleanConvert).toHaveBeenCalledWith(true);
- });
-
- it("should return false if any argument evaluates to false", () => {
- expect(combinator.evaluate(evaluator, [false])).toBe(false);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(1);
- expect(evaluator.evaluate).toHaveBeenCalledWith(false);
- expect(evaluator.booleanConvert).toHaveBeenCalledTimes(1);
- expect(evaluator.booleanConvert).toHaveBeenCalledWith(false);
- });
-
- it("should return false if any argument evaluates to null", () => {
- expect(combinator.evaluate(evaluator, [null])).toBe(false);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(1);
- expect(evaluator.evaluate).toHaveBeenCalledWith(null);
- expect(evaluator.booleanConvert).toHaveBeenCalledTimes(1);
- expect(evaluator.booleanConvert).toHaveBeenCalledWith(null);
- });
-
- it("should short-circuit and not evaluate unnecessary expressions", () => {
- expect(combinator.evaluate(evaluator, [true, false, true])).toBe(false);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(2);
- expect(evaluator.booleanConvert).toHaveBeenCalledTimes(2);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(1, true);
- expect(evaluator.booleanConvert).toHaveBeenNthCalledWith(1, true);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(2, false);
- expect(evaluator.booleanConvert).toHaveBeenNthCalledWith(2, false);
- });
-
- it("should combine multiple arguments", () => {
- expect(combinator.evaluate(evaluator, [true, true])).toBe(true);
- expect(combinator.evaluate(evaluator, [true, true, true])).toBe(true);
-
- expect(combinator.evaluate(evaluator, [true, false])).toBe(false);
- expect(combinator.evaluate(evaluator, [false, true])).toBe(false);
- expect(combinator.evaluate(evaluator, [false, false])).toBe(false);
- expect(combinator.evaluate(evaluator, [false, false, false])).toBe(false);
- });
- });
-});
diff --git a/src/__tests__/jsonexpr/operators/eq.test.js b/src/__tests__/jsonexpr/operators/eq.test.js
deleted file mode 100644
index d7132af..0000000
--- a/src/__tests__/jsonexpr/operators/eq.test.js
+++ /dev/null
@@ -1,110 +0,0 @@
-import { mockEvaluator } from "./evaluator";
-import { EqualsOperator } from "../../../jsonexpr/operators/eq";
-
-describe("EqOperator", () => {
- const operator = new EqualsOperator();
-
- describe("evaluate", () => {
- const evaluator = mockEvaluator();
-
- it("should return true when arguments are equal and comparable", () => {
- expect(operator.evaluate(evaluator, [0, 0])).toBe(true);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(2);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(1, 0);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(2, 0);
- expect(evaluator.compare).toHaveBeenCalledTimes(1);
- expect(evaluator.compare).toHaveBeenCalledWith(0, 0);
-
- evaluator.evaluate.mockClear();
- evaluator.compare.mockClear();
-
- expect(operator.evaluate(evaluator, [1, 0])).toBe(false);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(2);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(1, 1);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(2, 0);
- expect(evaluator.compare).toHaveBeenCalledTimes(1);
- expect(evaluator.compare).toHaveBeenCalledWith(1, 0);
-
- evaluator.evaluate.mockClear();
- evaluator.compare.mockClear();
-
- expect(operator.evaluate(evaluator, [0, 1])).toBe(false);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(2);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(1, 0);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(2, 1);
- expect(evaluator.compare).toHaveBeenCalledTimes(1);
- expect(evaluator.compare).toHaveBeenCalledWith(0, 1);
-
- evaluator.evaluate.mockClear();
- evaluator.compare.mockClear();
-
- expect(operator.evaluate(evaluator, [null, null])).toBe(null);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(1);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(1, null);
- expect(evaluator.compare).toHaveBeenCalledTimes(0);
-
- evaluator.evaluate.mockClear();
- evaluator.compare.mockClear();
-
- expect(
- operator.evaluate(evaluator, [
- [1, 2],
- [1, 2],
- ])
- ).toBe(true);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(2);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(1, [1, 2]);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(2, [1, 2]);
- expect(evaluator.compare).toHaveBeenCalledTimes(1);
- expect(evaluator.compare).toHaveBeenCalledWith([1, 2], [1, 2]);
-
- evaluator.evaluate.mockClear();
- evaluator.compare.mockClear();
-
- expect(
- operator.evaluate(evaluator, [
- [1, 2],
- [3, 4],
- ])
- ).toBe(null);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(2);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(1, [1, 2]);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(2, [3, 4]);
- expect(evaluator.compare).toHaveBeenCalledTimes(1);
- expect(evaluator.compare).toHaveBeenCalledWith([1, 2], [3, 4]);
-
- evaluator.evaluate.mockClear();
- evaluator.compare.mockClear();
-
- expect(
- operator.evaluate(evaluator, [
- { a: 1, b: 2 },
- { a: 1, b: 2 },
- ])
- ).toBe(true);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(2);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(1, { a: 1, b: 2 });
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(2, { a: 1, b: 2 });
- expect(evaluator.compare).toHaveBeenCalledTimes(1);
- expect(evaluator.compare).toHaveBeenCalledWith({ a: 1, b: 2 }, { a: 1, b: 2 });
-
- evaluator.evaluate.mockClear();
- evaluator.compare.mockClear();
-
- expect(
- operator.evaluate(evaluator, [
- { a: 1, b: 2 },
- { a: 3, b: 4 },
- ])
- ).toBe(null);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(2);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(1, { a: 1, b: 2 });
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(2, { a: 3, b: 4 });
- expect(evaluator.compare).toHaveBeenCalledTimes(1);
- expect(evaluator.compare).toHaveBeenCalledWith({ a: 1, b: 2 }, { a: 3, b: 4 });
-
- evaluator.evaluate.mockClear();
- evaluator.compare.mockClear();
- });
- });
-});
diff --git a/src/__tests__/jsonexpr/operators/evaluator.js b/src/__tests__/jsonexpr/operators/evaluator.js
deleted file mode 100644
index 2c67b58..0000000
--- a/src/__tests__/jsonexpr/operators/evaluator.js
+++ /dev/null
@@ -1,62 +0,0 @@
-import { isEqualsDeep, isObject } from "../../../utils";
-
-export function mockEvaluator() {
- return {
- evaluate: jest.fn((expr) => {
- return expr;
- }),
-
- booleanConvert: jest.fn((expr) => {
- return expr;
- }),
-
- numberConvert: jest.fn((expr) => {
- return expr;
- }),
-
- stringConvert: jest.fn((expr) => {
- return expr;
- }),
-
- versionCompare: jest.fn((lhs, rhs) => {
- const lhsStr = typeof lhs === "string" ? lhs : null;
- const rhsStr = typeof rhs === "string" ? rhs : null;
- if (lhsStr === null || rhsStr === null) return null;
- const lParts = lhsStr.split(".").map(Number);
- const rParts = rhsStr.split(".").map(Number);
- const len = Math.max(lParts.length, rParts.length);
- for (let i = 0; i < len; i++) {
- const l = lParts[i] || 0;
- const r = rParts[i] || 0;
- if (l !== r) return l > r ? 1 : -1;
- }
- return 0;
- }),
-
- compare: jest.fn((lhs, rhs) => {
- switch (typeof lhs) {
- case "boolean":
- case "number":
- case "string":
- return lhs === rhs ? 0 : lhs > rhs ? 1 : -1;
- default:
- if (isObject(lhs) || Array.isArray(lhs)) {
- if (isEqualsDeep(lhs, rhs)) {
- return 0;
- }
- }
- break;
- }
- return null;
- }),
-
- extractVar: jest.fn((path) => {
- switch (path) {
- case "a/b/c":
- return "abc";
- default:
- return null;
- }
- }),
- };
-}
diff --git a/src/__tests__/jsonexpr/operators/gt.test.js b/src/__tests__/jsonexpr/operators/gt.test.js
deleted file mode 100644
index e134f72..0000000
--- a/src/__tests__/jsonexpr/operators/gt.test.js
+++ /dev/null
@@ -1,50 +0,0 @@
-import { mockEvaluator } from "./evaluator";
-import { GreaterThanOperator } from "../../../jsonexpr/operators/gt";
-
-describe("GreaterThanOperator", () => {
- const operator = new GreaterThanOperator();
-
- describe("evaluate", () => {
- const evaluator = mockEvaluator();
-
- it("should return true when left-side argument is greater and comparable", () => {
- expect(operator.evaluate(evaluator, [0, 0])).toBe(false);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(2);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(1, 0);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(2, 0);
- expect(evaluator.compare).toHaveBeenCalledTimes(1);
- expect(evaluator.compare).toHaveBeenCalledWith(0, 0);
-
- evaluator.evaluate.mockClear();
- evaluator.compare.mockClear();
-
- expect(operator.evaluate(evaluator, [1, 0])).toBe(true);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(2);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(1, 1);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(2, 0);
- expect(evaluator.compare).toHaveBeenCalledTimes(1);
- expect(evaluator.compare).toHaveBeenCalledWith(1, 0);
-
- evaluator.evaluate.mockClear();
- evaluator.compare.mockClear();
-
- expect(operator.evaluate(evaluator, [0, 1])).toBe(false);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(2);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(1, 0);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(2, 1);
- expect(evaluator.compare).toHaveBeenCalledTimes(1);
- expect(evaluator.compare).toHaveBeenCalledWith(0, 1);
-
- evaluator.evaluate.mockClear();
- evaluator.compare.mockClear();
-
- expect(operator.evaluate(evaluator, [null, null])).toBe(null);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(1);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(1, null);
- expect(evaluator.compare).toHaveBeenCalledTimes(0);
-
- evaluator.evaluate.mockClear();
- evaluator.compare.mockClear();
- });
- });
-});
diff --git a/src/__tests__/jsonexpr/operators/gte.test.js b/src/__tests__/jsonexpr/operators/gte.test.js
deleted file mode 100644
index 4adbbea..0000000
--- a/src/__tests__/jsonexpr/operators/gte.test.js
+++ /dev/null
@@ -1,50 +0,0 @@
-import { mockEvaluator } from "./evaluator";
-import { GreaterThanOrEqualOperator } from "../../../jsonexpr/operators/gte";
-
-describe("GreaterThanOrEqualOperator", () => {
- const operator = new GreaterThanOrEqualOperator();
-
- describe("evaluate", () => {
- const evaluator = mockEvaluator();
-
- it("should return true when left-side argument is greater or equal and comparable", () => {
- expect(operator.evaluate(evaluator, [0, 0])).toBe(true);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(2);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(1, 0);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(2, 0);
- expect(evaluator.compare).toHaveBeenCalledTimes(1);
- expect(evaluator.compare).toHaveBeenCalledWith(0, 0);
-
- evaluator.evaluate.mockClear();
- evaluator.compare.mockClear();
-
- expect(operator.evaluate(evaluator, [1, 0])).toBe(true);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(2);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(1, 1);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(2, 0);
- expect(evaluator.compare).toHaveBeenCalledTimes(1);
- expect(evaluator.compare).toHaveBeenCalledWith(1, 0);
-
- evaluator.evaluate.mockClear();
- evaluator.compare.mockClear();
-
- expect(operator.evaluate(evaluator, [0, 1])).toBe(false);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(2);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(1, 0);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(2, 1);
- expect(evaluator.compare).toHaveBeenCalledTimes(1);
- expect(evaluator.compare).toHaveBeenCalledWith(0, 1);
-
- evaluator.evaluate.mockClear();
- evaluator.compare.mockClear();
-
- expect(operator.evaluate(evaluator, [null, null])).toBe(null);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(1);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(1, null);
- expect(evaluator.compare).toHaveBeenCalledTimes(0);
-
- evaluator.evaluate.mockClear();
- evaluator.compare.mockClear();
- });
- });
-});
diff --git a/src/__tests__/jsonexpr/operators/in.test.js b/src/__tests__/jsonexpr/operators/in.test.js
deleted file mode 100644
index 27fcef5..0000000
--- a/src/__tests__/jsonexpr/operators/in.test.js
+++ /dev/null
@@ -1,178 +0,0 @@
-import { mockEvaluator } from "./evaluator";
-import { InOperator } from "../../../jsonexpr/operators/in";
-
-describe("InOperator", () => {
- const operator = new InOperator();
-
- describe("evaluate", () => {
- const evaluator = mockEvaluator();
-
- it("should return true if string contains needle", () => {
- expect(operator.evaluate(evaluator, ["abcdefghijk", "abc"])).toBe(true);
- expect(operator.evaluate(evaluator, ["abcdefghijk", "def"])).toBe(true);
- expect(operator.evaluate(evaluator, ["abcdefghijk", "xxx"])).toBe(false);
-
- expect(operator.evaluate(evaluator, ["abcdefghijk", null])).toBe(null);
- expect(operator.evaluate(evaluator, [null, "abc"])).toBe(null);
-
- expect(evaluator.evaluate).toHaveBeenCalledTimes(9);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(1, "abcdefghijk");
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(2, "abc");
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(3, "abcdefghijk");
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(4, "def");
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(5, "abcdefghijk");
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(6, "xxx");
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(7, "abcdefghijk");
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(8, null);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(9, null);
-
- expect(evaluator.stringConvert).toHaveBeenCalledTimes(3);
- expect(evaluator.stringConvert).toHaveBeenNthCalledWith(1, "abc");
- expect(evaluator.stringConvert).toHaveBeenNthCalledWith(2, "def");
- expect(evaluator.stringConvert).toHaveBeenNthCalledWith(3, "xxx");
- });
-
- it("should return false with empty array", () => {
- expect(operator.evaluate(evaluator, [[], 1])).toBe(false);
- expect(operator.evaluate(evaluator, [[], "1"])).toBe(false);
- expect(operator.evaluate(evaluator, [[], true])).toBe(false);
- expect(operator.evaluate(evaluator, [[], false])).toBe(false);
- expect(operator.evaluate(evaluator, [[], null])).toBe(null);
-
- expect(evaluator.evaluate).toHaveBeenCalledTimes(10);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(1, []);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(2, 1);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(3, []);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(4, "1");
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(5, []);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(6, true);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(7, []);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(8, false);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(9, []);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(10, null);
-
- expect(evaluator.booleanConvert).not.toHaveBeenCalled();
- expect(evaluator.numberConvert).not.toHaveBeenCalled();
- expect(evaluator.stringConvert).not.toHaveBeenCalled();
- expect(evaluator.compare).not.toHaveBeenCalled();
- });
-
- it("should compare array elements as left-side and needle as right-side", () => {
- const haystack01 = [0, 1];
- const haystack12 = [1, 2];
-
- expect(operator.evaluate(evaluator, [haystack01, 2])).toBe(false);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(2);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(1, haystack01);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(2, 2);
- expect(evaluator.compare).toHaveBeenCalledTimes(2);
- expect(evaluator.compare).toHaveBeenNthCalledWith(1, 0, 2);
- expect(evaluator.compare).toHaveBeenNthCalledWith(2, 1, 2);
-
- evaluator.evaluate.mockClear();
- evaluator.compare.mockClear();
-
- expect(operator.evaluate(evaluator, [haystack12, 0])).toBe(false);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(2);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(1, haystack12);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(2, 0);
- expect(evaluator.compare).toHaveBeenCalledTimes(2);
- expect(evaluator.compare).toHaveBeenNthCalledWith(1, 1, 0);
- expect(evaluator.compare).toHaveBeenNthCalledWith(2, 2, 0);
-
- evaluator.evaluate.mockClear();
- evaluator.compare.mockClear();
-
- expect(operator.evaluate(evaluator, [haystack12, 1])).toBe(true);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(2);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(1, haystack12);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(2, 1);
- expect(evaluator.compare).toHaveBeenCalledTimes(1);
- expect(evaluator.compare).toHaveBeenNthCalledWith(1, 1, 1);
-
- evaluator.evaluate.mockClear();
- evaluator.compare.mockClear();
-
- expect(operator.evaluate(evaluator, [haystack12, 2])).toBe(true);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(2);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(1, haystack12);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(2, 2);
- expect(evaluator.compare).toHaveBeenCalledTimes(2);
- expect(evaluator.compare).toHaveBeenNthCalledWith(1, 1, 2);
- expect(evaluator.compare).toHaveBeenNthCalledWith(2, 2, 2);
- });
-
- it("should return true if object contains key", () => {
- const haystackab = { a: 1, b: 2 };
- const haystackbc = { b: 2, c: 3, 0: 100 };
-
- expect(operator.evaluate(evaluator, [haystackab, "c"])).toBe(false);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(2);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(1, haystackab);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(2, "c");
- expect(evaluator.stringConvert).toHaveBeenCalledTimes(1);
- expect(evaluator.stringConvert).toHaveBeenCalledWith("c");
-
- evaluator.evaluate.mockClear();
- evaluator.stringConvert.mockClear();
-
- expect(operator.evaluate(evaluator, [haystackbc, "a"])).toBe(false);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(2);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(1, haystackbc);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(2, "a");
- expect(evaluator.stringConvert).toHaveBeenCalledTimes(1);
- expect(evaluator.stringConvert).toHaveBeenCalledWith("a");
-
- evaluator.evaluate.mockClear();
- evaluator.stringConvert.mockClear();
-
- expect(operator.evaluate(evaluator, [haystackbc, "b"])).toBe(true);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(2);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(1, haystackbc);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(2, "b");
- expect(evaluator.stringConvert).toHaveBeenCalledTimes(1);
- expect(evaluator.stringConvert).toHaveBeenCalledWith("b");
-
- evaluator.evaluate.mockClear();
- evaluator.stringConvert.mockClear();
-
- expect(operator.evaluate(evaluator, [haystackbc, "c"])).toBe(true);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(2);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(1, haystackbc);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(2, "c");
- expect(evaluator.stringConvert).toHaveBeenCalledTimes(1);
- expect(evaluator.stringConvert).toHaveBeenCalledWith("c");
-
- evaluator.evaluate.mockClear();
- evaluator.stringConvert.mockClear();
-
- expect(operator.evaluate(evaluator, [haystackbc, 0])).toBe(true);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(2);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(1, haystackbc);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(2, 0);
- expect(evaluator.stringConvert).toHaveBeenCalledTimes(1);
- expect(evaluator.stringConvert).toHaveBeenCalledWith(0);
-
- evaluator.evaluate.mockClear();
- evaluator.stringConvert.mockClear();
- });
- });
-});
-
-/*
- assertTrue((Boolean) operator.evaluate(evaluator, listOf(haystackbc, "b")));
- verify(evaluator, times(2)).evaluate(any());
- verify(evaluator, times(1)).evaluate(haystackbc);
- verify(evaluator, times(1)).stringConvert(any());
- verify(evaluator, times(1)).stringConvert("b");
- verify(evaluator, times(1)).evaluate("b");
- Mockito.clearInvocations(evaluator);
-
- assertTrue((Boolean) operator.evaluate(evaluator, listOf(haystackbc, "c")));
- verify(evaluator, times(2)).evaluate(any());
- verify(evaluator, times(1)).evaluate(haystackbc);
- verify(evaluator, times(1)).stringConvert(any());
- verify(evaluator, times(1)).stringConvert("c");
- verify(evaluator, times(1)).evaluate("c");
- Mockito.clearInvocations(evaluator);
- */
diff --git a/src/__tests__/jsonexpr/operators/lt.test.js b/src/__tests__/jsonexpr/operators/lt.test.js
deleted file mode 100644
index fac955e..0000000
--- a/src/__tests__/jsonexpr/operators/lt.test.js
+++ /dev/null
@@ -1,50 +0,0 @@
-import { mockEvaluator } from "./evaluator";
-import { LessThanOperator } from "../../../jsonexpr/operators/lt";
-
-describe("LessThanOperator", () => {
- const operator = new LessThanOperator();
-
- describe("evaluate", () => {
- const evaluator = mockEvaluator();
-
- it("should return true when left-side argument is less and comparable", () => {
- expect(operator.evaluate(evaluator, [0, 0])).toBe(false);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(2);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(1, 0);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(2, 0);
- expect(evaluator.compare).toHaveBeenCalledTimes(1);
- expect(evaluator.compare).toHaveBeenCalledWith(0, 0);
-
- evaluator.evaluate.mockClear();
- evaluator.compare.mockClear();
-
- expect(operator.evaluate(evaluator, [1, 0])).toBe(false);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(2);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(1, 1);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(2, 0);
- expect(evaluator.compare).toHaveBeenCalledTimes(1);
- expect(evaluator.compare).toHaveBeenCalledWith(1, 0);
-
- evaluator.evaluate.mockClear();
- evaluator.compare.mockClear();
-
- expect(operator.evaluate(evaluator, [0, 1])).toBe(true);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(2);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(1, 0);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(2, 1);
- expect(evaluator.compare).toHaveBeenCalledTimes(1);
- expect(evaluator.compare).toHaveBeenCalledWith(0, 1);
-
- evaluator.evaluate.mockClear();
- evaluator.compare.mockClear();
-
- expect(operator.evaluate(evaluator, [null, null])).toBe(null);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(1);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(1, null);
- expect(evaluator.compare).toHaveBeenCalledTimes(0);
-
- evaluator.evaluate.mockClear();
- evaluator.compare.mockClear();
- });
- });
-});
diff --git a/src/__tests__/jsonexpr/operators/lte.test.js b/src/__tests__/jsonexpr/operators/lte.test.js
deleted file mode 100644
index bb59afc..0000000
--- a/src/__tests__/jsonexpr/operators/lte.test.js
+++ /dev/null
@@ -1,50 +0,0 @@
-import { mockEvaluator } from "./evaluator";
-import { LessThanOrEqualOperator } from "../../../jsonexpr/operators/lte";
-
-describe("LessThanOrEqualOperator", () => {
- const operator = new LessThanOrEqualOperator();
-
- describe("evaluate", () => {
- const evaluator = mockEvaluator();
-
- it("should return true when left-side argument is less or equal and comparable", () => {
- expect(operator.evaluate(evaluator, [0, 0])).toBe(true);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(2);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(1, 0);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(2, 0);
- expect(evaluator.compare).toHaveBeenCalledTimes(1);
- expect(evaluator.compare).toHaveBeenCalledWith(0, 0);
-
- evaluator.evaluate.mockClear();
- evaluator.compare.mockClear();
-
- expect(operator.evaluate(evaluator, [1, 0])).toBe(false);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(2);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(1, 1);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(2, 0);
- expect(evaluator.compare).toHaveBeenCalledTimes(1);
- expect(evaluator.compare).toHaveBeenCalledWith(1, 0);
-
- evaluator.evaluate.mockClear();
- evaluator.compare.mockClear();
-
- expect(operator.evaluate(evaluator, [0, 1])).toBe(true);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(2);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(1, 0);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(2, 1);
- expect(evaluator.compare).toHaveBeenCalledTimes(1);
- expect(evaluator.compare).toHaveBeenCalledWith(0, 1);
-
- evaluator.evaluate.mockClear();
- evaluator.compare.mockClear();
-
- expect(operator.evaluate(evaluator, [null, null])).toBe(null);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(1);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(1, null);
- expect(evaluator.compare).toHaveBeenCalledTimes(0);
-
- evaluator.evaluate.mockClear();
- evaluator.compare.mockClear();
- });
- });
-});
diff --git a/src/__tests__/jsonexpr/operators/match.test.js b/src/__tests__/jsonexpr/operators/match.test.js
deleted file mode 100644
index 4783aa1..0000000
--- a/src/__tests__/jsonexpr/operators/match.test.js
+++ /dev/null
@@ -1,35 +0,0 @@
-import { mockEvaluator } from "./evaluator";
-import { MatchOperator } from "../../../jsonexpr/operators/match";
-
-describe("MatchOperator", () => {
- const operator = new MatchOperator();
-
- describe("evaluate", () => {
- const evaluator = mockEvaluator();
-
- it("", () => {
- expect(operator.evaluate(evaluator, ["abcdefghijk", ""])).toBe(true);
- expect(operator.evaluate(evaluator, ["abcdefghijk", "abc"])).toBe(true);
- expect(operator.evaluate(evaluator, ["abcdefghijk", "ijk"])).toBe(true);
- expect(operator.evaluate(evaluator, ["abcdefghijk", "^abc"])).toBe(true);
- expect(operator.evaluate(evaluator, ["abcdefghijk", "ijk$"])).toBe(true);
- expect(operator.evaluate(evaluator, ["abcdefghijk", "def"])).toBe(true);
- expect(operator.evaluate(evaluator, ["abcdefghijk", "b.*j"])).toBe(true);
- expect(operator.evaluate(evaluator, ["abcdefghijk", "xyz"])).toBe(false);
-
- expect(operator.evaluate(evaluator, [null, "abc"])).toBe(null);
- expect(operator.evaluate(evaluator, ["abcdefghijk", null])).toBe(null);
- });
- });
-});
-
-/*
- assertTrue((Boolean) operator.evaluate(evaluator, listOf("abcdefghijk", "abc")));
- assertTrue((Boolean) operator.evaluate(evaluator, listOf("abcdefghijk", "ijk")));
- assertTrue((Boolean) operator.evaluate(evaluator, listOf("abcdefghijk", "^abc")));
- assertTrue((Boolean) operator.evaluate(evaluator, listOf(",l5abcdefghijk", "ijk$")));
- assertTrue((Boolean) operator.evaluate(evaluator, listOf("abcdefghijk", "def")));
- assertTrue((Boolean) operator.evaluate(evaluator, listOf("abcdefghijk", "b.*j")));
- assertFalse((Boolean) operator.evaluate(evaluator, listOf("abcdefghijk", "xyz")));
-
- */
diff --git a/src/__tests__/jsonexpr/operators/not.test.js b/src/__tests__/jsonexpr/operators/not.test.js
deleted file mode 100644
index a848892..0000000
--- a/src/__tests__/jsonexpr/operators/not.test.js
+++ /dev/null
@@ -1,37 +0,0 @@
-import { mockEvaluator } from "./evaluator";
-import { NotOperator } from "../../../jsonexpr/operators/not";
-
-describe("NotOperator", () => {
- const operator = new NotOperator();
-
- describe("evaluate", () => {
- const evaluator = mockEvaluator();
-
- it("should return true if argument is falsy", () => {
- expect(operator.evaluate(evaluator, false)).toBe(true);
-
- expect(evaluator.evaluate).toHaveBeenCalledTimes(1);
- expect(evaluator.evaluate).toHaveBeenCalledWith(false);
- expect(evaluator.booleanConvert).toHaveBeenCalledTimes(1);
- expect(evaluator.booleanConvert).toHaveBeenCalledWith(false);
- });
-
- it("should return false if argument is truthy", () => {
- expect(operator.evaluate(evaluator, true)).toBe(false);
-
- expect(evaluator.evaluate).toHaveBeenCalledTimes(1);
- expect(evaluator.evaluate).toHaveBeenCalledWith(true);
- expect(evaluator.booleanConvert).toHaveBeenCalledTimes(1);
- expect(evaluator.booleanConvert).toHaveBeenCalledWith(true);
- });
-
- it("should return true if argument is null", () => {
- expect(operator.evaluate(evaluator, null)).toBe(true);
-
- expect(evaluator.evaluate).toHaveBeenCalledTimes(1);
- expect(evaluator.evaluate).toHaveBeenCalledWith(null);
- expect(evaluator.booleanConvert).toHaveBeenCalledTimes(1);
- expect(evaluator.booleanConvert).toHaveBeenCalledWith(null);
- });
- });
-});
diff --git a/src/__tests__/jsonexpr/operators/null.test.js b/src/__tests__/jsonexpr/operators/null.test.js
deleted file mode 100644
index e464821..0000000
--- a/src/__tests__/jsonexpr/operators/null.test.js
+++ /dev/null
@@ -1,53 +0,0 @@
-import { mockEvaluator } from "./evaluator";
-import { NullOperator } from "../../../jsonexpr/operators/null";
-
-describe("NullOperator", () => {
- const operator = new NullOperator();
-
- describe("evaluate", () => {
- const evaluator = mockEvaluator();
-
- it("should return true if argument is null", () => {
- expect(operator.evaluate(evaluator, null)).toBe(true);
-
- expect(evaluator.evaluate).toHaveBeenCalledTimes(1);
- expect(evaluator.evaluate).toHaveBeenCalledWith(null);
- expect(evaluator.booleanConvert).not.toHaveBeenCalled();
- });
-
- it("should return true if argument is not null", () => {
- expect(operator.evaluate(evaluator, true)).toBe(false);
-
- expect(evaluator.evaluate).toHaveBeenCalledTimes(1);
- expect(evaluator.evaluate).toHaveBeenCalledWith(true);
-
- expect(operator.evaluate(evaluator, false)).toBe(false);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(2);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(2, false);
-
- expect(operator.evaluate(evaluator, 0)).toBe(false);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(3);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(3, 0);
- });
- });
-});
-
-/*
- @Test
- void testNull() {
- assertTrue((Boolean) operator.evaluate(evaluator, null));
- verify(evaluator, times(1)).evaluate(null);
- }
-
- @Test
- void testNotNull() {
- assertFalse((Boolean) operator.evaluate(evaluator, true));
- verify(evaluator, times(1)).evaluate(true);
-
- assertFalse((Boolean) operator.evaluate(evaluator, false));
- verify(evaluator, times(1)).evaluate(false);
-
- assertFalse((Boolean) operator.evaluate(evaluator, 0));
- verify(evaluator, times(1)).evaluate(0);
- }
- */
diff --git a/src/__tests__/jsonexpr/operators/or.test.js b/src/__tests__/jsonexpr/operators/or.test.js
deleted file mode 100644
index 566a223..0000000
--- a/src/__tests__/jsonexpr/operators/or.test.js
+++ /dev/null
@@ -1,52 +0,0 @@
-import { mockEvaluator } from "./evaluator";
-import { OrCombinator } from "../../../jsonexpr/operators/or";
-
-describe("OrCombinator", () => {
- const combinator = new OrCombinator();
-
- describe("evaluate", () => {
- const evaluator = mockEvaluator();
-
- it("should return true if any argument evaluates to true", () => {
- expect(combinator.evaluate(evaluator, [true])).toBe(true);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(1);
- expect(evaluator.evaluate).toHaveBeenCalledWith(true);
- expect(evaluator.booleanConvert).toHaveBeenCalledTimes(1);
- expect(evaluator.booleanConvert).toHaveBeenCalledWith(true);
- });
-
- it("should return false if all arguments evaluate to false", () => {
- expect(combinator.evaluate(evaluator, [false])).toBe(false);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(1);
- expect(evaluator.evaluate).toHaveBeenCalledWith(false);
- expect(evaluator.booleanConvert).toHaveBeenCalledTimes(1);
- expect(evaluator.booleanConvert).toHaveBeenCalledWith(false);
- });
-
- it("should return false if all arguments evaluates to null", () => {
- expect(combinator.evaluate(evaluator, [null])).toBe(false);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(1);
- expect(evaluator.evaluate).toHaveBeenCalledWith(null);
- expect(evaluator.booleanConvert).toHaveBeenCalledTimes(1);
- expect(evaluator.booleanConvert).toHaveBeenCalledWith(null);
- });
-
- it("should short-circuit and not evaluate unnecessary expressions", () => {
- expect(combinator.evaluate(evaluator, [true, false, true])).toBe(true);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(1);
- expect(evaluator.booleanConvert).toHaveBeenCalledTimes(1);
- expect(evaluator.evaluate).toHaveBeenNthCalledWith(1, true);
- expect(evaluator.booleanConvert).toHaveBeenNthCalledWith(1, true);
- });
-
- it("should combine multiple arguments", () => {
- expect(combinator.evaluate(evaluator, [true, true])).toBe(true);
- expect(combinator.evaluate(evaluator, [true, true, true])).toBe(true);
-
- expect(combinator.evaluate(evaluator, [true, false])).toBe(true);
- expect(combinator.evaluate(evaluator, [false, true])).toBe(true);
- expect(combinator.evaluate(evaluator, [false, false])).toBe(false);
- expect(combinator.evaluate(evaluator, [false, false, false])).toBe(false);
- });
- });
-});
diff --git a/src/__tests__/jsonexpr/operators/semver_eq.test.js b/src/__tests__/jsonexpr/operators/semver_eq.test.js
deleted file mode 100644
index 187747b..0000000
--- a/src/__tests__/jsonexpr/operators/semver_eq.test.js
+++ /dev/null
@@ -1,38 +0,0 @@
-import { mockEvaluator } from "./evaluator";
-import { SemverEqualsOperator } from "../../../jsonexpr/operators/semver_eq";
-
-describe("SemverEqualsOperator", () => {
- const operator = new SemverEqualsOperator();
-
- describe("evaluate", () => {
- const evaluator = mockEvaluator();
-
- afterEach(() => {
- evaluator.evaluate.mockClear();
- evaluator.versionCompare.mockClear();
- });
-
- it("should return true when versions are equal", () => {
- expect(operator.evaluate(evaluator, ["1.0.0", "1.0.0"])).toBe(true);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(2);
- expect(evaluator.versionCompare).toHaveBeenCalledWith("1.0.0", "1.0.0");
- });
-
- it("should return false when versions are not equal", () => {
- expect(operator.evaluate(evaluator, ["1.0.0", "2.0.0"])).toBe(false);
- expect(evaluator.versionCompare).toHaveBeenCalledWith("1.0.0", "2.0.0");
- });
-
- it("should return null when lhs is null", () => {
- expect(operator.evaluate(evaluator, [null, "1.0.0"])).toBe(null);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(1);
- expect(evaluator.versionCompare).not.toHaveBeenCalled();
- });
-
- it("should return null when rhs is null", () => {
- expect(operator.evaluate(evaluator, ["1.0.0", null])).toBe(null);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(2);
- expect(evaluator.versionCompare).not.toHaveBeenCalled();
- });
- });
-});
diff --git a/src/__tests__/jsonexpr/operators/semver_gt.test.js b/src/__tests__/jsonexpr/operators/semver_gt.test.js
deleted file mode 100644
index bb63d6f..0000000
--- a/src/__tests__/jsonexpr/operators/semver_gt.test.js
+++ /dev/null
@@ -1,42 +0,0 @@
-import { mockEvaluator } from "./evaluator";
-import { SemverGreaterThanOperator } from "../../../jsonexpr/operators/semver_gt";
-
-describe("SemverGreaterThanOperator", () => {
- const operator = new SemverGreaterThanOperator();
-
- describe("evaluate", () => {
- const evaluator = mockEvaluator();
-
- afterEach(() => {
- evaluator.evaluate.mockClear();
- evaluator.versionCompare.mockClear();
- });
-
- it("should return true when left version is greater", () => {
- expect(operator.evaluate(evaluator, ["2.0.0", "1.0.0"])).toBe(true);
- expect(evaluator.versionCompare).toHaveBeenCalledWith("2.0.0", "1.0.0");
- });
-
- it("should return false when versions are equal", () => {
- expect(operator.evaluate(evaluator, ["1.0.0", "1.0.0"])).toBe(false);
- expect(evaluator.versionCompare).toHaveBeenCalledWith("1.0.0", "1.0.0");
- });
-
- it("should return false when left version is less", () => {
- expect(operator.evaluate(evaluator, ["1.0.0", "2.0.0"])).toBe(false);
- expect(evaluator.versionCompare).toHaveBeenCalledWith("1.0.0", "2.0.0");
- });
-
- it("should return null when lhs is null", () => {
- expect(operator.evaluate(evaluator, [null, "1.0.0"])).toBe(null);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(1);
- expect(evaluator.versionCompare).not.toHaveBeenCalled();
- });
-
- it("should return null when rhs is null", () => {
- expect(operator.evaluate(evaluator, ["1.0.0", null])).toBe(null);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(2);
- expect(evaluator.versionCompare).not.toHaveBeenCalled();
- });
- });
-});
diff --git a/src/__tests__/jsonexpr/operators/semver_gte.test.js b/src/__tests__/jsonexpr/operators/semver_gte.test.js
deleted file mode 100644
index 38e6e84..0000000
--- a/src/__tests__/jsonexpr/operators/semver_gte.test.js
+++ /dev/null
@@ -1,42 +0,0 @@
-import { mockEvaluator } from "./evaluator";
-import { SemverGreaterThanOrEqualOperator } from "../../../jsonexpr/operators/semver_gte";
-
-describe("SemverGreaterThanOrEqualOperator", () => {
- const operator = new SemverGreaterThanOrEqualOperator();
-
- describe("evaluate", () => {
- const evaluator = mockEvaluator();
-
- afterEach(() => {
- evaluator.evaluate.mockClear();
- evaluator.versionCompare.mockClear();
- });
-
- it("should return true when left version is greater", () => {
- expect(operator.evaluate(evaluator, ["2.0.0", "1.0.0"])).toBe(true);
- expect(evaluator.versionCompare).toHaveBeenCalledWith("2.0.0", "1.0.0");
- });
-
- it("should return true when versions are equal", () => {
- expect(operator.evaluate(evaluator, ["1.0.0", "1.0.0"])).toBe(true);
- expect(evaluator.versionCompare).toHaveBeenCalledWith("1.0.0", "1.0.0");
- });
-
- it("should return false when left version is less", () => {
- expect(operator.evaluate(evaluator, ["1.0.0", "2.0.0"])).toBe(false);
- expect(evaluator.versionCompare).toHaveBeenCalledWith("1.0.0", "2.0.0");
- });
-
- it("should return null when lhs is null", () => {
- expect(operator.evaluate(evaluator, [null, "1.0.0"])).toBe(null);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(1);
- expect(evaluator.versionCompare).not.toHaveBeenCalled();
- });
-
- it("should return null when rhs is null", () => {
- expect(operator.evaluate(evaluator, ["1.0.0", null])).toBe(null);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(2);
- expect(evaluator.versionCompare).not.toHaveBeenCalled();
- });
- });
-});
diff --git a/src/__tests__/jsonexpr/operators/semver_lt.test.js b/src/__tests__/jsonexpr/operators/semver_lt.test.js
deleted file mode 100644
index 410619f..0000000
--- a/src/__tests__/jsonexpr/operators/semver_lt.test.js
+++ /dev/null
@@ -1,42 +0,0 @@
-import { mockEvaluator } from "./evaluator";
-import { SemverLessThanOperator } from "../../../jsonexpr/operators/semver_lt";
-
-describe("SemverLessThanOperator", () => {
- const operator = new SemverLessThanOperator();
-
- describe("evaluate", () => {
- const evaluator = mockEvaluator();
-
- afterEach(() => {
- evaluator.evaluate.mockClear();
- evaluator.versionCompare.mockClear();
- });
-
- it("should return true when left version is less", () => {
- expect(operator.evaluate(evaluator, ["1.0.0", "2.0.0"])).toBe(true);
- expect(evaluator.versionCompare).toHaveBeenCalledWith("1.0.0", "2.0.0");
- });
-
- it("should return false when versions are equal", () => {
- expect(operator.evaluate(evaluator, ["1.0.0", "1.0.0"])).toBe(false);
- expect(evaluator.versionCompare).toHaveBeenCalledWith("1.0.0", "1.0.0");
- });
-
- it("should return false when left version is greater", () => {
- expect(operator.evaluate(evaluator, ["2.0.0", "1.0.0"])).toBe(false);
- expect(evaluator.versionCompare).toHaveBeenCalledWith("2.0.0", "1.0.0");
- });
-
- it("should return null when lhs is null", () => {
- expect(operator.evaluate(evaluator, [null, "1.0.0"])).toBe(null);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(1);
- expect(evaluator.versionCompare).not.toHaveBeenCalled();
- });
-
- it("should return null when rhs is null", () => {
- expect(operator.evaluate(evaluator, ["1.0.0", null])).toBe(null);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(2);
- expect(evaluator.versionCompare).not.toHaveBeenCalled();
- });
- });
-});
diff --git a/src/__tests__/jsonexpr/operators/semver_lte.test.js b/src/__tests__/jsonexpr/operators/semver_lte.test.js
deleted file mode 100644
index b4a870f..0000000
--- a/src/__tests__/jsonexpr/operators/semver_lte.test.js
+++ /dev/null
@@ -1,42 +0,0 @@
-import { mockEvaluator } from "./evaluator";
-import { SemverLessThanOrEqualOperator } from "../../../jsonexpr/operators/semver_lte";
-
-describe("SemverLessThanOrEqualOperator", () => {
- const operator = new SemverLessThanOrEqualOperator();
-
- describe("evaluate", () => {
- const evaluator = mockEvaluator();
-
- afterEach(() => {
- evaluator.evaluate.mockClear();
- evaluator.versionCompare.mockClear();
- });
-
- it("should return true when left version is less", () => {
- expect(operator.evaluate(evaluator, ["1.0.0", "2.0.0"])).toBe(true);
- expect(evaluator.versionCompare).toHaveBeenCalledWith("1.0.0", "2.0.0");
- });
-
- it("should return true when versions are equal", () => {
- expect(operator.evaluate(evaluator, ["1.0.0", "1.0.0"])).toBe(true);
- expect(evaluator.versionCompare).toHaveBeenCalledWith("1.0.0", "1.0.0");
- });
-
- it("should return false when left version is greater", () => {
- expect(operator.evaluate(evaluator, ["2.0.0", "1.0.0"])).toBe(false);
- expect(evaluator.versionCompare).toHaveBeenCalledWith("2.0.0", "1.0.0");
- });
-
- it("should return null when lhs is null", () => {
- expect(operator.evaluate(evaluator, [null, "1.0.0"])).toBe(null);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(1);
- expect(evaluator.versionCompare).not.toHaveBeenCalled();
- });
-
- it("should return null when rhs is null", () => {
- expect(operator.evaluate(evaluator, ["1.0.0", null])).toBe(null);
- expect(evaluator.evaluate).toHaveBeenCalledTimes(2);
- expect(evaluator.versionCompare).not.toHaveBeenCalled();
- });
- });
-});
diff --git a/src/__tests__/jsonexpr/operators/value.test.js b/src/__tests__/jsonexpr/operators/value.test.js
deleted file mode 100644
index d676acd..0000000
--- a/src/__tests__/jsonexpr/operators/value.test.js
+++ /dev/null
@@ -1,23 +0,0 @@
-import { mockEvaluator } from "./evaluator";
-import { ValueOperator } from "../../../jsonexpr/operators/value";
-
-describe("ValueOperator", () => {
- const operator = new ValueOperator();
-
- describe("evaluate", () => {
- const evaluator = mockEvaluator();
-
- it("should not call evaluator evaluate", () => {
- expect(operator.evaluate(evaluator, 0)).toBe(0);
- expect(operator.evaluate(evaluator, 1)).toBe(1);
- expect(operator.evaluate(evaluator, true)).toBe(true);
- expect(operator.evaluate(evaluator, false)).toBe(false);
- expect(operator.evaluate(evaluator, "")).toBe("");
- expect(operator.evaluate(evaluator, null)).toBe(null);
- expect(operator.evaluate(evaluator, {})).toEqual({});
- expect(operator.evaluate(evaluator, [])).toEqual([]);
-
- expect(evaluator.evaluate).not.toHaveBeenCalled();
- });
- });
-});
diff --git a/src/__tests__/jsonexpr/operators/var.test.js b/src/__tests__/jsonexpr/operators/var.test.js
deleted file mode 100644
index ac00c64..0000000
--- a/src/__tests__/jsonexpr/operators/var.test.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import { mockEvaluator } from "./evaluator";
-import { VarOperator } from "../../../jsonexpr/operators/var";
-
-describe("VarOperator", () => {
- const operator = new VarOperator();
-
- describe("evaluate", () => {
- const evaluator = mockEvaluator();
-
- it("should call evaluator extract", () => {
- expect(operator.evaluate(evaluator, "a/b/c")).toBe("abc");
-
- expect(evaluator.extractVar).toHaveBeenCalledTimes(1);
- expect(evaluator.extractVar).toHaveBeenCalledWith("a/b/c");
- expect(evaluator.evaluate).not.toHaveBeenCalled();
- });
- });
-});
diff --git a/src/__tests__/matcher.test.js b/src/__tests__/matcher.test.js
deleted file mode 100644
index 05c345c..0000000
--- a/src/__tests__/matcher.test.js
+++ /dev/null
@@ -1,49 +0,0 @@
-import { AudienceMatcher } from "../matcher";
-
-describe("AudienceMatcher", () => {
- const matcher = new AudienceMatcher();
-
- it("should return null on empty audience", () => {
- expect(matcher.evaluate("", null)).toBe(null);
- expect(matcher.evaluate("{}", null)).toBe(null);
- expect(matcher.evaluate("null", null)).toBe(null);
- });
-
- it("should return null if filter not object or array", () => {
- expect(matcher.evaluate('{"filter":null}', null)).toBe(null);
- expect(matcher.evaluate('{"filter":false}', null)).toBe(null);
- expect(matcher.evaluate('{"filter":5}', null)).toBe(null);
- expect(matcher.evaluate('{"filter":"a"}', null)).toBe(null);
- });
-
- it("should return boolean", () => {
- expect(matcher.evaluate('{"filter":[{"value":5}]}', null)).toBe(true);
- expect(matcher.evaluate('{"filter":[{"value":true}]}', null)).toBe(true);
- expect(matcher.evaluate('{"filter":[{"value":1}]}', null)).toBe(true);
- expect(matcher.evaluate('{"filter":[{"value":null}]}', null)).toBe(false);
- expect(matcher.evaluate('{"filter":[{"value":0}]}', null)).toBe(false);
-
- expect(matcher.evaluate('{"filter":[{"not":{"var":"returning"}}]}', { returning: true })).toBe(false);
- expect(matcher.evaluate('{"filter":[{"not":{"var":"returning"}}]}', { returning: false })).toBe(true);
- });
-});
-
-/*
-
- @Test
- void evaluateReturnsNullIfFilterNotMapOrList() {
- assertNull(matcher.evaluate("{\"filter\":5}", null));
- }
-
- @Test
- void evaluateReturnsBoolean() {
- assertTrue(matcher.evaluate("{\"filter\":[{\"value\":5}]}", null));
- assertTrue(matcher.evaluate("{\"filter\":[{\"value\":true}]}", null));
- assertTrue(matcher.evaluate("{\"filter\":[{\"value\":1}]}", null));
- assertFalse(matcher.evaluate("{\"filter\":[{\"value\":null}]}", null));
- assertFalse(matcher.evaluate("{\"filter\":[{\"value\":0}]}", null));
-
- assertFalse(matcher.evaluate("{\"filter\":[{\"not\":{\"var\":\"returning\"}}]}", mapOf("returning", true)));
- assertTrue(matcher.evaluate("{\"filter\":[{\"not\":{\"var\":\"returning\"}}]}", mapOf("returning", false)));
- }
- */
diff --git a/src/__tests__/matcher.test.ts b/src/__tests__/matcher.test.ts
new file mode 100644
index 0000000..0664f7a
--- /dev/null
+++ b/src/__tests__/matcher.test.ts
@@ -0,0 +1,111 @@
+import { describe, expect, test, it } from "vitest";
+import { AudienceMatcher } from "../matcher";
+
+describe("AudienceMatcher", () => {
+ const matcher = new AudienceMatcher();
+
+ describe("null/empty handling", () => {
+ test("null audience → null", () => {
+ expect(matcher.evaluate(null as any, {})).toBe(null);
+ });
+
+ test("empty string → null", () => {
+ expect(matcher.evaluate("", {})).toBe(null);
+ });
+
+ test("returns null for invalid JSON", () => {
+ expect(matcher.evaluate("invalid json", {})).toBe(null);
+ });
+
+ test("returns null for missing filter", () => {
+ expect(matcher.evaluate(JSON.stringify({}), {})).toBe(null);
+ });
+
+ test("returns null for null filter", () => {
+ expect(matcher.evaluate(JSON.stringify({ filter: null }), {})).toBe(null);
+ });
+ });
+
+ describe("filter evaluation", () => {
+ test("evaluates matching audience", () => {
+ const audience = JSON.stringify({ filter: [{ value: true }] });
+ expect(matcher.evaluate(audience, {})).toBe(true);
+ });
+
+ test("evaluates non-matching audience", () => {
+ const audience = JSON.stringify({ filter: [{ value: false }] });
+ expect(matcher.evaluate(audience, {})).toBe(false);
+ });
+
+ test("evaluates with not operator", () => {
+ const audience = JSON.stringify({ filter: [{ not: { value: false } }] });
+ expect(matcher.evaluate(audience, {})).toBe(true);
+ });
+
+ it("and with all true → true", () => {
+ const audience = JSON.stringify({
+ filter: [{ and: [{ value: true }, { value: true }] }],
+ });
+ expect(matcher.evaluate(audience, {})).toBe(true);
+ });
+
+ it("and with one false → false", () => {
+ const audience = JSON.stringify({
+ filter: [{ and: [{ value: true }, { value: false }] }],
+ });
+ expect(matcher.evaluate(audience, {})).toBe(false);
+ });
+
+ it("evaluates with attributes (gte)", () => {
+ const audience = JSON.stringify({
+ filter: [{ gte: [{ var: "age" }, { value: 18 }] }],
+ });
+ expect(matcher.evaluate(audience, { age: 25 })).toBe(true);
+ expect(matcher.evaluate(audience, { age: 15 })).toBe(false);
+ });
+
+ it("complex filter with and+gte+in", () => {
+ const audience = JSON.stringify({
+ filter: [{
+ and: [
+ { gte: [{ var: "age" }, { value: 18 }] },
+ { in: [{ value: ["US", "UK"] }, { var: "country" }] },
+ ],
+ }],
+ });
+ expect(matcher.evaluate(audience, { age: 25, country: "US" })).toBe(true);
+ expect(matcher.evaluate(audience, { age: 25, country: "FR" })).toBe(false);
+ expect(matcher.evaluate(audience, { age: 15, country: "US" })).toBe(false);
+ });
+
+ it("or filter", () => {
+ const audience = JSON.stringify({
+ filter: [{
+ or: [
+ { eq: [{ var: "plan" }, { value: "pro" }] },
+ { eq: [{ var: "plan" }, { value: "enterprise" }] },
+ ],
+ }],
+ });
+ expect(matcher.evaluate(audience, { plan: "pro" })).toBe(true);
+ expect(matcher.evaluate(audience, { plan: "enterprise" })).toBe(true);
+ expect(matcher.evaluate(audience, { plan: "free" })).toBe(false);
+ });
+
+ it("not filter", () => {
+ const audience = JSON.stringify({
+ filter: [{ not: { eq: [{ var: "bot" }, { value: true }] } }],
+ });
+ expect(matcher.evaluate(audience, { bot: false })).toBe(true);
+ expect(matcher.evaluate(audience, { bot: true })).toBe(false);
+ });
+
+ it("match filter with regex", () => {
+ const audience = JSON.stringify({
+ filter: [{ match: [{ var: "email" }, { value: ".*@absmartly\\.com$" }] }],
+ });
+ expect(matcher.evaluate(audience, { email: "user@absmartly.com" })).toBe(true);
+ expect(matcher.evaluate(audience, { email: "user@other.com" })).toBe(false);
+ });
+ });
+});
diff --git a/src/__tests__/md5.test.js b/src/__tests__/md5.test.js
deleted file mode 100644
index 6086c21..0000000
--- a/src/__tests__/md5.test.js
+++ /dev/null
@@ -1,34 +0,0 @@
-import { md5 } from "../md5";
-import { base64UrlNoPadding, stringToUint8Array } from "../utils";
-
-describe("md5()", () => {
- it("should match known hashes", (done) => {
- const testCases = [
- ["", "1B2M2Y8AsgTpgAmY7PhCfg"],
- [" ", "chXunH2dwinSkhpA6JnsXw"],
- ["t", "41jvpIn1gGLxDdcxa2Vkng"],
- ["te", "Vp73JkK-D63XEdakaNaO4Q"],
- ["tes", "KLZi2IO212_Zbk3cXpungA"],
- ["test", "CY9rzUYh03PK3k6DJie09g"],
- ["testy", "K5I_V6RgP8c6sYKz-TVn8g"],
- ["testy1", "8fT8xGipOhPkZ2DncKU-1A"],
- ["testy12", "YqRAtOz000gIu61ErEH18A"],
- ["testy123", "pfV2H07L6WvdqlY0zHuYIw"],
- ["special characters açb↓c", "4PIrO7lKtTxOcj2eMYlG7A"],
- ["The quick brown fox jumps over the lazy dog", "nhB9nTcrtoJr2B01QqQZ1g"],
- ["The quick brown fox jumps over the lazy dog and eats a pie", "iM-8ECRrLUQzixl436y96A"],
- [
- "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
- "24m7XOq4f5wPzCqzbBicLA",
- ],
- ];
-
- testCases.forEach((testCase) => {
- const bytes = stringToUint8Array(testCase[0]);
- const hash = md5(bytes.buffer);
- expect(base64UrlNoPadding(hash)).toEqual(testCase[1]);
- });
-
- done();
- });
-});
diff --git a/src/__tests__/md5.test.ts b/src/__tests__/md5.test.ts
new file mode 100644
index 0000000..96ad237
--- /dev/null
+++ b/src/__tests__/md5.test.ts
@@ -0,0 +1,45 @@
+import { describe, expect, test } from "vitest";
+import { md5 } from "../md5";
+
+function stringToBuffer(value: string): ArrayBuffer {
+ const n = value.length;
+ const array: number[] = [];
+ let k = 0;
+ for (let i = 0; i < n; ++i) {
+ const c = value.charCodeAt(i);
+ if (c < 0x80) {
+ array[k++] = c;
+ } else if (c < 0x800) {
+ array[k++] = (c >> 6) | 192;
+ array[k++] = (c & 63) | 128;
+ } else {
+ array[k++] = (c >> 12) | 224;
+ array[k++] = ((c >> 6) & 63) | 128;
+ array[k++] = (c & 63) | 128;
+ }
+ }
+ return Uint8Array.from(array).buffer;
+}
+
+function toHex(bytes: Uint8Array): string {
+ return Array.from(bytes)
+ .map((b) => b.toString(16).padStart(2, "0"))
+ .join("");
+}
+
+describe("md5", () => {
+ const testCases: [string, string][] = [
+ ["", "d41d8cd98f00b204e9800998ecf8427e"],
+ ["a", "0cc175b9c0f1b6a831c399e269772661"],
+ ["abc", "900150983cd24fb0d6963f7d28e17f72"],
+ ["message digest", "f96b697d7cb7938d525a2f31aaf161d0"],
+ ["abcdefghijklmnopqrstuvwxyz", "c3fcd3d76192e4007dfb496cca67e13b"],
+ ];
+
+ for (const [input, expectedHex] of testCases) {
+ test(`md5("${input}") == ${expectedHex}`, () => {
+ const result = md5(stringToBuffer(input));
+ expect(toHex(result)).toBe(expectedHex);
+ });
+ }
+});
diff --git a/src/__tests__/murmur3_32.test.js b/src/__tests__/murmur3.test.ts
similarity index 65%
rename from src/__tests__/murmur3_32.test.js
rename to src/__tests__/murmur3.test.ts
index 6b5a279..7f76321 100644
--- a/src/__tests__/murmur3_32.test.js
+++ b/src/__tests__/murmur3.test.ts
@@ -1,8 +1,9 @@
-import { stringToUint8Array } from "../utils";
-import { murmur3_32 } from "../murmur3_32";
+import { describe, expect, test } from "vitest";
+import { murmur3_32 } from "../murmur3";
+import { stringToUint8Array } from "../hashing";
-describe("murmur3_32()", () => {
- const testCases = [
+describe("murmur3_32", () => {
+ const testCases: [string, number, number][] = [
["", 0x00000000, 0x00000000],
[" ", 0x00000000, 0x7ef49b98],
["t", 0x00000000, 0xca87df4d],
@@ -13,7 +14,7 @@ describe("murmur3_32()", () => {
["testy1", 0x00000000, 0x8a1a243a],
["testy12", 0x00000000, 0x845461b9],
["testy123", 0x00000000, 0x47628ac4],
- ["special characters açb↓c", 0x00000000, 0xbe83b140],
+ ["special characters a\u00e7b\u2193c", 0x00000000, 0xbe83b140],
["The quick brown fox jumps over the lazy dog", 0x00000000, 0x2e4ff723],
["", 0xdeadbeef, 0x0de5c6a9],
[" ", 0xdeadbeef, 0x25acce43],
@@ -25,7 +26,7 @@ describe("murmur3_32()", () => {
["testy1", 0xdeadbeef, 0x09ed28e9],
["testy12", 0xdeadbeef, 0x22467835],
["testy123", 0xdeadbeef, 0xd633060d],
- ["special characters açb↓c", 0xdeadbeef, 0xf7fdd8a2],
+ ["special characters a\u00e7b\u2193c", 0xdeadbeef, 0xf7fdd8a2],
["The quick brown fox jumps over the lazy dog", 0xdeadbeef, 0x3a7b3f4d],
["", 0x00000001, 0x514e28b7],
[" ", 0x00000001, 0x4f0f7132],
@@ -37,16 +38,14 @@ describe("murmur3_32()", () => {
["testy1", 0x00000001, 0x33925ceb],
["testy12", 0x00000001, 0xd92c9f23],
["testy123", 0x00000001, 0x3bc1712d],
- ["special characters açb↓c", 0x00000001, 0x293327b5],
+ ["special characters a\u00e7b\u2193c", 0x00000001, 0x293327b5],
["The quick brown fox jumps over the lazy dog", 0x00000001, 0x78e69e27],
];
- it("should match known hashes", (done) => {
- testCases.forEach((testCase) => {
- const bytes = stringToUint8Array(testCase[0]);
- expect(murmur3_32(bytes.buffer, testCase[1])).toBe(testCase[2]);
+ for (const [input, seed, expected] of testCases) {
+ test(`murmur3_32("${input}", 0x${seed.toString(16)}) == 0x${expected.toString(16).padStart(8, "0")}`, () => {
+ const bytes = stringToUint8Array(input);
+ expect(murmur3_32(bytes.buffer, seed)).toBe(expected);
});
-
- done();
- });
+ }
});
diff --git a/src/__tests__/operators.test.ts b/src/__tests__/operators.test.ts
new file mode 100644
index 0000000..3c2421e
--- /dev/null
+++ b/src/__tests__/operators.test.ts
@@ -0,0 +1,205 @@
+import { describe, it, expect } from "vitest";
+import { Evaluator } from "../jsonexpr/evaluator";
+import {
+ AndCombinator,
+ EqualsOperator,
+ GreaterThanOperator,
+ GreaterThanOrEqualOperator,
+ InOperator,
+ LessThanOperator,
+ LessThanOrEqualOperator,
+ MatchOperator,
+ NotOperator,
+ NullOperator,
+ OrCombinator,
+ ValueOperator,
+ VarOperator,
+} from "../jsonexpr/operators";
+
+const operators = {
+ and: new AndCombinator(),
+ or: new OrCombinator(),
+ value: new ValueOperator(),
+ var: new VarOperator(),
+ null: new NullOperator(),
+ not: new NotOperator(),
+ in: new InOperator(),
+ match: new MatchOperator(),
+ eq: new EqualsOperator(),
+ gt: new GreaterThanOperator(),
+ gte: new GreaterThanOrEqualOperator(),
+ lt: new LessThanOperator(),
+ lte: new LessThanOrEqualOperator(),
+};
+
+function evalExpr(expr: unknown, vars: Record = {}): unknown {
+ const e = new Evaluator(operators, vars);
+ return e.evaluate(expr);
+}
+
+describe("operators", () => {
+ describe("value", () => {
+ it("returns literal", () => expect(evalExpr({ value: 42 })).toBe(42));
+ it("returns string", () => expect(evalExpr({ value: "hello" })).toBe("hello"));
+ it("returns null", () => expect(evalExpr({ value: null })).toBe(null));
+ it("returns boolean", () => expect(evalExpr({ value: true })).toBe(true));
+ });
+
+ // NOTE: Branch VarOperator expects path string or {path: "..."}, not {value: "..."}
+ describe("var", () => {
+ it("extracts variable by path string", () => {
+ expect(evalExpr({ var: "x" }, { x: 99 })).toBe(99);
+ });
+ it("extracts nested via slash-separated path", () => {
+ expect(evalExpr({ var: "a/b" }, { a: { b: 5 } } as any)).toBe(5);
+ });
+ it("missing returns null", () => {
+ expect(evalExpr({ var: "z" }, { x: 1 })).toBe(null);
+ });
+ it("extracts via object with path property", () => {
+ expect(evalExpr({ var: { path: "x" } as unknown }, { x: 42 })).toBe(42);
+ });
+ });
+
+ describe("and", () => {
+ it("empty → true", () => expect(evalExpr({ and: [] })).toBe(true));
+ it("all true → true", () => expect(evalExpr({ and: [{ value: true }, { value: 1 }] })).toBe(true));
+ it("any false → false", () => expect(evalExpr({ and: [{ value: true }, { value: false }] })).toBe(false));
+ it("all false → false", () => expect(evalExpr({ and: [{ value: false }, { value: 0 }] })).toBe(false));
+ });
+
+ // NOTE: Branch OrCombinator returns true for empty array (vacuous truth), matching AndCombinator
+ describe("or", () => {
+ it("empty → true (vacuous)", () => expect(evalExpr({ or: [] })).toBe(true));
+ it("any true → true", () => expect(evalExpr({ or: [{ value: false }, { value: true }] })).toBe(true));
+ it("all false → false", () => expect(evalExpr({ or: [{ value: false }, { value: 0 }] })).toBe(false));
+ it("first true → true", () => expect(evalExpr({ or: [{ value: true }, { value: false }] })).toBe(true));
+ });
+
+ describe("not", () => {
+ it("true → false", () => expect(evalExpr({ not: { value: true } })).toBe(false));
+ it("false → true", () => expect(evalExpr({ not: { value: false } })).toBe(true));
+ it("1 → false", () => expect(evalExpr({ not: { value: 1 } })).toBe(false));
+ it("0 → true", () => expect(evalExpr({ not: { value: 0 } })).toBe(true));
+ it("null → true", () => expect(evalExpr({ not: { value: null } })).toBe(true));
+ });
+
+ describe("null", () => {
+ it("null → true", () => expect(evalExpr({ null: { value: null } })).toBe(true));
+ it("0 → false", () => expect(evalExpr({ null: { value: 0 } })).toBe(false));
+ it("'' → false", () => expect(evalExpr({ null: { value: "" } })).toBe(false));
+ it("false → false", () => expect(evalExpr({ null: { value: false } })).toBe(false));
+ });
+
+ // NOTE: BinaryOperator base returns null if lhs is null, so eq(null, null) → null
+ describe("eq", () => {
+ it("null == null → null (null short-circuits)", () =>
+ expect(evalExpr({ eq: [{ value: null }, { value: null }] })).toBe(null));
+ it("null == 0 → null", () => expect(evalExpr({ eq: [{ value: null }, { value: 0 }] })).toBe(null));
+ it("0 == 0 → true", () => expect(evalExpr({ eq: [{ value: 0 }, { value: 0 }] })).toBe(true));
+ it("1 == 0 → false", () => expect(evalExpr({ eq: [{ value: 1 }, { value: 0 }] })).toBe(false));
+ it("'a' == 'a' → true", () => expect(evalExpr({ eq: [{ value: "a" }, { value: "a" }] })).toBe(true));
+ it("'a' == 'b' → false", () => expect(evalExpr({ eq: [{ value: "a" }, { value: "b" }] })).toBe(false));
+ it("true == true → true", () => expect(evalExpr({ eq: [{ value: true }, { value: true }] })).toBe(true));
+ it("true == false → false", () => expect(evalExpr({ eq: [{ value: true }, { value: false }] })).toBe(false));
+ });
+
+ describe("gt", () => {
+ it("1 > 0 → true", () => expect(evalExpr({ gt: [{ value: 1 }, { value: 0 }] })).toBe(true));
+ it("0 > 1 → false", () => expect(evalExpr({ gt: [{ value: 0 }, { value: 1 }] })).toBe(false));
+ it("0 > 0 → false", () => expect(evalExpr({ gt: [{ value: 0 }, { value: 0 }] })).toBe(false));
+ it("null > 0 → null", () => expect(evalExpr({ gt: [{ value: null }, { value: 0 }] })).toBe(null));
+ it("'b' > 'a' → true", () => expect(evalExpr({ gt: [{ value: "b" }, { value: "a" }] })).toBe(true));
+ });
+
+ describe("gte", () => {
+ it("1 >= 0 → true", () => expect(evalExpr({ gte: [{ value: 1 }, { value: 0 }] })).toBe(true));
+ it("0 >= 0 → true", () => expect(evalExpr({ gte: [{ value: 0 }, { value: 0 }] })).toBe(true));
+ it("0 >= 1 → false", () => expect(evalExpr({ gte: [{ value: 0 }, { value: 1 }] })).toBe(false));
+ });
+
+ describe("lt", () => {
+ it("0 < 1 → true", () => expect(evalExpr({ lt: [{ value: 0 }, { value: 1 }] })).toBe(true));
+ it("1 < 0 → false", () => expect(evalExpr({ lt: [{ value: 1 }, { value: 0 }] })).toBe(false));
+ it("0 < 0 → false", () => expect(evalExpr({ lt: [{ value: 0 }, { value: 0 }] })).toBe(false));
+ });
+
+ describe("lte", () => {
+ it("0 <= 1 → true", () => expect(evalExpr({ lte: [{ value: 0 }, { value: 1 }] })).toBe(true));
+ it("0 <= 0 → true", () => expect(evalExpr({ lte: [{ value: 0 }, { value: 0 }] })).toBe(true));
+ it("1 <= 0 → false", () => expect(evalExpr({ lte: [{ value: 1 }, { value: 0 }] })).toBe(false));
+ });
+
+ // NOTE: Branch InOperator signature is (haystack, needle) — first arg is the collection
+ describe("in", () => {
+ it("string contains", () => {
+ expect(evalExpr({ in: [{ value: "abcdef" }, { value: "bc" }] })).toBe(true);
+ });
+ it("string not contains", () => {
+ expect(evalExpr({ in: [{ value: "abcdef" }, { value: "xyz" }] })).toBe(false);
+ });
+ it("array contains", () => {
+ expect(evalExpr({ in: [{ value: [1, 2, 3] }, { value: 2 }] })).toBe(true);
+ });
+ it("array not contains", () => {
+ expect(evalExpr({ in: [{ value: [1, 2, 3] }, { value: 4 }] })).toBe(false);
+ });
+ it("null haystack → null", () => {
+ expect(evalExpr({ in: [{ value: null }, { value: "a" }] })).toBe(null);
+ });
+ it("object key exists", () => {
+ expect(evalExpr({ in: [{ value: { a: 1, b: 2 } }, { value: "a" }] })).toBe(true);
+ });
+ it("object key missing", () => {
+ expect(evalExpr({ in: [{ value: { a: 1, b: 2 } }, { value: "c" }] })).toBe(false);
+ });
+ });
+
+ describe("match", () => {
+ it("matches regex", () => {
+ expect(evalExpr({ match: [{ value: "hello world" }, { value: "hello.*" }] })).toBe(true);
+ });
+ it("no match", () => {
+ expect(evalExpr({ match: [{ value: "hello" }, { value: "^world$" }] })).toBe(false);
+ });
+ it("null text → null", () => {
+ expect(evalExpr({ match: [{ value: null }, { value: "abc" }] })).toBe(null);
+ });
+ it("null pattern → null", () => {
+ expect(evalExpr({ match: [{ value: "hello" }, { value: null }] })).toBe(null);
+ });
+ it("invalid regex → null", () => {
+ expect(evalExpr({ match: [{ value: "hello" }, { value: "[invalid" }] })).toBe(null);
+ });
+ });
+
+ describe("complex expressions", () => {
+ it("nested and/or", () => {
+ const expr = {
+ and: [
+ { or: [{ value: true }, { value: false }] },
+ { not: { value: false } },
+ ],
+ };
+ expect(evalExpr(expr)).toBe(true);
+ });
+
+ it("variable comparison", () => {
+ const expr = { gt: [{ var: "age" }, { value: 18 }] };
+ expect(evalExpr(expr, { age: 25 })).toBe(true);
+ expect(evalExpr(expr, { age: 15 })).toBe(false);
+ });
+
+ it("audience-like filter", () => {
+ const expr = {
+ and: [
+ { gte: [{ var: "age" }, { value: 18 }] },
+ { in: [{ value: ["US", "UK", "CA"] }, { var: "country" }] },
+ ],
+ };
+ expect(evalExpr(expr, { age: 25, country: "US" })).toBe(true);
+ expect(evalExpr(expr, { age: 25, country: "FR" })).toBe(false);
+ expect(evalExpr(expr, { age: 15, country: "US" })).toBe(false);
+ });
+ });
+});
diff --git a/src/__tests__/provider.test.js b/src/__tests__/provider.test.js
deleted file mode 100644
index ed15180..0000000
--- a/src/__tests__/provider.test.js
+++ /dev/null
@@ -1,51 +0,0 @@
-import Client from "../client";
-import SDK from "../sdk";
-import { ContextDataProvider } from "../provider";
-
-jest.mock("../client");
-jest.mock("../sdk");
-
-describe("ContextDataProvider", () => {
- const client = new Client();
- const sdk = new SDK();
-
- sdk.getClient.mockReturnValue(client);
-
- describe("getContextData()", () => {
- it("should call client getContext", async () => {
- const provider = new ContextDataProvider();
-
- const data = {};
- client.getContext.mockReturnValue(Promise.resolve(data));
-
- const result = provider.getContextData(sdk);
-
- expect(result).toBeInstanceOf(Promise);
- expect(client.getContext).toHaveBeenCalledTimes(1);
- expect(client.getContext).toHaveBeenCalledWith(undefined);
-
- result.then((resp) => {
- expect(resp).toBe(data);
- });
- });
-
- it("should pass through options", async () => {
- const provider = new ContextDataProvider();
-
- const data = {};
- client.getContext.mockReturnValue(Promise.resolve(data));
-
- const result = provider.getContextData(sdk, { timeout: 1234 });
-
- expect(result).toBeInstanceOf(Promise);
- expect(client.getContext).toHaveBeenCalledTimes(1);
- expect(client.getContext).toHaveBeenCalledWith({
- timeout: 1234,
- });
-
- result.then((resp) => {
- expect(resp).toBe(data);
- });
- });
- });
-});
diff --git a/src/__tests__/provider.test.ts b/src/__tests__/provider.test.ts
new file mode 100644
index 0000000..26d5db5
--- /dev/null
+++ b/src/__tests__/provider.test.ts
@@ -0,0 +1,15 @@
+import { describe, expect, test, vi } from "vitest";
+import { DefaultContextDataProvider } from "../provider";
+
+describe("DefaultContextDataProvider", () => {
+ test("delegates to sdk.getClient().getContext()", async () => {
+ const mockGetContext = vi.fn().mockResolvedValue({ experiments: [] });
+ const mockSdk = { getClient: () => ({ getContext: mockGetContext }) };
+
+ const provider = new DefaultContextDataProvider();
+ const result = await provider.getContextData(mockSdk, { path: "/test" });
+
+ expect(mockGetContext).toHaveBeenCalledWith({ path: "/test" });
+ expect(result).toEqual({ experiments: [] });
+ });
+});
diff --git a/src/__tests__/publisher.test.js b/src/__tests__/publisher.test.js
deleted file mode 100644
index 4d59dbe..0000000
--- a/src/__tests__/publisher.test.js
+++ /dev/null
@@ -1,56 +0,0 @@
-import Client from "../client";
-import SDK from "../sdk";
-import Context from "../context";
-import { ContextPublisher } from "../publisher";
-
-jest.mock("../client");
-jest.mock("../sdk");
-jest.mock("../context");
-
-describe("ContextPublisher", () => {
- const client = new Client();
- const sdk = new SDK();
- const context = new Context();
-
- sdk.getClient.mockReturnValue(client);
-
- describe("publish()", () => {
- it("should call client publish", async () => {
- const publisher = new ContextPublisher();
-
- const data = { ok: true };
- client.publish.mockReturnValue(Promise.resolve(data));
-
- const request = { test: 1 };
- const result = publisher.publish(request, sdk, context);
-
- expect(result).toBeInstanceOf(Promise);
- expect(client.publish).toHaveBeenCalledTimes(1);
- expect(client.publish).toHaveBeenCalledWith(request, undefined);
-
- result.then((resp) => {
- expect(resp).toBe(data);
- });
- });
-
- it("should pass through options", async () => {
- const publisher = new ContextPublisher();
-
- const data = { ok: true };
- client.publish.mockReturnValue(Promise.resolve(data));
-
- const request = { test: 1 };
- const result = publisher.publish(request, sdk, context, { timeout: 1234 });
-
- expect(result).toBeInstanceOf(Promise);
- expect(client.publish).toHaveBeenCalledTimes(1);
- expect(client.publish).toHaveBeenCalledWith(request, {
- timeout: 1234,
- });
-
- result.then((resp) => {
- expect(resp).toBe(data);
- });
- });
- });
-});
diff --git a/src/__tests__/publisher.test.ts b/src/__tests__/publisher.test.ts
new file mode 100644
index 0000000..d755958
--- /dev/null
+++ b/src/__tests__/publisher.test.ts
@@ -0,0 +1,20 @@
+import { describe, expect, test, vi } from "vitest";
+import { DefaultContextPublisher } from "../publisher";
+
+describe("DefaultContextPublisher", () => {
+ test("delegates to sdk.getClient().publish()", async () => {
+ const mockPublish = vi.fn().mockResolvedValue({});
+ const mockSdk = { getClient: () => ({ publish: mockPublish }) };
+ const request = {
+ units: [{ type: "session_id", uid: "abc" }],
+ publishedAt: 1000,
+ hashed: true,
+ sdkVersion: "2.0.0",
+ };
+
+ const publisher = new DefaultContextPublisher();
+ await publisher.publish(request, mockSdk, {}, { path: "/test" });
+
+ expect(mockPublish).toHaveBeenCalledWith(request, { path: "/test" });
+ });
+});
diff --git a/src/__tests__/sdk.test.js b/src/__tests__/sdk.test.js
deleted file mode 100644
index 3dc75de..0000000
--- a/src/__tests__/sdk.test.js
+++ /dev/null
@@ -1,479 +0,0 @@
-import Client from "../client";
-import SDK from "../sdk";
-import Context from "../context";
-import { ContextPublisher } from "../publisher";
-import { ContextDataProvider } from "../provider";
-
-jest.mock("../client");
-jest.mock("../context");
-jest.mock("../publisher");
-jest.mock("../provider");
-
-describe("SDK", () => {
- const contextParams = {
- units: {
- session_id: "ab",
- },
- };
-
- const testEventLogger = jest.fn();
- const testContextDataProvider = new ContextDataProvider();
- const testContextPublisher = new ContextPublisher();
-
- const sdkOptions = {
- agent: "javascript-sdk",
- apiKey: "apikey",
- application: "website",
- endpoint: "localhost:8080",
- environment: "test",
- eventLogger: testEventLogger,
- publisher: testContextPublisher,
- provider: testContextDataProvider,
- timeout: 1000,
- };
-
- describe("constructor()", () => {
- it("should try to create a client with no options", (done) => {
- const sdk = new SDK();
-
- expect(sdk).toBeInstanceOf(SDK);
- expect(sdk.getEventLogger()).toBe(SDK.defaultEventLogger);
- expect(Client).toHaveBeenCalledTimes(1);
- expect(Client).toHaveBeenCalledWith({
- agent: "absmartly-javascript-sdk",
- });
-
- expect(ContextDataProvider).toHaveBeenCalledTimes(1);
- expect(ContextDataProvider).toHaveBeenCalledWith();
-
- expect(ContextPublisher).toHaveBeenCalledTimes(1);
- expect(ContextPublisher).toHaveBeenCalledWith();
-
- expect(sdk.getClient()).toBeInstanceOf(Client);
- expect(sdk.getContextDataProvider()).toBeInstanceOf(ContextDataProvider);
- expect(sdk.getContextPublisher()).toBeInstanceOf(ContextPublisher);
-
- done();
- });
-
- it("should create a client with specified options", (done) => {
- const sdk = new SDK(sdkOptions);
-
- expect(sdk).toBeInstanceOf(SDK);
- expect(sdk.getEventLogger()).toBe(testEventLogger);
- expect(sdk.getContextDataProvider()).toBe(testContextDataProvider);
- expect(sdk.getContextPublisher()).toBe(testContextPublisher);
- expect(Client).toHaveBeenCalledTimes(1);
- expect(Client).toHaveBeenCalledWith({
- agent: "javascript-sdk",
- apiKey: "apikey",
- application: "website",
- endpoint: "localhost:8080",
- environment: "test",
- timeout: 1000,
- });
-
- expect(sdk.getClient()).toBeInstanceOf(Client);
- expect(sdk.getContextDataProvider()).toBe(testContextDataProvider);
- expect(sdk.getContextPublisher()).toBe(testContextPublisher);
-
- done();
- });
-
- it("should pass custom agent to client", (done) => {
- const customAgent = "my-custom-agent";
- const options = {
- ...sdkOptions,
- agent: customAgent,
- };
-
- const sdk = new SDK(options);
-
- expect(sdk).toBeInstanceOf(SDK);
- expect(Client).toHaveBeenCalledTimes(1);
- expect(Client).toHaveBeenCalledWith(
- expect.objectContaining({
- agent: customAgent,
- })
- );
-
- done();
- });
-
- it("should set default values for unspecified client options", (done) => {
- const options = {
- application: "application",
- apiKey: "apikey",
- endpoint: "localhost:8080",
- environment: "test",
- };
-
- const sdk = new SDK(options);
-
- expect(sdk).toBeInstanceOf(SDK);
- expect(sdk.getEventLogger()).toBe(SDK.defaultEventLogger);
- expect(Client).toHaveBeenCalledTimes(1);
- expect(Client).toHaveBeenCalledWith(
- Object.assign(
- {},
- {
- agent: "absmartly-javascript-sdk",
- },
- options
- )
- );
-
- done();
- });
- });
-
- describe("getContextData()", () => {
- it("should call client getContext and return data promise", (done) => {
- const sdk = new SDK(sdkOptions);
-
- const promise = Promise.resolve({});
- testContextDataProvider.getContextData.mockReturnValue(promise);
-
- const data = sdk.getContextData();
-
- expect(testContextDataProvider.getContextData).toHaveBeenCalledTimes(1);
- expect(testContextDataProvider.getContextData).toHaveBeenCalledWith(sdk, undefined);
- expect(data).toBe(promise);
-
- expect(Context).not.toHaveBeenCalled();
-
- done();
- });
- });
-
- describe("createContext()", () => {
- it("should create Context object with promise", (done) => {
- const sdk = new SDK(sdkOptions);
-
- const promise = Promise.resolve({});
- testContextDataProvider.getContextData.mockReturnValue(promise);
-
- const contextOptions = {
- publishDelay: 1000,
- refreshPeriod: 0,
- };
-
- const context = sdk.createContext(contextParams, contextOptions);
-
- expect(context).toBeInstanceOf(Context);
- expect(testContextDataProvider.getContextData).toHaveBeenCalledTimes(1);
- expect(testContextDataProvider.getContextData).toHaveBeenCalledWith(sdk, undefined);
-
- expect(Context).toHaveBeenCalledTimes(1);
- expect(Context).toHaveBeenCalledWith(sdk, contextOptions, contextParams, promise);
-
- done();
- });
-
- it("should pass through request options", (done) => {
- const sdk = new SDK(sdkOptions);
-
- const promise = Promise.resolve({});
- testContextDataProvider.getContextData.mockReturnValue(promise);
-
- const contextOptions = {
- publishDelay: 1000,
- refreshPeriod: 0,
- };
-
- const requestOptions = {
- timeout: 1234,
- };
-
- const context = sdk.createContext(contextParams, contextOptions, requestOptions);
-
- expect(context).toBeInstanceOf(Context);
- expect(testContextDataProvider.getContextData).toHaveBeenCalledTimes(1);
- expect(testContextDataProvider.getContextData).toHaveBeenCalledWith(sdk, requestOptions);
-
- expect(Context).toHaveBeenCalledTimes(1);
- expect(Context).toHaveBeenCalledWith(sdk, contextOptions, contextParams, promise);
-
- done();
- });
-
- it("should coerce unit uid to string", (done) => {
- const sdk = new SDK(sdkOptions);
-
- const promise = Promise.resolve({});
- testContextDataProvider.getContextData.mockReturnValue(promise);
-
- const contextOptions = {
- publishDelay: 1000,
- refreshPeriod: 0,
- };
-
- const params = {
- units: {
- session_id: "ab",
- user_id: 125,
- float_id: 125.75,
- },
- };
-
- const context = sdk.createContext(params, contextOptions);
-
- expect(context).toBeInstanceOf(Context);
- expect(testContextDataProvider.getContextData).toHaveBeenCalledTimes(1);
- expect(testContextDataProvider.getContextData).toHaveBeenCalledWith(sdk, undefined);
-
- expect(Context).toHaveBeenCalledTimes(1);
- expect(Context).toHaveBeenCalledWith(sdk, contextOptions, params, promise);
-
- done();
- });
-
- it("should throw on unsupported unit uid type", (done) => {
- const sdk = new SDK(sdkOptions);
-
- const promise = Promise.resolve({});
- testContextDataProvider.getContextData.mockReturnValue(promise);
-
- const contextOptions = {
- publishDelay: 1000,
- refreshPeriod: 0,
- eventLogger: testEventLogger,
- };
-
- const params = {
- units: {
- session_id: true,
- },
- };
-
- expect(() => sdk.createContext(params, contextOptions)).toThrow(
- new Error(
- "Unit 'session_id' UID is of unsupported type 'boolean'. UID must be one of ['string', 'number']"
- )
- );
- expect(testContextDataProvider.getContextData).not.toHaveBeenCalled();
- expect(Context).not.toHaveBeenCalled();
-
- done();
- });
-
- it("should throw on empty unit uid", (done) => {
- const sdk = new SDK(sdkOptions);
-
- const promise = Promise.resolve({});
- testContextDataProvider.getContextData.mockReturnValue(promise);
-
- const contextOptions = {
- publishDelay: 1000,
- refreshPeriod: 0,
- eventLogger: testEventLogger,
- };
-
- const params = {
- units: {
- session_id: "",
- },
- };
-
- expect(() => sdk.createContext(params, contextOptions)).toThrow(
- new Error("Unit 'session_id' UID length must be >= 1")
- );
- expect(testContextDataProvider.getContextData).not.toHaveBeenCalled();
- expect(Context).not.toHaveBeenCalled();
-
- done();
- });
-
- it("should initialize context with default options for nodejs", (done) => {
- const sdk = new SDK(sdkOptions);
-
- const promise = Promise.resolve({});
- testContextDataProvider.getContextData.mockReturnValue(promise);
-
- const context = sdk.createContext(contextParams);
-
- const defaultOptions = {
- publishDelay: -1,
- refreshPeriod: 0,
- };
-
- expect(context).toBeInstanceOf(Context);
- expect(testContextDataProvider.getContextData).toHaveBeenCalledTimes(1);
- expect(testContextDataProvider.getContextData).toHaveBeenCalledWith(sdk, undefined);
-
- expect(context).toBeInstanceOf(Context);
- expect(Context).toHaveBeenCalledTimes(1);
- expect(Context).toHaveBeenCalledWith(sdk, defaultOptions, contextParams, promise);
-
- done();
- });
-
- it("should initialize context with default options for browser", (done) => {
- const sdk = new SDK(sdkOptions);
-
- const promise = Promise.resolve({});
- testContextDataProvider.getContextData.mockReturnValue(promise);
-
- // fake browser environment
- const previousWindow = global.window;
- global.window = { document: {} };
-
- const context = sdk.createContext(contextParams);
-
- // restore environment
- global.window = previousWindow;
-
- const defaultOptions = {
- publishDelay: 100,
- refreshPeriod: 0,
- };
-
- expect(context).toBeInstanceOf(Context);
- expect(testContextDataProvider.getContextData).toHaveBeenCalledTimes(1);
- expect(testContextDataProvider.getContextData).toHaveBeenCalledWith(sdk, undefined);
-
- expect(context).toBeInstanceOf(Context);
- expect(Context).toHaveBeenCalledTimes(1);
- expect(Context).toHaveBeenCalledWith(sdk, defaultOptions, contextParams, promise);
-
- done();
- });
- });
-
- describe("createContextWith()", () => {
- it("should not call client getContext", (done) => {
- const data = {
- guid: "test",
- };
-
- const contextOptions = {
- publishDelay: 1000,
- refreshPeriod: 0,
- eventLogger: testEventLogger,
- };
-
- const sdk = new SDK(sdkOptions);
- const context = sdk.createContextWith(contextParams, data, contextOptions);
-
- expect(context).toBeInstanceOf(Context);
- expect(testContextDataProvider.getContextData).not.toHaveBeenCalled();
-
- expect(Context).toHaveBeenCalledTimes(1);
- expect(Context).toHaveBeenCalledWith(sdk, contextOptions, contextParams, data);
-
- done();
- });
-
- it("should throw on unsupported unit uid type", (done) => {
- const sdk = new SDK(sdkOptions);
-
- const contextOptions = {
- publishDelay: 1000,
- refreshPeriod: 0,
- eventLogger: testEventLogger,
- };
-
- const params = {
- units: {
- session_id: true,
- },
- };
-
- expect(() => sdk.createContextWith(params, contextOptions, {})).toThrow(
- new Error(
- "Unit 'session_id' UID is of unsupported type 'boolean'. UID must be one of ['string', 'number']"
- )
- );
- expect(testContextDataProvider.getContextData).not.toHaveBeenCalled();
- expect(Context).not.toHaveBeenCalled();
-
- done();
- });
-
- it("should initialize context with default options", (done) => {
- const data = {
- guid: "test",
- };
-
- const defaultOptions = {
- publishDelay: -1,
- refreshPeriod: 0,
- };
-
- const sdk = new SDK(sdkOptions);
- const context = sdk.createContextWith(contextParams, data);
-
- expect(context).toBeInstanceOf(Context);
- expect(Context).toHaveBeenCalledTimes(1);
- expect(Context).toHaveBeenCalledWith(sdk, defaultOptions, contextParams, data);
-
- done();
- });
- });
-
- describe("setEventLogger()", () => {
- it("should override the current logger", (done) => {
- const sdk = new SDK(sdkOptions);
- expect(sdk.getEventLogger()).toBe(testEventLogger);
-
- const newLogger = jest.fn();
- sdk.setEventLogger(newLogger);
- expect(sdk.getEventLogger()).toBe(newLogger);
-
- done();
- });
- });
-
- describe("setContextDataProvider()", () => {
- it("should override the current provider", (done) => {
- const sdk = new SDK(sdkOptions);
- expect(sdk.getContextDataProvider()).toBe(testContextDataProvider);
-
- const newProvider = new ContextDataProvider();
- sdk.setContextDataProvider(newProvider);
- expect(sdk.getContextDataProvider()).toBe(newProvider);
-
- done();
- });
- });
-
- describe("setContextPublisher()", () => {
- it("should override the current publisher", (done) => {
- const sdk = new SDK(sdkOptions);
- expect(sdk.getContextPublisher()).toBe(testContextPublisher);
-
- const newPublisher = new ContextPublisher();
- sdk.setContextPublisher(newPublisher);
- expect(sdk.getContextPublisher()).toBe(newPublisher);
-
- done();
- });
- });
-
- describe("defaultLogger", () => {
- it("should log only errors to console", (done) => {
- const errorSpy = jest.spyOn(console, "error").mockImplementation(() => {});
- jest.spyOn(console, "warn").mockImplementation(() => {});
- jest.spyOn(console, "info").mockImplementation(() => {});
- jest.spyOn(console, "log").mockImplementation(() => {});
-
- for (const eventName of ["error", "ready", "refresh", "publish", "goal", "exposure"]) {
- if (eventName === "error") {
- SDK.defaultEventLogger("context", eventName, "error text");
- expect(console.error).toHaveBeenCalledTimes(1);
- expect(console.error).toHaveBeenCalledWith("error text");
-
- errorSpy.mockClear();
- } else {
- SDK.defaultEventLogger("context", eventName, {});
- expect(console.error).not.toHaveBeenCalled();
- }
- expect(console.warn).not.toHaveBeenCalled();
- expect(console.info).not.toHaveBeenCalled();
- expect(console.log).not.toHaveBeenCalled();
- }
-
- done();
- });
- });
-});
diff --git a/src/__tests__/sdk.test.ts b/src/__tests__/sdk.test.ts
new file mode 100644
index 0000000..2ce308f
--- /dev/null
+++ b/src/__tests__/sdk.test.ts
@@ -0,0 +1,127 @@
+import { describe, expect, test, vi } from "vitest";
+import { SDK } from "../sdk";
+import type { ClientOptions } from "../interfaces";
+
+const defaultOpts: ClientOptions = {
+ agent: "test-agent",
+ apiKey: "test-api-key",
+ application: "test-app",
+ endpoint: "https://test.absmartly.io/v1",
+ environment: "test",
+};
+
+describe("SDK", () => {
+ test("creates SDK instance", () => {
+ const sdk = new SDK(defaultOpts);
+ expect(sdk).toBeInstanceOf(SDK);
+ });
+
+ test("getClient returns client", () => {
+ const sdk = new SDK(defaultOpts);
+ expect(sdk.getClient()).toBeDefined();
+ });
+
+ test("get/set event logger", () => {
+ const sdk = new SDK(defaultOpts);
+ const logger = vi.fn();
+ sdk.setEventLogger(logger);
+ expect(sdk.getEventLogger()).toBe(logger);
+ });
+
+ test("default event logger logs errors", () => {
+ const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => {});
+ const error = new Error("test");
+ SDK.defaultEventLogger({} as never, "error", error);
+ expect(consoleSpy).toHaveBeenCalledWith(error);
+ consoleSpy.mockRestore();
+ });
+
+ test("createContext validates unit types", () => {
+ const sdk = new SDK(defaultOpts);
+ expect(() => sdk.createContext({ units: { session_id: true as unknown as string } })).toThrow(
+ "Unit 'session_id' UID is of unsupported type 'boolean'. UID must be one of ['string', 'number']",
+ );
+ });
+
+ test("createContext validates empty string units", () => {
+ const sdk = new SDK(defaultOpts);
+ expect(() => sdk.createContext({ units: { session_id: "" } })).toThrow(
+ "Unit 'session_id' UID length must be >= 1",
+ );
+ });
+
+ test("createContext returns Context instance", () => {
+ vi.stubGlobal(
+ "fetch",
+ vi.fn().mockResolvedValue({ ok: true, json: () => Promise.resolve({ experiments: [] }) }),
+ );
+ const sdk = new SDK(defaultOpts);
+ const context = sdk.createContext({ units: { session_id: "abc" } });
+ expect(context).toBeDefined();
+ vi.restoreAllMocks();
+ });
+
+ test("createContextWith accepts pre-fetched data", () => {
+ const sdk = new SDK(defaultOpts);
+ const context = sdk.createContextWith({ units: { session_id: "abc" } }, { experiments: [] });
+ expect(context).toBeDefined();
+ expect(context.isReady()).toBe(true);
+ });
+
+ test("get/set context publisher", () => {
+ const sdk = new SDK(defaultOpts);
+ const publisher = { publish: vi.fn() };
+ sdk.setContextPublisher(publisher as never);
+ expect(sdk.getContextPublisher()).toBe(publisher);
+ });
+
+ test("get/set context data provider", () => {
+ const sdk = new SDK(defaultOpts);
+ const provider = { getContextData: vi.fn() };
+ sdk.setContextDataProvider(provider as never);
+ expect(sdk.getContextDataProvider()).toBe(provider);
+ });
+
+ test("accepts custom client via SDKOptions", () => {
+ const mockClient = {
+ getContext: vi.fn().mockResolvedValue({ experiments: [] }),
+ publish: vi.fn().mockResolvedValue("ok"),
+ getAgent: vi.fn().mockReturnValue("custom-agent"),
+ getApplication: vi.fn().mockReturnValue({ name: "custom-app", version: 0 }),
+ getEnvironment: vi.fn().mockReturnValue("custom-env"),
+ };
+ const sdk = new SDK({ ...defaultOpts, client: mockClient } as any);
+ expect(sdk.getClient()).toBe(mockClient);
+ });
+
+ test("event logger fires ready event on createContextWith", () => {
+ const logger = vi.fn();
+ const sdk = new SDK({ ...defaultOpts, eventLogger: logger });
+ const context = sdk.createContextWith({ units: { session_id: "abc" } }, { experiments: [] });
+ expect(logger).toHaveBeenCalledWith(context, "ready", expect.anything());
+ });
+
+ test("forwards fetchImpl and AbortControllerImpl to Client", async () => {
+ const fetchImpl = vi.fn().mockResolvedValue({ ok: true, json: () => Promise.resolve({ experiments: [] }) });
+ let abortControllerInstances = 0;
+ class FakeAbortController {
+ signal = { addEventListener: vi.fn(), removeEventListener: vi.fn() } as unknown as AbortSignal;
+ constructor() {
+ abortControllerInstances += 1;
+ }
+ abort = vi.fn();
+ }
+
+ const sdk = new SDK({
+ ...defaultOpts,
+ fetchImpl,
+ AbortControllerImpl: FakeAbortController as unknown as typeof AbortController,
+ });
+ const context = sdk.createContext({ units: { session_id: "abc" } });
+ await context.ready();
+
+ expect(fetchImpl).toHaveBeenCalledTimes(1);
+ expect(abortControllerInstances).toBe(1);
+ });
+});
+
diff --git a/src/__tests__/utils.test.js b/src/__tests__/utils.test.js
deleted file mode 100644
index 39cf8d4..0000000
--- a/src/__tests__/utils.test.js
+++ /dev/null
@@ -1,343 +0,0 @@
-import {
- arrayEqualsShallow,
- base64UrlNoPadding,
- chooseVariant,
- hashUnit,
- isEqualsDeep,
- isNumeric,
- isObject,
- isPromise,
- stringToUint8Array,
-} from "../utils";
-
-class SomeClass {}
-
-describe("isObject()", () => {
- it("should return true with objects", (done) => {
- expect(isObject({})).toBe(true);
- expect(isObject(new Object())).toBe(true);
-
- done();
- });
-
- it("should return false with common non-object", (done) => {
- expect(isObject(null)).toBe(false);
- expect(isObject([])).toBe(false);
- expect(isObject(1)).toBe(false);
- expect(isObject(true)).toBe(false);
- expect(isObject(false)).toBe(false);
- expect(isObject("str")).toBe(false);
- expect(isObject(new Uint8Array(1))).toBe(false);
- expect(isObject(new Map())).toBe(false);
- expect(isObject(new SomeClass())).toBe(false);
-
- done();
- });
-});
-
-describe("isNumeric()", () => {
- it("should return true with numbers", (done) => {
- expect(isNumeric(1)).toBe(true);
- expect(isNumeric(1.5)).toBe(true);
-
- done();
- });
-
- it("should return false with non-numbers", (done) => {
- expect(isNumeric(null)).toBe(false);
- expect(isNumeric("1")).toBe(false);
- expect(isNumeric(true)).toBe(false);
- expect(isNumeric(false)).toBe(false);
- expect(isNumeric([])).toBe(false);
- expect(isNumeric({})).toBe(false);
- expect(isNumeric(new Object())).toBe(false);
- expect(isNumeric(new Map())).toBe(false);
-
- done();
- });
-});
-
-describe("isPromise()", () => {
- it("should return true with a thenable object", (done) => {
- expect(
- isPromise({
- then() {},
- })
- ).toBe(true);
-
- done();
- });
-
- it("should return false with non objects or objects without then function", (done) => {
- expect(isPromise(null)).toBe(false);
- expect(isPromise([])).toBe(false);
- expect(isPromise({})).toBe(false);
- expect(isPromise(1)).toBe(false);
- expect(isPromise(true)).toBe(false);
- expect(isPromise(false)).toBe(false);
- expect(isPromise("str")).toBe(false);
- expect(isPromise(new Uint8Array(1))).toBe(false);
-
- done();
- });
-});
-
-describe("isEqualsDeep()", () => {
- it("should return true with two NaNs", (done) => {
- expect(isEqualsDeep(Number.NaN, Number.NaN)).toBe(true);
-
- done();
- });
-
- it("should return true iff basic primitives are equal", (done) => {
- expect(isEqualsDeep(0, 0)).toBe(true);
- expect(isEqualsDeep(1, 1)).toBe(true);
- expect(isEqualsDeep(1.5, 1.5)).toBe(true);
- expect(isEqualsDeep("", "")).toBe(true);
- expect(isEqualsDeep("abc", "abc")).toBe(true);
- expect(isEqualsDeep(true, true)).toBe(true);
- expect(isEqualsDeep(false, false)).toBe(true);
-
- expect(isEqualsDeep(0, 1)).toBe(false);
- expect(isEqualsDeep(1, 1.5)).toBe(false);
- expect(isEqualsDeep(1.5, "")).toBe(false);
- expect(isEqualsDeep("", "abc")).toBe(false);
- expect(isEqualsDeep("abc", true)).toBe(false);
- expect(isEqualsDeep(true, false)).toBe(false);
- expect(isEqualsDeep(false, 0)).toBe(false);
-
- done();
- });
-
- it("should return true iff arrays are equal", (done) => {
- expect(isEqualsDeep([1, 2, 3], [1, 2, 3])).toBe(true);
- expect(isEqualsDeep([1, 2, 3], [3, 2, 1])).toBe(false);
-
- expect(isEqualsDeep([], [1])).toBe(false);
- expect(isEqualsDeep([1], [])).toBe(false);
-
- expect(isEqualsDeep([1, 2, [3, 4, [5, 6]]], [1, 2, [3, 4, [5, 6]]])).toBe(true);
- expect(isEqualsDeep([1, 2, [3, 4, [5, 6]]], [1, 2, [3, 4, [5, 9]]])).toBe(false);
-
- expect(isEqualsDeep(["a", "b", ["c", "d", ["e", "f"]]], ["a", "b", ["c", "d", ["e", "f"]]])).toBe(true);
- expect(isEqualsDeep(["a", "b", ["c", "d", ["e", "f"]]], ["a", "b", ["c", "d", ["e", "x"]]])).toBe(false);
-
- done();
- });
-
- it("should return true iff arrays with circular references are equal", (done) => {
- const a = [1, 2, [3, 4, [5, 6]]];
- a[1] = a;
-
- const b = [1, 2, [3, 4, [5, 6]]];
- b[1] = b;
-
- expect(isEqualsDeep(a, b)).toBe(true);
-
- a[2][2][0] = a;
- b[2][2][0] = b;
-
- expect(isEqualsDeep(a, b)).toBe(true);
-
- b[2][2][1] = 9;
-
- expect(isEqualsDeep(a, b)).toBe(false);
-
- done();
- });
-
- it("should return true iff objects are equal", (done) => {
- expect(isEqualsDeep({ a: 1, b: 2, c: 3 }, { a: 1, b: 2, c: 3 })).toBe(true);
- expect(isEqualsDeep({ a: 1, b: 2, c: 3 }, { c: 3, b: 2, a: 1 })).toBe(true);
- expect(isEqualsDeep({ a: 1, b: 2, c: 3 }, { a: 3, b: 2, c: 1 })).toBe(false);
-
- expect(isEqualsDeep({}, { a: 1 })).toBe(false);
- expect(isEqualsDeep({ a: 1 }, {})).toBe(false);
-
- expect(
- isEqualsDeep(
- { a: 1, b: 2, c: { d: 3, e: 4, f: { g: 5, h: 6 } } },
- { a: 1, b: 2, c: { d: 3, e: 4, f: { g: 5, h: 6 } } }
- )
- ).toBe(true);
- expect(
- isEqualsDeep(
- { a: 1, b: 2, c: { d: 3, e: 4, f: { g: 5, h: 6 } } },
- { a: 1, b: 2, c: { d: 3, e: 4, f: { g: 5, h: 9 } } }
- )
- ).toBe(false);
-
- expect(
- isEqualsDeep(
- { a: "a", b: "b", c: { d: "c", e: "d", f: { g: "e", h: "f" } } },
- { a: "a", b: "b", c: { d: "c", e: "d", f: { g: "e", h: "f" } } }
- )
- ).toBe(true);
- expect(
- isEqualsDeep(
- { a: "a", b: "b", c: { d: "c", e: "d", f: { g: "e", h: "f" } } },
- { a: "a", b: "b", c: { d: "c", e: "d", f: { g: "e", h: "x" } } }
- )
- ).toBe(false);
-
- done();
- });
-
- it("should return true iff arrays with circular references are equal", (done) => {
- const a = { a: 1, b: 2, c: { d: 3, e: 4, f: { g: 5, h: 6 } } };
- a.b = a;
-
- const b = { a: 1, b: 2, c: { d: 3, e: 4, f: { g: 5, h: 6 } } };
- b.b = b;
-
- expect(isEqualsDeep(a, b)).toBe(true);
-
- a.c.f.g = a;
- b.c.f.g = b;
-
- expect(isEqualsDeep(a, b)).toBe(true);
-
- b.c.f.h = 9;
-
- expect(isEqualsDeep(a, b)).toBe(false);
-
- done();
- });
-});
-
-describe("arrayEqualsShallow()", () => {
- it("should return true only with equal arrays", (done) => {
- expect(arrayEqualsShallow([], [])).toEqual(true);
- expect(arrayEqualsShallow([1], [1])).toEqual(true);
- expect(arrayEqualsShallow([1, 2, 3], [1, 2, 3])).toEqual(true);
- expect(arrayEqualsShallow([0.5, 1.0, 1.5], [0.5, 1.0, 1.5])).toEqual(true);
-
- expect(arrayEqualsShallow([1], ["1"])).toEqual(false);
- expect(arrayEqualsShallow([1, 2, 3], [1, 2, "3"])).toEqual(false);
- expect(arrayEqualsShallow([1], [])).toEqual(false);
- expect(arrayEqualsShallow([], [1])).toEqual(false);
- expect(arrayEqualsShallow([1, 2, 3], [1, 2])).toEqual(false);
- expect(arrayEqualsShallow([1, 2], [1, 2, 3])).toEqual(false);
-
- done();
- });
-});
-
-describe("hashUnit()", () => {
- it("should return matching hashes", (done) => {
- expect(hashUnit("4a42766ca6313d26f49985e799ff4f3790fb86efa0fce46edb3ea8fbf1ea3408")).toBe(
- "H2jvj6o9YcAgNdhKqEbtWw"
- );
- expect(hashUnit("bleh@absmarty.com")).toBe("DRgslOje35bZMmpaohQjkA");
- expect(hashUnit("açb↓c")).toBe("LxcqH5VC15rXfWfA_smreg");
- expect(hashUnit("testy")).toBe("K5I_V6RgP8c6sYKz-TVn8g");
- expect(hashUnit(123456778999)).toBe("K4uy4bTeCy34W97lmceVRg");
-
- done();
- });
-});
-
-describe("chooseVariant()", () => {
- it("should return correct variant", (done) => {
- expect(chooseVariant([0.0, 1.0], 0.0)).toBe(1);
- expect(chooseVariant([0.0, 1.0], 0.5)).toBe(1);
- expect(chooseVariant([0.0, 1.0], 1.0)).toBe(1);
-
- expect(chooseVariant([1.0, 0.0], 0.0)).toBe(0);
- expect(chooseVariant([1.0, 0.0], 0.5)).toBe(0);
- expect(chooseVariant([1.0, 0.0], 1.0)).toBe(1);
-
- expect(chooseVariant([0.5, 0.5], 0.0)).toBe(0);
- expect(chooseVariant([0.5, 0.5], 0.25)).toBe(0);
- expect(chooseVariant([0.5, 0.5], 0.49999999)).toBe(0);
- expect(chooseVariant([0.5, 0.5], 0.5)).toBe(1);
- expect(chooseVariant([0.5, 0.5], 0.50000001)).toBe(1);
- expect(chooseVariant([0.5, 0.5], 0.75)).toBe(1);
- expect(chooseVariant([0.5, 0.5], 1.0)).toBe(1);
-
- expect(chooseVariant([0.333, 0.333, 0.334], 0.0)).toBe(0);
- expect(chooseVariant([0.333, 0.333, 0.334], 0.25)).toBe(0);
- expect(chooseVariant([0.333, 0.333, 0.334], 0.33299999)).toBe(0);
- expect(chooseVariant([0.333, 0.333, 0.334], 0.333)).toBe(1);
- expect(chooseVariant([0.333, 0.333, 0.334], 0.33300001)).toBe(1);
- expect(chooseVariant([0.333, 0.333, 0.334], 0.5)).toBe(1);
- expect(chooseVariant([0.333, 0.333, 0.334], 0.66599999)).toBe(1);
- expect(chooseVariant([0.333, 0.333, 0.334], 0.666)).toBe(2);
- expect(chooseVariant([0.333, 0.333, 0.334], 0.66600001)).toBe(2);
- expect(chooseVariant([0.333, 0.333, 0.334], 0.75)).toBe(2);
- expect(chooseVariant([0.333, 0.333, 0.334], 1.0)).toBe(2);
-
- done();
- });
-});
-
-describe("stringToUint8Array()", () => {
- it("should encode special characters to utf8", (done) => {
- const testCases = [
- ["", Uint8Array.from([])],
- [" ", Uint8Array.from([32])],
- ["a", Uint8Array.from([97])],
- ["ab", Uint8Array.from([97, 98])],
- ["abc", Uint8Array.from([97, 98, 99])],
- ["abcd", Uint8Array.from([97, 98, 99, 100])],
- ["ç", Uint8Array.from([195, 167])],
- ["aç", Uint8Array.from([97, 195, 167])],
- ["çb", Uint8Array.from([195, 167, 98])],
- ["açb", Uint8Array.from([97, 195, 167, 98])],
- ["↓", Uint8Array.from([226, 134, 147])],
- ["a↓", Uint8Array.from([97, 226, 134, 147])],
- ["↓b", Uint8Array.from([226, 134, 147, 98])],
- ["a↓b", Uint8Array.from([97, 226, 134, 147, 98])],
- ["aç↓", Uint8Array.from([97, 195, 167, 226, 134, 147])],
- ["aç↓b", Uint8Array.from([97, 195, 167, 226, 134, 147, 98])],
- ["açb↓c", Uint8Array.from([97, 195, 167, 98, 226, 134, 147, 99])],
- ];
-
- for (const testCase of testCases) {
- const array = stringToUint8Array(testCase[0]);
- const expected = testCase[1];
- expect(array.length).toBe(expected.length);
- for (let i = 0; i < array.length; ++i) {
- expect(array[i]).toBe(expected[i]);
- }
- }
- done();
- });
-});
-
-describe("base64UrlNoPadding()", () => {
- it("should match known encodings", (done) => {
- const testCases = [
- ["", ""],
- [" ", "IA"],
- ["t", "dA"],
- ["te", "dGU"],
- ["tes", "dGVz"],
- ["test", "dGVzdA"],
- ["testy", "dGVzdHk"],
- ["testy1", "dGVzdHkx"],
- ["testy12", "dGVzdHkxMg"],
- ["testy123", "dGVzdHkxMjM"],
- ["special characters açb↓c", "c3BlY2lhbCBjaGFyYWN0ZXJzIGHDp2LihpNj"],
- [
- "The quick brown fox jumps over the lazy dog",
- "VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZw",
- ],
- [
- "The quick brown fox jumps over the lazy dog and eats a pie",
- "VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZyBhbmQgZWF0cyBhIHBpZQ",
- ],
- [
- "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
- "TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdCwgc2VkIGRvIGVpdXNtb2QgdGVtcG9yIGluY2lkaWR1bnQgdXQgbGFib3JlIGV0IGRvbG9yZSBtYWduYSBhbGlxdWEuIFV0IGVuaW0gYWQgbWluaW0gdmVuaWFtLCBxdWlzIG5vc3RydWQgZXhlcmNpdGF0aW9uIHVsbGFtY28gbGFib3JpcyBuaXNpIHV0IGFsaXF1aXAgZXggZWEgY29tbW9kbyBjb25zZXF1YXQuIER1aXMgYXV0ZSBpcnVyZSBkb2xvciBpbiByZXByZWhlbmRlcml0IGluIHZvbHVwdGF0ZSB2ZWxpdCBlc3NlIGNpbGx1bSBkb2xvcmUgZXUgZnVnaWF0IG51bGxhIHBhcmlhdHVyLiBFeGNlcHRldXIgc2ludCBvY2NhZWNhdCBjdXBpZGF0YXQgbm9uIHByb2lkZW50LCBzdW50IGluIGN1bHBhIHF1aSBvZmZpY2lhIGRlc2VydW50IG1vbGxpdCBhbmltIGlkIGVzdCBsYWJvcnVtLg",
- ],
- ];
-
- testCases.forEach((testCase) => {
- const bytes = stringToUint8Array(testCase[0]);
- expect(base64UrlNoPadding(bytes)).toEqual(testCase[1]);
- });
-
- done();
- });
-});
diff --git a/src/__tests__/utils.test.ts b/src/__tests__/utils.test.ts
new file mode 100644
index 0000000..5af8c4f
--- /dev/null
+++ b/src/__tests__/utils.test.ts
@@ -0,0 +1,129 @@
+import { describe, expect, test } from "vitest";
+import { arrayEqualsShallow, chooseVariant, isEqualsDeep, isObject, isPromise } from "../utils";
+
+describe("isObject", () => {
+ test("returns true for plain objects", () => {
+ expect(isObject({})).toBe(true);
+ expect(isObject({ a: 1 })).toBe(true);
+ });
+
+ test("returns false for non-objects", () => {
+ expect(isObject(null)).toBe(false);
+ expect(isObject(undefined)).toBe(false);
+ expect(isObject(42)).toBe(false);
+ expect(isObject("str")).toBe(false);
+ expect(isObject([])).toBe(false);
+ expect(isObject(new Date())).toBe(false);
+ });
+});
+
+describe("isPromise", () => {
+ test("returns true for promises", () => {
+ expect(isPromise(Promise.resolve())).toBe(true);
+ expect(isPromise({ then: () => {} })).toBe(true);
+ });
+
+ test("returns false for non-promises", () => {
+ expect(isPromise(null)).toBe(false);
+ expect(isPromise(undefined)).toBe(false);
+ expect(isPromise({})).toBe(false);
+ expect(isPromise(42)).toBe(false);
+ });
+});
+
+describe("isEqualsDeep", () => {
+ test("primitives", () => {
+ expect(isEqualsDeep(1, 1)).toBe(true);
+ expect(isEqualsDeep(1, 2)).toBe(false);
+ expect(isEqualsDeep("a", "a")).toBe(true);
+ expect(isEqualsDeep("a", "b")).toBe(false);
+ expect(isEqualsDeep(true, true)).toBe(true);
+ expect(isEqualsDeep(true, false)).toBe(false);
+ });
+
+ test("NaN", () => {
+ expect(isEqualsDeep(NaN, NaN)).toBe(true);
+ });
+
+ test("arrays", () => {
+ expect(isEqualsDeep([1, 2, 3], [1, 2, 3])).toBe(true);
+ expect(isEqualsDeep([1, 2, 3], [1, 2, 4])).toBe(false);
+ expect(isEqualsDeep([1, 2], [1, 2, 3])).toBe(false);
+ });
+
+ test("objects", () => {
+ expect(isEqualsDeep({ a: 1, b: 2 }, { a: 1, b: 2 })).toBe(true);
+ expect(isEqualsDeep({ a: 1 }, { a: 2 })).toBe(false);
+ expect(isEqualsDeep({ a: 1 }, { a: 1, b: 2 })).toBe(false);
+ });
+
+ test("nested structures", () => {
+ expect(isEqualsDeep({ a: [1, { b: 2 }] }, { a: [1, { b: 2 }] })).toBe(true);
+ expect(isEqualsDeep({ a: [1, { b: 2 }] }, { a: [1, { b: 3 }] })).toBe(false);
+ });
+
+ test("different types", () => {
+ expect(isEqualsDeep(1, "1")).toBe(false);
+ expect(isEqualsDeep([], {})).toBe(false);
+ });
+});
+
+describe("arrayEqualsShallow", () => {
+ test("same reference", () => {
+ const arr = [1, 2, 3];
+ expect(arrayEqualsShallow(arr, arr)).toBe(true);
+ });
+
+ test("equal arrays", () => {
+ expect(arrayEqualsShallow([1, 2, 3], [1, 2, 3])).toBe(true);
+ });
+
+ test("different arrays", () => {
+ expect(arrayEqualsShallow([1, 2, 3], [1, 2, 4])).toBe(false);
+ });
+
+ test("different lengths", () => {
+ expect(arrayEqualsShallow([1, 2], [1, 2, 3])).toBe(false);
+ });
+
+ test("both undefined", () => {
+ expect(arrayEqualsShallow(undefined, undefined)).toBe(true);
+ });
+
+ test("both null", () => {
+ expect(arrayEqualsShallow(null, null)).toBe(true);
+ });
+
+ test("array vs null returns false", () => {
+ expect(arrayEqualsShallow([1], null)).toBe(false);
+ });
+
+ test("null vs array returns false", () => {
+ expect(arrayEqualsShallow(null, [1])).toBe(false);
+ });
+});
+
+describe("chooseVariant", () => {
+ test("selects correct variant based on probability", () => {
+ expect(chooseVariant([0.5, 0.5], 0.0)).toBe(0);
+ expect(chooseVariant([0.5, 0.5], 0.4)).toBe(0);
+ expect(chooseVariant([0.5, 0.5], 0.5)).toBe(1);
+ expect(chooseVariant([0.5, 0.5], 0.9)).toBe(1);
+ });
+
+ test("three-way split", () => {
+ expect(chooseVariant([0.33, 0.33, 0.34], 0.0)).toBe(0);
+ expect(chooseVariant([0.33, 0.33, 0.34], 0.3)).toBe(0);
+ expect(chooseVariant([0.33, 0.33, 0.34], 0.33)).toBe(1);
+ expect(chooseVariant([0.33, 0.33, 0.34], 0.65)).toBe(1);
+ expect(chooseVariant([0.33, 0.33, 0.34], 0.66)).toBe(2);
+ });
+
+ test("returns last variant for probability >= 1", () => {
+ expect(chooseVariant([0.5, 0.5], 1.0)).toBe(1);
+ });
+
+ test("zero-weight first variant [0.0, 1.0] with prob=0.0 returns 1", () => {
+ expect(chooseVariant([0.0, 1.0], 0.0)).toBe(1);
+ });
+});
diff --git a/src/abort-controller-shim.ts b/src/abort-controller-shim.ts
deleted file mode 100644
index 1456e47..0000000
--- a/src/abort-controller-shim.ts
+++ /dev/null
@@ -1,90 +0,0 @@
-export type AbortControllerEvents = {
- [key: string]: Array<() => unknown>;
-};
-
-// eslint-disable-next-line no-shadow
-export class AbortSignal {
- aborted = false;
- private readonly _events: AbortControllerEvents;
-
- constructor() {
- this._events = {};
- }
-
- addEventListener(type: string, listener: () => void) {
- let listeners = this._events[type];
- if (!listeners) {
- listeners = [];
- this._events[type] = listeners;
- }
- listeners.push(listener);
- }
-
- removeEventListener(type: string, listener: () => void) {
- const listeners = this._events[type];
- if (listeners) {
- const index = listeners.findIndex((x) => x === listener);
- if (index !== -1) {
- listeners.splice(index, 1);
- if (listeners.length === 0) {
- delete this._events[type];
- }
- }
- }
- }
-
- dispatchEvent(evt: { type: string }) {
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
- // @ts-ignore
- this[`on${evt.type}`] && this[`on${evt.type}`](evt);
- const listeners = this._events[evt.type];
- if (listeners) {
- for (const listener of listeners) {
- listener.call(null, evt);
- }
- }
- }
-
- toString() {
- return "[object AbortSignal]";
- }
-}
-
-// eslint-disable-next-line no-shadow
-export class AbortController {
- signal = new AbortSignal();
-
- abort() {
- let evt: Event | { type: string; bubbles: boolean; cancelable: boolean };
- try {
- evt = new Event("abort");
- } catch (e) {
- evt = {
- type: "abort",
- bubbles: false,
- cancelable: false,
- };
- }
-
- this.signal.aborted = true;
- this.signal.dispatchEvent(evt);
- }
-
- toString() {
- return "[object AbortController]";
- }
-}
-
-if (typeof Symbol !== "undefined" && Symbol.toStringTag !== undefined) {
- Object.defineProperty(AbortSignal.prototype, Symbol.toStringTag, {
- configurable: true,
- value: "AbortSignal",
- });
-
- Object.defineProperty(AbortController.prototype, Symbol.toStringTag, {
- configurable: true,
- value: "AbortController",
- });
-}
-
-export default AbortController;
diff --git a/src/abort.ts b/src/abort.ts
deleted file mode 100644
index 563ff75..0000000
--- a/src/abort.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import { isLongLivedApp, isWorker } from "./utils";
-import AbortControllerShim from "./abort-controller-shim";
-
-// eslint-disable-next-line no-shadow
-export const AbortController =
- isLongLivedApp() && window.AbortController
- ? window.AbortController
- : isWorker() && self.AbortController
- ? self.AbortController
- : global && global.AbortController
- ? global.AbortController
- : AbortControllerShim;
diff --git a/src/algorithm.ts b/src/algorithm.ts
index d4c4857..bfb83fb 100644
--- a/src/algorithm.ts
+++ b/src/algorithm.ts
@@ -1,13 +1,16 @@
-export const insertUniqueSorted = (arr: TData[], value: TData, isSorted: (a: TData, b: TData) => boolean) => {
+export function insertUniqueSorted(
+ arr: TData[],
+ value: TData,
+ isSorted: (a: TData, b: TData) => boolean,
+): void {
let left = 0;
let right = arr.length - 1;
while (left <= right) {
const mid = Math.floor(left + (right - left) / 2);
-
- if (isSorted(arr[mid], value)) {
+ if (isSorted(arr[mid]!, value)) {
left = mid + 1;
- } else if (isSorted(value, arr[mid])) {
+ } else if (isSorted(value, arr[mid]!)) {
right = mid - 1;
} else {
return;
@@ -15,4 +18,4 @@ export const insertUniqueSorted = (arr: TData[], value: TData, isSorted:
}
arr.splice(left, 0, value);
-};
+}
diff --git a/src/assigner.ts b/src/assigner.ts
index e744af0..f1b8ec0 100644
--- a/src/assigner.ts
+++ b/src/assigner.ts
@@ -1,25 +1,26 @@
-import { chooseVariant, stringToUint8Array } from "./utils";
-import { murmur3_32 } from "./murmur3_32";
+import { chooseVariant } from "./utils";
+import { stringToUint8Array } from "./hashing";
+import { murmur3_32 } from "./murmur3";
export class VariantAssigner {
private readonly _unitHash: number;
+
constructor(unit: string) {
this._unitHash = murmur3_32(stringToUint8Array(unit).buffer);
}
- assign(split: number[], seedHi: number, seedLo: number) {
+ assign(split: number[], seedHi: number, seedLo: number): number {
const prob = this._probability(seedHi, seedLo);
return chooseVariant(split, prob);
}
- private _probability(seedHi: number, seedLo: number) {
+ private _probability(seedHi: number, seedLo: number): number {
const key = this._unitHash;
const buffer = new ArrayBuffer(12);
const view = new DataView(buffer);
view.setUint32(0, seedLo, true);
view.setUint32(4, seedHi, true);
view.setUint32(8, key, true);
-
return murmur3_32(buffer) * (1.0 / 0xffffffff);
}
}
diff --git a/src/browser.ts b/src/browser.ts
deleted file mode 100644
index c3399d1..0000000
--- a/src/browser.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import Context from "./context";
-import SDK from "./sdk";
-import { mergeConfig } from "./config";
-import { ContextDataProvider } from "./provider";
-import { ContextPublisher } from "./publisher";
-// eslint-disable-next-line no-shadow
-import { AbortController } from "./abort";
-
-export default { mergeConfig, AbortController, Context, ContextDataProvider, ContextPublisher, SDK };
diff --git a/src/client.ts b/src/client.ts
index 3f934bb..c01d45e 100644
--- a/src/client.ts
+++ b/src/client.ts
@@ -1,61 +1,22 @@
-import fetch from "./fetch"; // eslint-disable-line no-shadow
-// eslint-disable-next-line no-shadow
-import { AbortController } from "./abort";
-// eslint-disable-next-line no-shadow
import { AbortError, RetryError, TimeoutError } from "./errors";
-
-import { AbortSignal as ABsmartlyAbortSignal } from "./abort-controller-shim";
-import { ContextOptions, ContextParams } from "./context";
-import { PublishParams } from "./publisher";
-
-export type FetchResponse = {
- status: number;
- ok: boolean;
- text: () => Promise;
- statusText: string;
- json: () => Promise;
-};
-
-export type ClientRequestOptions = {
- query?: Record;
- path: string;
- method?: "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "HEAD" | "OPTIONS";
- body?: Record;
- auth?: boolean;
- signal?: AbortSignal | ABsmartlyAbortSignal;
- timeout?: number;
-};
-
-export type ApplicationObject = { name: string; version: number | string };
-
-export type ClientOptions = {
- agent?: string;
- apiKey: string;
- application: string | ApplicationObject;
- endpoint: string;
- environment: string;
- retries?: number;
- timeout?: number;
- keepalive?: boolean;
-};
+import type { ApplicationObject, ContextData, PublishParams } from "./models";
+import type { ContextParams } from "./interfaces";
+import type { Client, ClientOptions, ClientRequestOptions } from "./interfaces";
type NormalizedClientOptions = Omit, "application"> & {
application: ApplicationObject;
};
-export default class Client {
+export class DefaultClient implements Client {
private readonly _opts: NormalizedClientOptions;
private readonly _delay: number;
+ private readonly _fetchImpl: typeof fetch;
+ private readonly _AbortControllerImpl: typeof AbortController;
constructor(opts: ClientOptions) {
const merged: Record = Object.assign(
- {
- agent: "javascript-client",
- retries: 5,
- timeout: 3000,
- keepalive: true,
- },
- opts
+ { agent: "javascript-client", retries: 5, timeout: 3000, keepalive: true },
+ opts,
);
for (const key of ["agent", "application", "apiKey", "endpoint", "environment"]) {
@@ -63,9 +24,7 @@ export default class Client {
const value = merged[key];
if (typeof value !== "string" || (value as string).length === 0) {
if (key === "application") {
- if (value !== null && typeof value === "object" && "name" in (value as object)) {
- continue;
- }
+ if (value !== null && typeof value === "object" && "name" in (value as object)) continue;
}
throw new Error(`Invalid '${key}' in options argument`);
}
@@ -75,17 +34,17 @@ export default class Client {
}
if (typeof merged.application === "string") {
- merged.application = {
- name: merged.application,
- version: 0,
- };
+ merged.application = { name: merged.application, version: 0 };
}
this._opts = merged as unknown as NormalizedClientOptions;
this._delay = 50;
+ this._fetchImpl = (opts.fetchImpl ?? globalThis.fetch).bind(globalThis) as typeof fetch;
+ this._AbortControllerImpl = opts.AbortControllerImpl ?? AbortController;
}
- getContext(options?: Partial) {
+
+ getContext(options?: Partial): Promise {
return this.getUnauthed({
...options,
path: "/context",
@@ -93,23 +52,15 @@ export default class Client {
application: this._opts.application.name,
environment: this._opts.environment,
},
- });
+ }) as Promise;
}
- createContext(params: ContextParams, options: ContextOptions) {
- const body = {
- units: params.units,
- };
-
- return this.post({
- ...options,
- path: "/context",
- body,
- });
+ createContext(params: ContextParams): Promise {
+ return this.post({ path: "/context", body: { units: params.units } });
}
- publish(params: PublishParams, options?: ClientRequestOptions) {
- const body: PublishParams = {
+ publish(params: PublishParams, options?: ClientRequestOptions): Promise {
+ const body: Record = {
units: params.units,
hashed: params.hashed,
publishedAt: params.publishedAt || Date.now(),
@@ -119,38 +70,32 @@ export default class Client {
if (Array.isArray(params.goals) && params.goals.length > 0) {
body.goals = params.goals;
}
-
if (Array.isArray(params.exposures) && params.exposures.length > 0) {
body.exposures = params.exposures;
}
-
if (Array.isArray(params.attributes) && params.attributes.length > 0) {
body.attributes = params.attributes;
}
- return this.put({
- ...options,
- path: "/context",
- body,
- });
+ return this.put({ ...options, path: "/context", body });
}
- request(options: ClientRequestOptions) {
+ request(options: ClientRequestOptions): Promise {
let url = `${this._opts.endpoint}${options.path}`;
if (options.query) {
const keys = Object.keys(options.query);
if (keys.length > 0) {
const encoded = keys
- .map((k) => (options.query ? `${k}=${encodeURIComponent(options.query[k])}` : null))
+ .map((k) => (options.query ? `${k}=${encodeURIComponent(options.query[k]!)}` : null))
.join("&");
url = `${url}?${encoded}`;
}
}
- const controller = new AbortController();
+ const controller = new this._AbortControllerImpl();
- const tryOnce = () => {
- const opts: Record = {
+ const tryOnce = (): Promise => {
+ const opts: RequestInit = {
method: options.method,
body: options.body !== undefined ? JSON.stringify(options.body, null, 0) : undefined,
signal: controller.signal,
@@ -164,34 +109,27 @@ export default class Client {
"X-Agent": this._opts.agent,
"X-Environment": this._opts.environment,
"X-Application": this._opts.application.name,
- "X-Application-Version": this._opts.application.version,
+ "X-Application-Version": String(this._opts.application.version),
};
}
- return fetch(url, opts).then((response: FetchResponse) => {
+ return this._fetchImpl(url, opts).then((response: Response) => {
if (!response.ok) {
const bail = response.status >= 400 && response.status < 500;
return response.text().then((text: string) => {
const error: Error & { _bail?: boolean } = new Error(
- text !== null && text.length > 0 ? text : response.statusText
+ text !== null && text.length > 0 ? text : response.statusText,
);
error._bail = bail;
-
return Promise.reject(error);
});
}
-
return response.json();
});
};
type WaitFn = ((ms: number) => Promise) & { reject?: (reason: AbortError) => void };
- type TryWithFn = ((
- retries: number,
- timeout: number,
- tries?: number,
- waited?: number
- ) => ReturnType) & {
+ type TryWithFn = ((retries: number, timeout: number, tries?: number, waited?: number) => Promise) & {
timedout?: boolean;
};
@@ -212,24 +150,15 @@ export default class Client {
delete tryWith.timedout;
return tryOnce().catch((reason: Error & { _bail?: boolean }) => {
- console.warn(reason);
-
- if (reason._bail || retries <= 0) {
- throw new Error(reason.message);
- } else if (tries >= retries) {
- throw new RetryError(tries, reason, url);
- } else if (waited >= timeout || reason.name === "AbortError") {
- if (tryWith.timedout) {
- throw new TimeoutError(timeout);
- }
-
+ if (reason._bail || retries <= 0) throw new Error(reason.message);
+ if (tries >= retries) throw new RetryError(tries, reason, url);
+ if (waited >= timeout || reason.name === "AbortError") {
+ if (tryWith.timedout) throw new TimeoutError(timeout);
throw reason;
}
let delay = (1 << tries) * this._delay + 0.5 * Math.random() * this._delay;
- if (waited + delay > timeout) {
- delay = timeout - waited;
- }
+ if (waited + delay > timeout) delay = timeout - waited;
return wait(delay).then(() => tryWith(retries, timeout, tries + 1, waited + delay));
});
@@ -253,7 +182,7 @@ export default class Client {
? setTimeout(() => {
tryWith.timedout = true;
abort();
- }, timeout)
+ }, timeout)
: 0;
const finalCleanUp = () => {
@@ -263,8 +192,8 @@ export default class Client {
}
};
- return tryWith(this._opts.retries ?? 5, this._opts.timeout ?? 3000)
- .then((value: string) => {
+ return tryWith(this._opts.retries ?? 5, timeout || this._opts.timeout || 3000)
+ .then((value) => {
finalCleanUp();
return value;
})
@@ -274,20 +203,12 @@ export default class Client {
});
}
- post(options: ClientRequestOptions) {
- return this.request({
- ...options,
- auth: true,
- method: "POST",
- });
+ post(options: ClientRequestOptions): Promise {
+ return this.request({ ...options, auth: true, method: "POST" });
}
- put(options: ClientRequestOptions) {
- return this.request({
- ...options,
- auth: true,
- method: "PUT",
- });
+ put(options: ClientRequestOptions): Promise {
+ return this.request({ ...options, auth: true, method: "PUT" });
}
getAgent(): string {
@@ -302,10 +223,7 @@ export default class Client {
return this._opts.environment;
}
- getUnauthed(options: ClientRequestOptions) {
- return this.request({
- ...options,
- method: "GET",
- });
+ getUnauthed(options: ClientRequestOptions): Promise {
+ return this.request({ ...options, method: "GET" });
}
}
diff --git a/src/config.ts b/src/config.ts
index 1be84c7..11d844d 100644
--- a/src/config.ts
+++ b/src/config.ts
@@ -1,25 +1,43 @@
-import clone from "rfdc/default";
-import Context from "./context";
import { isObject } from "./utils";
-export function mergeConfig(context: Context, previousConfig: Record) {
- const merged = clone(previousConfig);
+interface ConfigContext {
+ variableKeys(): Record;
+ variableValue(key: string, defaultValue: unknown): unknown;
+}
+
+function deepClone(value: T): T {
+ if (Array.isArray(value)) {
+ return value.map((item) => deepClone(item)) as T;
+ }
+
+ if (value !== null && typeof value === "object" && Object.getPrototypeOf(value) === Object.prototype) {
+ const result: Record = {};
+ for (const [key, item] of Object.entries(value)) {
+ result[key] = deepClone(item);
+ }
+ return result as T;
+ }
+
+ return value;
+}
+
+export function mergeConfig(context: ConfigContext, previousConfig: Record): Record {
+ const merged = deepClone(previousConfig);
const keys = context.variableKeys();
for (const [variableKey, experimentName] of Object.entries(keys)) {
- let target = merged;
+ let target: Record | undefined = merged;
const frags = variableKey.split(".");
for (let index = 0; index < frags.length; ++index) {
- const frag = frags[index];
+ const frag = frags[index]!;
+
+ if (target === undefined) break;
if (`_${frag}_setter` in target) {
console.error(
- `Config key '${frags.slice(0, index + 1).join(".")}' already set by experiment '${
- target[`_${frag}_setter`]
- }'.`
+ `Config key '${frags.slice(0, index + 1).join(".")}' already set by experiment '${target[`_${frag}_setter`]}'.`,
);
-
target = undefined;
break;
}
@@ -28,14 +46,12 @@ export function mergeConfig(context: Context, previousConfig: Record;
} else {
- target = target[frag];
+ target = target[frag] as Record;
}
}
}
@@ -43,15 +59,9 @@ export function mergeConfig(context: Context, previousConfig: Record {
- return context.variableValue(variableKey, defaultValue);
- },
+ get: () => context.variableValue(variableKey, defaultValue),
});
}
}
diff --git a/src/context.ts b/src/context.ts
index c862b3d..ae52b3c 100644
--- a/src/context.ts
+++ b/src/context.ts
@@ -1,116 +1,46 @@
-import { arrayEqualsShallow, hashUnit, isObject, isPromise } from "./utils";
+import { hashUnit } from "./hashing";
import { VariantAssigner } from "./assigner";
import { AudienceMatcher } from "./matcher";
import { insertUniqueSorted } from "./algorithm";
-import SDK, { EventLogger, EventName } from "./sdk";
-import { ContextPublisher, PublishParams } from "./publisher";
-import { ContextDataProvider } from "./provider";
-import { ClientRequestOptions } from "./client";
+import { arrayEqualsShallow, isObject, isPromise } from "./utils";
import { SDK_VERSION } from "./version";
+import { ContextNotReadyError, ContextFinalizedError } from "./errors";
+import type {
+ Assignment,
+ Attribute,
+ ContextData,
+ Experiment,
+ ExperimentData,
+ Exposure,
+ GoalAchievement,
+ Units,
+ PublishParams,
+ JSONValue,
+ CustomFieldValue,
+} from "./models";
+import type {
+ ClientRequestOptions,
+ ContextDataProvider,
+ ContextPublisher,
+ EventLogger,
+ EventName,
+ ContextParams,
+} from "./interfaces";
+
+interface SDKLike {
+ getClient(): {
+ getAgent(): string;
+ getApplication(): { name: string; version: number | string };
+ getEnvironment(): string;
+ publish(request: PublishParams, options?: ClientRequestOptions): Promise;
+ getContext(options?: Partial): Promise;
+ };
+ getContextPublisher(): ContextPublisher;
+ getContextDataProvider(): ContextDataProvider;
+ getEventLogger(): EventLogger;
+}
-type JSONPrimitive = string | number | boolean | null;
-type JSONObject = { [key: string]: JSONValue };
-type JSONArray = JSONValue[];
-type JSONValue = JSONPrimitive | JSONObject | JSONArray;
-
-type CustomFieldValueType = "text" | "string" | "number" | "json" | "boolean";
-
-type CustomFieldValue = {
- name: string;
- value: string;
- type: CustomFieldValueType;
-};
-
-export type ExperimentData = {
- id: number;
- name: string;
- unitType: string | null;
- iteration: number;
- fullOnVariant: number;
- trafficSplit: number[];
- trafficSeedHi: number;
- trafficSeedLo: number;
- audience: string;
- audienceStrict: boolean;
- split: number[];
- seedHi: number;
- seedLo: number;
- variants: { config: null | string }[];
- variables: Record;
- variant: number;
- overridden: boolean;
- assigned: boolean;
- exposed: boolean;
- eligible: boolean;
- fullOn: boolean;
- custom: boolean;
- audienceMismatch: boolean;
- customFieldValues: CustomFieldValue[] | null;
-};
-
-type Assignment = {
- id: number;
- iteration: number;
- fullOnVariant: number;
- unitType: string | null;
- variant: number;
- overridden: boolean;
- assigned: boolean;
- exposed: boolean;
- eligible: boolean;
- fullOn: boolean;
- custom: boolean;
- audienceMismatch: boolean;
- trafficSplit?: number[];
- variables?: Record;
- attrsSeq?: number;
-};
-
-export type Experiment = {
- data: ExperimentData;
- variables: Record[];
-};
-
-export type Unit = {
- type: string;
- uid: string | null;
-};
-
-export type Exposure = {
- id: number;
- name: string;
- exposedAt: number;
- unit: string | null;
- variant: number;
- assigned: boolean;
- eligible: boolean;
- overridden: boolean;
- fullOn: boolean;
- custom: boolean;
- audienceMismatch: boolean;
-};
-
-export type Attribute = {
- name: string;
- value: unknown;
- setAt: number;
-};
-
-export type Units = {
- [key: string]: string | number;
-};
-
-export type Goal = {
- name: string;
- properties: Record | null;
- achievedAt: number;
-};
-
-export type ContextParams = {
- units: Record;
-};
-
-export type ContextOptions = {
+type ContextOptionsInternal = {
publisher?: ContextPublisher;
dataProvider?: ContextDataProvider;
eventLogger?: EventLogger;
@@ -119,39 +49,38 @@ export type ContextOptions = {
includeSystemAttributes?: boolean;
};
-export type ContextData = {
- experiments?: ExperimentData[];
-};
-
-export default class Context {
+export class Context {
private readonly _assigners: Record;
private readonly _attrs: Attribute[];
private readonly _audienceMatcher: AudienceMatcher;
private readonly _cassignments: Record;
private readonly _dataProvider: ContextDataProvider;
private readonly _eventLogger: EventLogger;
- private readonly _opts: ContextOptions;
+ private readonly _opts: ContextOptionsInternal;
private readonly _publisher: ContextPublisher;
- private readonly _sdk: SDK;
+ private readonly _sdk: SDKLike;
private readonly _units: Units;
- private _assignments: Record;
- private _data: ContextData;
+ private _assignments: Record = {};
+ private _data!: ContextData;
private _exposures: Exposure[];
private _failed: boolean;
+ private _failedError: Error | null = null;
private _finalized: boolean;
- private _finalizing: boolean | Promise | null;
- private _goals: Goal[];
- private _index: Record;
- private _indexVariables: Record;
+ private _finalizing: Promise | null = null;
+ private _goals: GoalAchievement[];
+ private _index!: Record;
+ private _indexVariables!: Record;
private _overrides: Record;
private _pending: number;
private _attrsSeq: number;
+ private _attrsMapCache: Record | null = null;
+ private _attrsMapCacheSeq: number = -1;
private _hashes?: Record;
private _promise?: Promise;
private _publishTimeout?: ReturnType;
private _refreshInterval?: ReturnType;
- constructor(sdk: SDK, options: ContextOptions, params: ContextParams, promise: ContextData | Promise) {
+ constructor(sdk: SDKLike, options: ContextOptionsInternal, params: ContextParams, promise: ContextData | Promise) {
this._sdk = sdk;
this._publisher = options.publisher || this._sdk.getContextPublisher();
this._dataProvider = options.dataProvider || this._sdk.getContextDataProvider();
@@ -190,15 +119,14 @@ export default class Context {
this._init({});
this._failed = true;
+ this._failedError = error;
delete this._promise;
this._logError(error);
});
} else {
- promise = promise as ContextData;
- this._init(promise);
-
- this._logEvent("ready", promise);
+ this._init(promise as ContextData);
+ this._logEvent("ready", promise as ContextData);
}
}
@@ -218,13 +146,17 @@ export default class Context {
return this._failed;
}
- ready() {
+ readyError(): Error | null {
+ return this._failedError;
+ }
+
+ ready(): Promise {
if (this.isReady()) {
return Promise.resolve(true);
}
return new Promise((resolve) => {
- this._promise?.then(() => resolve(true)).catch((e) => resolve(e));
+ this._promise?.then(() => resolve(true)).catch(() => resolve(true));
});
}
@@ -234,7 +166,6 @@ export default class Context {
data() {
this._checkReady();
-
return this._data;
}
@@ -250,6 +181,14 @@ export default class Context {
return this._dataProvider;
}
+ getSDK() {
+ return this._sdk;
+ }
+
+ getOptions(): ContextOptionsInternal {
+ return { ...this._opts };
+ }
+
publish(requestOptions?: ClientRequestOptions) {
this._checkReady(true);
@@ -302,29 +241,34 @@ export default class Context {
}
this._units[unitType] = uid;
+
+ if (this._hashes) {
+ delete this._hashes[unitType];
+ }
}
getUnits() {
- return this._units;
+ return { ...this._units };
}
units(units: Record) {
- Object.entries(units).forEach(([unitType, uid]) => {
+ for (const [unitType, uid] of Object.entries(units)) {
this.unit(unitType, uid);
- });
+ }
}
getAttribute(attrName: string) {
let result;
-
- this._attrs.forEach((attr) => {
+ for (const attr of this._attrs) {
if (attr.name === attrName) result = attr.value;
- });
-
+ }
return result;
}
attribute(attrName: string, value: unknown) {
+ if (typeof attrName !== "string" || attrName.trim().length === 0) {
+ throw new Error("Attribute name must be a non-empty string");
+ }
this._checkNotFinalized();
this._attrs.push({ name: attrName, value: value, setAt: Date.now() });
@@ -333,35 +277,39 @@ export default class Context {
getAttributes() {
const attributes: Record = {};
- this._attrs
- .map((a) => [a.name, a.value])
- .forEach(([key, value]) => {
- attributes[key as string] = value;
- });
+ for (const a of this._attrs) {
+ attributes[a.name] = a.value;
+ }
return attributes;
}
attributes(attrs: Record) {
- Object.entries(attrs).forEach(([attrName, value]) => {
+ for (const [attrName, value] of Object.entries(attrs)) {
this.attribute(attrName, value);
- });
+ }
}
peek(experimentName: string) {
+ if (typeof experimentName !== "string" || experimentName.trim().length === 0) {
+ throw new Error("Experiment name must be a non-empty string");
+ }
this._checkReady(true);
-
return this._peek(experimentName).variant;
}
treatment(experimentName: string) {
+ if (typeof experimentName !== "string" || experimentName.trim().length === 0) {
+ throw new Error("Experiment name must be a non-empty string");
+ }
this._checkReady(true);
-
return this._treatment(experimentName).variant;
}
track(goalName: string, properties?: Record) {
+ if (typeof goalName !== "string" || goalName.trim().length === 0) {
+ throw new Error("Goal name must be a non-empty string");
+ }
this._checkNotFinalized();
-
return this._track(goalName, properties);
}
@@ -371,19 +319,22 @@ export default class Context {
experiments() {
this._checkReady();
-
return this._data.experiments?.map((x) => x.name);
}
- variableValue(key: string, defaultValue: string): string {
+ variableValue(key: string, defaultValue: T): T {
+ if (typeof key !== "string" || key.trim().length === 0) {
+ throw new Error("Variable key must be a non-empty string");
+ }
this._checkReady(true);
-
return this._variableValue(key, defaultValue);
}
- peekVariableValue(key: string, defaultValue: string): string {
+ peekVariableValue(key: string, defaultValue: T): T {
+ if (typeof key !== "string" || key.trim().length === 0) {
+ throw new Error("Variable key must be a non-empty string");
+ }
this._checkReady(true);
-
return this._peekVariable(key, defaultValue);
}
@@ -392,49 +343,88 @@ export default class Context {
const variableExperiments: Record = {};
- Object.entries(this._indexVariables).forEach(([key, values]) => {
- values.forEach((value) => {
+ for (const [key, values] of Object.entries(this._indexVariables)) {
+ for (const value of values) {
if (variableExperiments[key]) variableExperiments[key].push(value.data.name);
else variableExperiments[key] = [value.data.name];
- });
- });
+ }
+ }
return variableExperiments;
}
override(experimentName: string, variant: number) {
+ if (typeof experimentName !== "string" || experimentName.trim().length === 0) {
+ throw new Error("Experiment name must be a non-empty string");
+ }
+ if (typeof variant !== "number" || variant < 0 || !Number.isInteger(variant)) {
+ throw new Error("Variant must be a non-negative integer");
+ }
+ this._checkNotFinalized();
this._overrides = Object.assign(this._overrides, { [experimentName]: variant });
}
overrides(experimentVariants: Record) {
- Object.entries(experimentVariants).forEach(([experimentName, variant]) => {
+ for (const [experimentName, variant] of Object.entries(experimentVariants)) {
this.override(experimentName, variant);
- });
+ }
}
customAssignment(experimentName: string, variant: number) {
+ if (typeof experimentName !== "string" || experimentName.trim().length === 0) {
+ throw new Error("Experiment name must be a non-empty string");
+ }
+ if (typeof variant !== "number" || variant < 0 || !Number.isInteger(variant)) {
+ throw new Error("Variant must be a non-negative integer");
+ }
this._checkNotFinalized();
-
this._cassignments[experimentName] = variant;
}
customAssignments(experimentVariants: Record) {
- Object.entries(experimentVariants).forEach(([experimentName, variant]) => {
+ for (const [experimentName, variant] of Object.entries(experimentVariants)) {
this.customAssignment(experimentName, variant);
- });
+ }
+ }
+
+ customFieldKeys() {
+ this._checkReady(true);
+ return this._customFieldKeys();
+ }
+
+ customFieldValue(experimentName: string, key: string) {
+ if (typeof experimentName !== "string" || experimentName.trim().length === 0) {
+ throw new Error("Experiment name must be a non-empty string");
+ }
+ if (typeof key !== "string" || key.trim().length === 0) {
+ throw new Error("Key must be a non-empty string");
+ }
+ this._checkReady(true);
+ return this._customFieldValue(experimentName, key);
+ }
+
+ customFieldValueType(experimentName: string, key: string) {
+ if (typeof experimentName !== "string" || experimentName.trim().length === 0) {
+ throw new Error("Experiment name must be a non-empty string");
+ }
+ if (typeof key !== "string" || key.trim().length === 0) {
+ throw new Error("Key must be a non-empty string");
+ }
+ this._checkReady(true);
+ return this._customFieldValueType(experimentName, key);
}
private _checkNotFinalized() {
if (this.isFinalized()) {
- throw new Error("ABSmartly Context is finalized.");
+ throw new ContextFinalizedError();
} else if (this.isFinalizing()) {
- throw new Error("ABSmartly Context is finalizing.");
+ throw new ContextFinalizedError();
}
}
private _checkReady(expectNotFinalized?: boolean) {
if (!this.isReady()) {
- throw new Error("ABSmartly Context is not yet ready.");
+ throw new ContextNotReadyError();
}
if (expectNotFinalized) {
@@ -443,14 +433,28 @@ export default class Context {
}
private _getAttributesMap(): Record {
+ if (this._attrsMapCache !== null && this._attrsMapCacheSeq === this._attrsSeq) {
+ return this._attrsMapCache;
+ }
const attrs: Record = {};
- this._attrs.forEach((attr) => {
+ for (const attr of this._attrs) {
attrs[attr.name] = attr.value;
- });
+ }
+ this._attrsMapCache = attrs;
+ this._attrsMapCacheSeq = this._attrsSeq;
return attrs;
}
- private _assign(experimentName: string) {
+ private _evaluateAudience(audience: string): boolean | null {
+ try {
+ return this._audienceMatcher.evaluate(audience, this._getAttributesMap());
+ } catch (error) {
+ this._logError(error as Error);
+ return null;
+ }
+ }
+
+ private _assign(experimentName: string): Assignment {
const experimentMatches = (experiment: ExperimentData, assignment: Assignment) => {
return (
experiment.id === assignment.id &&
@@ -463,9 +467,9 @@ export default class Context {
const audienceMatches = (experiment: ExperimentData, assignment: Assignment) => {
if (experiment.audience && experiment.audience.length > 0) {
- if (this._attrsSeq > (assignment.attrsSeq ?? 0)) {
- const result = this._audienceMatcher.evaluate(experiment.audience, this._getAttributesMap());
- const newAudienceMismatch = typeof result === "boolean" ? !result : false;
+ if (this._attrsSeq > assignment.attrsSeq) {
+ const result = this._evaluateAudience(experiment.audience);
+ const newAudienceMismatch = typeof result === "boolean" ? !result : true;
if (newAudienceMismatch !== assignment.audienceMismatch) {
return false;
@@ -479,23 +483,20 @@ export default class Context {
const hasCustom = experimentName in this._cassignments;
const hasOverride = experimentName in this._overrides;
- const experiment = experimentName in this._index ? this._index[experimentName] : null;
+ const experiment = experimentName in this._index ? this._index[experimentName]! : null;
if (experimentName in this._assignments) {
- const assignment = this._assignments[experimentName];
+ const assignment = this._assignments[experimentName]!;
if (hasOverride) {
- if (assignment.overridden && assignment.variant === this._overrides[experimentName]) {
- // override up-to-date
+ if (assignment.overridden && assignment.variant === this._overrides[experimentName]!) {
return assignment;
}
} else if (experiment == null) {
if (!assignment.assigned) {
- // previously not-running experiment
return assignment;
}
- } else if (!hasCustom || this._cassignments[experimentName] === assignment.variant) {
+ } else if (!hasCustom || this._cassignments[experimentName]! === assignment.variant) {
if (experimentMatches(experiment.data, assignment) && audienceMatches(experiment.data, assignment)) {
- // assignment up-to-date
return assignment;
}
}
@@ -514,6 +515,9 @@ export default class Context {
fullOn: false,
custom: false,
audienceMismatch: false,
+ trafficSplit: null,
+ variables: null,
+ attrsSeq: 0,
};
this._assignments[experimentName] = assignment;
@@ -525,17 +529,14 @@ export default class Context {
}
assignment.overridden = true;
- assignment.variant = this._overrides[experimentName];
+ assignment.variant = this._overrides[experimentName]!;
} else {
if (experiment != null) {
const unitType = experiment.data.unitType;
if (experiment.data.audience && experiment.data.audience.length > 0) {
- const result = this._audienceMatcher.evaluate(experiment.data.audience, this._getAttributesMap());
-
- if (typeof result === "boolean") {
- assignment.audienceMismatch = !result;
- }
+ const result = this._evaluateAudience(experiment.data.audience);
+ assignment.audienceMismatch = typeof result === "boolean" ? !result : true;
}
if (experiment.data.audienceStrict && assignment.audienceMismatch) {
@@ -547,7 +548,7 @@ export default class Context {
if (unit !== null) {
const assigner =
unitType in this._assigners
- ? this._assigners[unitType]
+ ? this._assigners[unitType]!
: (this._assigners[unitType] = new VariantAssigner(unit));
const eligible =
assigner.assign(
@@ -561,7 +562,7 @@ export default class Context {
if (eligible) {
if (hasCustom) {
- assignment.variant = this._cassignments[experimentName];
+ assignment.variant = this._cassignments[experimentName]!;
assignment.custom = true;
} else {
assignment.variant = assigner.assign(
@@ -583,7 +584,6 @@ export default class Context {
assignment.fullOn = true;
}
- // store these so we can detect changes to running experiment
assignment.unitType = unitType;
assignment.id = experiment.data.id;
assignment.iteration = experiment.data.iteration;
@@ -594,7 +594,7 @@ export default class Context {
}
if (experiment != null && assignment.variant < experiment.data.variants.length) {
- assignment.variables = experiment.variables[assignment.variant];
+ assignment.variables = experiment.variables[assignment.variant] ?? null;
}
return assignment;
@@ -609,7 +609,6 @@ export default class Context {
if (!assignment.exposed) {
assignment.exposed = true;
-
this._queueExposure(experimentName, assignment);
}
@@ -654,18 +653,14 @@ export default class Context {
return Array.from(keys);
}
- customFieldKeys() {
- this._checkReady(true);
-
- return this._customFieldKeys();
- }
-
private _customFieldValue(experimentName: string, key: string): JSONValue {
const experiment = this._index[experimentName];
if (experiment != null) {
- const field = experiment.data.customFieldValues?.find((x) => x.name === key);
+ const field = experiment.data.customFieldValues?.find((x: CustomFieldValue) => x.name === key);
if (field != null) {
+ if (field.value === null) return null;
+
switch (field.type) {
case "text":
case "string":
@@ -678,14 +673,16 @@ export default class Context {
if (field.value === "") return "";
return JSON.parse(field.value);
} catch (e) {
- console.error(`Failed to parse JSON custom field value '${key}' for experiment '${experimentName}'`);
+ this._logError(new Error(
+ `Failed to parse JSON custom field value '${key}' for experiment '${experimentName}': ${(e as Error).message}`
+ ));
return null;
}
case "boolean":
return field.value === "true";
default:
- console.error(
- `Unknown custom field type '${field.type}' for experiment '${experimentName}' and key '${key}' - you may need to upgrade to the latest SDK version`
+ this._logError(
+ new Error(`Unknown custom field type '${field.type}' for experiment '${experimentName}' and key '${key}' - you may need to upgrade to the latest SDK version`)
);
return null;
}
@@ -695,17 +692,11 @@ export default class Context {
return null;
}
- customFieldValue(experimentName: string, key: string) {
- this._checkReady(true);
-
- return this._customFieldValue(experimentName, key);
- }
-
private _customFieldValueType(experimentName: string, key: string) {
const experiment = this._index[experimentName];
if (experiment != null) {
- const field = experiment.data.customFieldValues?.find((x) => x.name === key);
+ const field = experiment.data.customFieldValues?.find((x: CustomFieldValue) => x.name === key);
if (field != null) {
return field.type;
}
@@ -714,25 +705,21 @@ export default class Context {
return null;
}
- customFieldValueType(experimentName: string, key: string) {
- this._checkReady(true);
-
- return this._customFieldValueType(experimentName, key);
- }
-
- private _variableValue(key: string, defaultValue: string): string {
- for (const i in this._indexVariables[key]) {
- const experimentName = this._indexVariables[key][i].data.name;
- const assignment = this._assign(experimentName);
- if (assignment.variables !== undefined) {
- if (!assignment.exposed) {
- assignment.exposed = true;
-
- this._queueExposure(experimentName, assignment);
- }
+ private _variableValue(key: string, defaultValue: T): T {
+ const experiments = this._indexVariables[key];
+ if (experiments) {
+ for (const experiment of experiments) {
+ const experimentName = experiment.data.name;
+ const assignment = this._assign(experimentName);
+ if (assignment.variables != null) {
+ if (!assignment.exposed) {
+ assignment.exposed = true;
+ this._queueExposure(experimentName, assignment);
+ }
- if (key in assignment.variables && (assignment.assigned || assignment.overridden)) {
- return assignment.variables[key] as string;
+ if (key in assignment.variables && (assignment.assigned || assignment.overridden)) {
+ return assignment.variables[key] as T;
+ }
}
}
}
@@ -740,13 +727,16 @@ export default class Context {
return defaultValue;
}
- private _peekVariable(key: string, defaultValue: string): string {
- for (const i in this._indexVariables[key]) {
- const experimentName = this._indexVariables[key][i].data.name;
- const assignment = this._assign(experimentName);
- if (assignment.variables !== undefined) {
- if (key in assignment.variables && (assignment.assigned || assignment.overridden)) {
- return assignment.variables[key] as string;
+ private _peekVariable