diff --git a/YLErpWeb/Views/SwapTrade2/TradeEdit.cshtml b/YLErpWeb/Views/SwapTrade2/TradeEdit.cshtml
index 3e8660bc..b8c7d03f 100644
--- a/YLErpWeb/Views/SwapTrade2/TradeEdit.cshtml
+++ b/YLErpWeb/Views/SwapTrade2/TradeEdit.cshtml
@@ -96,6 +96,7 @@
+
}
-
\ No newline at end of file
+
diff --git a/YLErpWeb/Views/SwapTrade2/TradeMarketReport_EodPosition.cshtml b/YLErpWeb/Views/SwapTrade2/TradeMarketReport_EodPosition.cshtml
index 551ef10d..3516c460 100644
--- a/YLErpWeb/Views/SwapTrade2/TradeMarketReport_EodPosition.cshtml
+++ b/YLErpWeb/Views/SwapTrade2/TradeMarketReport_EodPosition.cshtml
@@ -6,9 +6,8 @@
var pageObj = new
{
EndTime = ViewBag.EndTime?.ToString(),
- StartTime = ViewBag.StartTime?.ToString(),
valueDate = valuedateBLL.ValueDate.ToString("yyyy-MM-dd"),
- configcolumn = configcolumn_data.互换估值,
+ configcolumn = configcolumn_data.互换估值V1,
StructureType = ViewBag.StructureType
};
}
@@ -23,7 +22,7 @@
width: 250px !important;
}
- #ValueDateFrom, #ValueDate {
+ #ValueDate {
width: 152px !important;
font-size: 1rem !important;
}
@@ -52,7 +51,7 @@
@Html.MyAceDropdownInput("ClientId", "客户名称", ClientDataModel.GetAllClient(), false, true, null, false)
@Html.CheckBox("ParentFlag", false) @Html.Label(null,"包含子级", new { @style = "font-size:12px;" })
- @Html.ShortInput("ValueDateFrom", "起始日期:")
+ @Html.MyAceDropdownInput("BookId", "簿记账户", AssetunitController.GetClientassetunit(), false, true, null, false)
@Html.ShortInput("ValueDate", "结束日期:")
@MyControls.SearchBtn()
@if (CurUser.结算管理_每日估值报告邮件发送)
diff --git a/YLErpWeb/Views/trade/EodPositionRisks.cshtml b/YLErpWeb/Views/trade/EodPositionRisks.cshtml
index a905a38b..d6831d6f 100644
--- a/YLErpWeb/Views/trade/EodPositionRisks.cshtml
+++ b/YLErpWeb/Views/trade/EodPositionRisks.cshtml
@@ -32,6 +32,18 @@
overflow: hidden;
text-overflow: ellipsis;
}
+
+ #listGrid tr.jqgrow {
+ height: 25px !important;
+ }
+
+ #listGrid tr.jqgrow > td {
+ height: 25px !important;
+ line-height: 20px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
@section JS{
@@ -107,4 +119,4 @@
-
\ No newline at end of file
+
diff --git a/YLErpWeb/Views/trade/tradeList.cshtml b/YLErpWeb/Views/trade/tradeList.cshtml
index 4d51253e..82451b35 100644
--- a/YLErpWeb/Views/trade/tradeList.cshtml
+++ b/YLErpWeb/Views/trade/tradeList.cshtml
@@ -91,7 +91,18 @@
.tag-context {
padding: 0px;
}
-
+
+ #listGrid tr.jqgrow {
+ height: 25px !important;
+ }
+
+ #listGrid tr.jqgrow > td {
+ height: 25px !important;
+ line-height: 20px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
}
diff --git a/YLErpWeb/fe-tests/_shim_run.js b/YLErpWeb/fe-tests/_shim_run.js
new file mode 100644
index 00000000..93bcb82a
--- /dev/null
+++ b/YLErpWeb/fe-tests/_shim_run.js
@@ -0,0 +1,54 @@
+/**
+ * _shim_run.js — 不依赖 jest 的轻量测试运行器(仅用于在沙箱内验证测试文件逻辑)。
+ * 本机请用 jest:cd YLErpWeb/fe-tests && npm i && npm test
+ */
+let passed = 0;
+let failed = 0;
+const failures = [];
+
+function fmt(v) {
+ return typeof v === 'object' ? JSON.stringify(v) : String(v);
+}
+
+function makeExpect(actual) {
+ return {
+ toBe(expected) {
+ if (Object.is(actual, expected)) { passed++; }
+ else { failed++; failures.push('toBe: expected ' + fmt(expected) + ' got ' + fmt(actual)); }
+ },
+ toBeDefined() {
+ if (actual !== undefined && actual !== null) { passed++; }
+ else { failed++; failures.push('toBeDefined: got ' + fmt(actual)); }
+ },
+ toBeLessThanOrEqual(n) {
+ if (actual <= n) { passed++; }
+ else { failed++; failures.push('toBeLessThanOrEqual: ' + fmt(actual) + ' <= ' + n + ' failed'); }
+ },
+ toBeGreaterThan(n) {
+ if (actual > n) { passed++; }
+ else { failed++; failures.push('toBeGreaterThan: ' + fmt(actual) + ' > ' + n + ' failed'); }
+ },
+ toBeGreaterThanOrEqual(n) {
+ if (actual >= n) { passed++; }
+ else { failed++; failures.push('toBeGreaterThanOrEqual: ' + fmt(actual) + ' >= ' + n + ' failed'); }
+ },
+ };
+}
+
+global.expect = (actual) => makeExpect(actual);
+global.describe = (name, fn) => { fn(); };
+global.test = (name, fn) => {
+ try { fn(); }
+ catch (e) { failed++; failures.push(name + ': ' + e.message); }
+};
+global.it = global.test;
+
+require('./swapCalc.test.js');
+require('./otcformat.test.js');
+require('./parity.test.js');
+
+console.log('\n==== RUNNER (jest-shim) ====');
+console.log('PASS=' + passed + ' FAIL=' + failed);
+failures.forEach((f) => console.log(' ✗ ' + f));
+console.log(failures.length ? 'RESULT: RED' : 'RESULT: GREEN');
+process.exit(failed > 0 ? 1 : 0);
diff --git a/YLErpWeb/fe-tests/guard_arch.js b/YLErpWeb/fe-tests/guard_arch.js
new file mode 100644
index 00000000..d480b6ab
--- /dev/null
+++ b/YLErpWeb/fe-tests/guard_arch.js
@@ -0,0 +1,122 @@
+#!/usr/bin/env node
+/**
+ * guard_arch.js — 前端架构闸门(零依赖,纯 Node)
+ * ============================================================================
+ * 目的:防止在 Vue 组件方法里【新增】手写「金额 / 精度」计算(toFixed / _.round /
+ * Math.round / × multiplier 缩放等),避免又长出一份「不可测的内联公式」。
+ *
+ * 规则:仅扫描【本次提交改动中新增/修改的行】(git diff 的 + 行),且位于
+ * wwwroot/Scripts/app/ 并定义 new Vue(...) 的文件。对其中每一行「金额算术」,
+ * 若该行没有路由到某个 *Calc 模块(含 SwapCalc.),则判为违规 → 退出码 1。
+ *
+ * 设计要点:
+ * - 只查「新增/修改的行」,不查历史存量。这样不会阻断对存量文件(如仍含内联计算的
+ * unwindSwapTrade.js)的正常改动,只拦「新写的内联金额公式」。
+ * - 已外置计算逻辑的组件(incomeSwapTrade.js / swapTradeEdit.js)通过调用 SwapCalc.*
+ * 保持合规;新代码必须把金额计算放进 *Calc 模块(参考 swapCalc.js)。
+ * - 注释行会被剥离后再判断,避免注释里的样例文字误报。
+ * - 无需 jest / npm install,和 _shim_run.js 同属零依赖守卫。
+ *
+ * 用法:node guard_arch.js (一般在 pre-commit / CI 中自动调用)
+ * ============================================================================
+ */
+'use strict';
+
+const { execSync } = require('child_process');
+const fs = require('fs');
+const path = require('path');
+
+// fe-tests -> YLErpWeb -> zszq-trs(仓库根)
+const ROOT = path.resolve(__dirname, '..', '..');
+
+// 金额 / 精度算术模式(命中即怀疑)
+const MONEY_PATTERNS = [
+ /\.toFixed\s*\(/, // 显示/入库精度
+ /_\.round\s*\(/, // lodash 四舍五入
+ /Math\.round\s*\(/, // 原生四舍五入
+ /\*\s*this\.multiplier/, // 价格 × 乘数缩放(dcf649f2 / 20ea93d8 类)
+ /\*\s*thisObj\.multiplier/,
+];
+
+// 合规标记:行内引用了某个 *Calc 模块(如 SwapCalc.),视为已外置
+const COMPLIANT = /Calc\./;
+
+function tryCmd(cmd) {
+ try {
+ return execSync(cmd, { cwd: ROOT }).toString().trim();
+ } catch (e) {
+ return '';
+ }
+}
+
+function changedAppVueFiles() {
+ const listCmd = 'git diff --cached --name-only --diff-filter=ACM -- "*.js"';
+ let out = tryCmd(listCmd);
+ if (!out) out = tryCmd('git diff --name-only --diff-filter=ACM -- "*.js"');
+ if (!out) return [];
+ return out.split('\n').filter((f) => {
+ if (!/wwwroot[\\/]Scripts[\\/]app[\\/]/.test(f)) return false;
+ const full = path.join(ROOT, f);
+ if (!fs.existsSync(full)) return false;
+ try {
+ return /new\s+Vue\s*\(/.test(fs.readFileSync(full, 'utf8'));
+ } catch (e) {
+ return false;
+ }
+ });
+}
+
+// 取文件在本次提交中【新增/修改】的行(git diff 的 + 行,排除 +++ 文件头)
+function addedLines(file) {
+ const quoted = JSON.stringify(file);
+ let out = tryCmd(`git diff --cached -U0 -- ${quoted}`);
+ if (!out) out = tryCmd(`git diff -U0 -- ${quoted}`);
+ if (!out) return [];
+ return out.split('\n')
+ .filter((l) => l.startsWith('+') && !l.startsWith('+++'))
+ .map((l) => l.slice(1));
+}
+
+function stripComment(line) {
+ // 去掉 /* */ 块注释与 // 行内注释,避免注释里的样例文字误报
+ return line.replace(/\/\*.*?\*\//g, '').replace(/\/\/.*$/, '').trim();
+}
+
+function main() {
+ const files = changedAppVueFiles();
+ if (files.length) {
+ console.log(`[guard_arch] 扫描 ${files.length} 个改动的 Vue 组件文件的新增/修改行`);
+ }
+
+ let violations = 0;
+ for (const file of files) {
+ const added = addedLines(file);
+ const found = [];
+ added.forEach((rawLine) => {
+ const code = stripComment(rawLine);
+ if (!code) return;
+ const hasMoney = MONEY_PATTERNS.some((p) => p.test(code));
+ if (hasMoney && !COMPLIANT.test(code)) {
+ found.push(` + ${rawLine.trim()}`);
+ }
+ });
+
+ if (found.length) {
+ violations += found.length;
+ console.log(`[guard_arch] 违规 ${file} 发现【新增】内联金额计算(应路由到 *Calc 模块):`);
+ found.forEach((f) => console.log(f));
+ }
+ }
+
+ if (violations > 0) {
+ console.log(
+ `\n[guard_arch] 发现 ${violations} 处【新增】内联金额计算, 提交被阻断。` +
+ `请把金额/精度计算抽到 *Calc 模块(参考 swapCalc.js)。`
+ );
+ process.exit(1);
+ }
+ console.log('[guard_arch] OK: 改动的 Vue 组件未新增内联金额计算。');
+ process.exit(0);
+}
+
+main();
diff --git a/YLErpWeb/fe-tests/numberInput.paste.test.js b/YLErpWeb/fe-tests/numberInput.paste.test.js
new file mode 100644
index 00000000..80eb942a
--- /dev/null
+++ b/YLErpWeb/fe-tests/numberInput.paste.test.js
@@ -0,0 +1,105 @@
+/**
+ * numberInput.paste.test.js — FastVue.numberInput 粘贴路径回归守卫
+ * ============================================================================
+ * 目的:防止 #EQD-5914 后新增的 `percent:true`+空 append 格式在粘贴时 ×100。
+ * 覆盖字段类型:percent、append:'%'、append:'‱'、普通数字。
+ *
+ * 运行:cd YLErpWeb/fe-tests && npm test -- numberInput.paste
+ */
+
+const { JSDOM } = require('jsdom');
+const dom = new JSDOM('');
+global.window = dom.window;
+global.document = dom.window.document;
+global.navigator = dom.window.navigator;
+
+// fastVue.base.js 内部多个 IIFE 通过全局 FastVue 共享;
+// 浏览器里 window.FastVue 与全局 FastVue 等价,Node 里需要桥接一下。
+Object.defineProperty(global, 'FastVue', {
+ get() { return global.window.FastVue; },
+ set(value) { global.window.FastVue = value; },
+ configurable: true
+});
+
+const $ = require('jquery');
+global.$ = $;
+global.jQuery = $;
+
+// fastVue.base.js 依赖全局 main.formatNumber
+global.main = {
+ formatNumber: function (number, precision, options) {
+ const n = Number(number);
+ if (Number.isNaN(n)) return '0';
+ const useGrouping = options && options.grouping;
+ if (useGrouping) {
+ return n.toLocaleString('en-US', { minimumFractionDigits: precision, maximumFractionDigits: precision });
+ }
+ return n.toFixed(precision);
+ }
+};
+
+require('../wwwroot/Scripts/fast/fastVue.base.js');
+
+function createInput() {
+ return document.createElement('input');
+}
+
+function simulatePaste(el, pastedText) {
+ el.value = pastedText;
+ // 先触发 keydown 让 _ctrlV=true(Ctrl+V 的 keyCode=86,ctrlKey=true)
+ const keydown = new window.KeyboardEvent('keydown', { keyCode: 86, ctrlKey: true, bubbles: true });
+ el.dispatchEvent(keydown);
+ // 再触发 input 事件
+ const input = new window.Event('input', { bubbles: true });
+ el.dispatchEvent(input);
+ // 最后触发 change 事件(浏览器在失焦或回车时触发;这里手动触发验证 onchange)
+ const change = new window.Event('change', { bubbles: true });
+ el.dispatchEvent(change);
+}
+
+describe('FastVue.numberInput 粘贴路径', () => {
+ test('percent:true + 空 append:粘贴 99.07 不应 ×100(债券净价 bug 场景)', () => {
+ const el = createInput();
+ const changes = [];
+ FastVue.numberInput(el, { precision: 4, percent: true, append: '', onchange: (v) => changes.push(v) });
+
+ simulatePaste(el, '99.0756');
+
+ expect(el.value).toBe('99.0756');
+ expect(changes.length).toBeGreaterThan(0);
+ expect(changes[changes.length - 1]).toBeCloseTo(0.990756, 8);
+ });
+
+ test('append:"%":粘贴 99.07% 应解析为 0.9907', () => {
+ const el = createInput();
+ const changes = [];
+ FastVue.numberInput(el, { precision: 2, append: '%', onchange: (v) => changes.push(v) });
+
+ simulatePaste(el, '99.07%');
+
+ expect(el.value).toBe('99.07%');
+ expect(changes[changes.length - 1]).toBeCloseTo(0.9907, 8);
+ });
+
+ test('append:"‱":粘贴 990.7‱ 应解析为 0.09907', () => {
+ const el = createInput();
+ const changes = [];
+ FastVue.numberInput(el, { precision: 4, append: '‱', onchange: (v) => changes.push(v) });
+
+ simulatePaste(el, '990.7‱');
+
+ expect(el.value).toBe('990.7‱');
+ expect(changes[changes.length - 1]).toBeCloseTo(0.09907, 8);
+ });
+
+ test('普通数字字段:粘贴 99.07 保持原值', () => {
+ const el = createInput();
+ const changes = [];
+ FastVue.numberInput(el, { precision: 2, onchange: (v) => changes.push(v) });
+
+ simulatePaste(el, '99.07');
+
+ expect(el.value).toBe('99.07');
+ expect(changes[changes.length - 1]).toBeCloseTo(99.07, 8);
+ });
+});
diff --git a/YLErpWeb/fe-tests/otcformat.test.js b/YLErpWeb/fe-tests/otcformat.test.js
new file mode 100644
index 00000000..03604a40
--- /dev/null
+++ b/YLErpWeb/fe-tests/otcformat.test.js
@@ -0,0 +1,50 @@
+/**
+ * otcformat.test.js — 守卫运行时配置 otcformat.js 的精度回归
+ * ============================================================================
+ * 背景:088df270 中 otcformat.js 的 precision 被 Revert 误从 9 改回 2,
+ * 导致"期末全价只能录 2 位小数"。该 bug 已复发 2 次,纯前端/后端测试都碰不到。
+ * 本测试直接解析 App_Data/Config/otcformat.js,断言关键字段 precision 不低于预期,
+ * 是 ROI 最高的单一守卫(零重构、1 个文件、无依赖)。
+ *
+ * 运行:cd YLErpWeb/fe-tests && npm i && npm test
+ */
+const fs = require('fs');
+const path = require('path');
+
+const cfgPath = path.resolve(__dirname, '../App_Data/Config/otcformat.js');
+const src = fs.readFileSync(cfgPath, 'utf8');
+
+// otcformat.js 形如 `var main = main || {}; main.formatOptions = {...};`
+// 在沙箱函数内求值并取出 main.formatOptions
+const formatOptions = new Function(src + '\n;return main.formatOptions;')();
+
+describe('otcformat.js 精度配置守卫 (088df270)', () => {
+ test('配置文件可被解析且含 trading 节点', () => {
+ expect(formatOptions).toBeDefined();
+ expect(formatOptions.trading).toBeDefined();
+ });
+
+ // 这些字段在 088df270 被误降到 2,必须保持 9(与当前全 precision=9 一致)
+ const mustBeNine = [
+ 'umprice', 'umpriceP', 'umpricePR',
+ 'tradeSinglePrice', 'tradePrice', 'StockEqvNotional', 'notional',
+ 'premiumRate', 'premiumRateP', 'volatility',
+ 'marginRate', 'marginRateP', 'greek'
+ ];
+
+ mustBeNine.forEach(function (key) {
+ test('trading.' + key + '.precision === 9', () => {
+ expect(formatOptions.trading[key]).toBeDefined();
+ expect(formatOptions.trading[key].precision).toBe(9);
+ });
+ });
+
+ test('所有 trading 数值字段 precision 均 >= 9(防再次误降)', () => {
+ Object.keys(formatOptions.trading).forEach(function (key) {
+ const opt = formatOptions.trading[key];
+ if (opt && typeof opt.precision === 'number') {
+ expect(opt.precision).toBeGreaterThanOrEqual(9);
+ }
+ });
+ });
+});
diff --git a/YLErpWeb/fe-tests/package-lock.json b/YLErpWeb/fe-tests/package-lock.json
new file mode 100644
index 00000000..5dbfcd44
--- /dev/null
+++ b/YLErpWeb/fe-tests/package-lock.json
@@ -0,0 +1,4681 @@
+{
+ "name": "zszq-trs-fe-tests",
+ "version": "1.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "zszq-trs-fe-tests",
+ "version": "1.0.0",
+ "devDependencies": {
+ "jest": "^29.7.0",
+ "jest-environment-jsdom": "^30.4.1",
+ "jquery": "^4.0.0"
+ }
+ },
+ "node_modules/@asamuzakjp/css-color": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmmirror.com/@asamuzakjp/css-color/-/css-color-3.2.0.tgz",
+ "integrity": "sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@csstools/css-calc": "^2.1.3",
+ "@csstools/css-color-parser": "^3.0.9",
+ "@csstools/css-parser-algorithms": "^3.0.4",
+ "@csstools/css-tokenizer": "^3.0.3",
+ "lru-cache": "^10.4.3"
+ }
+ },
+ "node_modules/@asamuzakjp/css-color/node_modules/lru-cache": {
+ "version": "10.4.3",
+ "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-10.4.3.tgz",
+ "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/@babel/code-frame": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmmirror.com/@babel/code-frame/-/code-frame-7.29.7.tgz",
+ "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-validator-identifier": "^7.29.7",
+ "js-tokens": "^4.0.0",
+ "picocolors": "^1.1.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/compat-data": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmmirror.com/@babel/compat-data/-/compat-data-7.29.7.tgz",
+ "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/core": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmmirror.com/@babel/core/-/core-7.29.7.tgz",
+ "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.29.7",
+ "@babel/generator": "^7.29.7",
+ "@babel/helper-compilation-targets": "^7.29.7",
+ "@babel/helper-module-transforms": "^7.29.7",
+ "@babel/helpers": "^7.29.7",
+ "@babel/parser": "^7.29.7",
+ "@babel/template": "^7.29.7",
+ "@babel/traverse": "^7.29.7",
+ "@babel/types": "^7.29.7",
+ "@jridgewell/remapping": "^2.3.5",
+ "convert-source-map": "^2.0.0",
+ "debug": "^4.1.0",
+ "gensync": "^1.0.0-beta.2",
+ "json5": "^2.2.3",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/babel"
+ }
+ },
+ "node_modules/@babel/generator": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmmirror.com/@babel/generator/-/generator-7.29.7.tgz",
+ "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.29.7",
+ "@babel/types": "^7.29.7",
+ "@jridgewell/gen-mapping": "^0.3.12",
+ "@jridgewell/trace-mapping": "^0.3.28",
+ "jsesc": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-compilation-targets": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmmirror.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz",
+ "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/compat-data": "^7.29.7",
+ "@babel/helper-validator-option": "^7.29.7",
+ "browserslist": "^4.24.0",
+ "lru-cache": "^5.1.1",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-globals": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmmirror.com/@babel/helper-globals/-/helper-globals-7.29.7.tgz",
+ "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-imports": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmmirror.com/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz",
+ "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/traverse": "^7.29.7",
+ "@babel/types": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-transforms": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmmirror.com/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz",
+ "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-module-imports": "^7.29.7",
+ "@babel/helper-validator-identifier": "^7.29.7",
+ "@babel/traverse": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/helper-plugin-utils": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmmirror.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz",
+ "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-string-parser": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz",
+ "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-identifier": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz",
+ "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-option": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmmirror.com/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz",
+ "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helpers": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmmirror.com/@babel/helpers/-/helpers-7.29.7.tgz",
+ "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/template": "^7.29.7",
+ "@babel/types": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/parser": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.29.7.tgz",
+ "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.29.7"
+ },
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-async-generators": {
+ "version": "7.8.4",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz",
+ "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==",
+ "dev": true,
+ "license": "MIT",
+ "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.npmmirror.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz",
+ "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==",
+ "dev": true,
+ "license": "MIT",
+ "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.npmmirror.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz",
+ "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==",
+ "dev": true,
+ "license": "MIT",
+ "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.npmmirror.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz",
+ "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==",
+ "dev": true,
+ "license": "MIT",
+ "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-import-attributes": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.29.7.tgz",
+ "integrity": "sha512-zGYcYfq/WmZ4V+kBIXQon9dSSc8ircGZqw9ZaNhhGj9nZkeBu1jHLBDQqYYi5WA9uawvA2sIMbry2nCFhf5Djg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.29.7"
+ },
+ "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.npmmirror.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz",
+ "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==",
+ "dev": true,
+ "license": "MIT",
+ "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.npmmirror.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz",
+ "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.8.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-jsx": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.29.7.tgz",
+ "integrity": "sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.29.7"
+ },
+ "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.npmmirror.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz",
+ "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==",
+ "dev": true,
+ "license": "MIT",
+ "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.npmmirror.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz",
+ "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==",
+ "dev": true,
+ "license": "MIT",
+ "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.npmmirror.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz",
+ "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==",
+ "dev": true,
+ "license": "MIT",
+ "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.npmmirror.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz",
+ "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==",
+ "dev": true,
+ "license": "MIT",
+ "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.npmmirror.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz",
+ "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==",
+ "dev": true,
+ "license": "MIT",
+ "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.npmmirror.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz",
+ "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==",
+ "dev": true,
+ "license": "MIT",
+ "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.npmmirror.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz",
+ "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==",
+ "dev": true,
+ "license": "MIT",
+ "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-top-level-await": {
+ "version": "7.14.5",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz",
+ "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==",
+ "dev": true,
+ "license": "MIT",
+ "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.29.7",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.29.7.tgz",
+ "integrity": "sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/template": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmmirror.com/@babel/template/-/template-7.29.7.tgz",
+ "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.29.7",
+ "@babel/parser": "^7.29.7",
+ "@babel/types": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/traverse": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmmirror.com/@babel/traverse/-/traverse-7.29.7.tgz",
+ "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.29.7",
+ "@babel/generator": "^7.29.7",
+ "@babel/helper-globals": "^7.29.7",
+ "@babel/parser": "^7.29.7",
+ "@babel/template": "^7.29.7",
+ "@babel/types": "^7.29.7",
+ "debug": "^4.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/types": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.29.7.tgz",
+ "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-string-parser": "^7.29.7",
+ "@babel/helper-validator-identifier": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@bcoe/v8-coverage": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmmirror.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz",
+ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@csstools/color-helpers": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmmirror.com/@csstools/color-helpers/-/color-helpers-5.1.0.tgz",
+ "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/csstools"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/csstools"
+ }
+ ],
+ "license": "MIT-0",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@csstools/css-calc": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmmirror.com/@csstools/css-calc/-/css-calc-2.1.4.tgz",
+ "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/csstools"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/csstools"
+ }
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@csstools/css-parser-algorithms": "^3.0.5",
+ "@csstools/css-tokenizer": "^3.0.4"
+ }
+ },
+ "node_modules/@csstools/css-color-parser": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmmirror.com/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz",
+ "integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/csstools"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/csstools"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "@csstools/color-helpers": "^5.1.0",
+ "@csstools/css-calc": "^2.1.4"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@csstools/css-parser-algorithms": "^3.0.5",
+ "@csstools/css-tokenizer": "^3.0.4"
+ }
+ },
+ "node_modules/@csstools/css-parser-algorithms": {
+ "version": "3.0.5",
+ "resolved": "https://registry.npmmirror.com/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz",
+ "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/csstools"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/csstools"
+ }
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@csstools/css-tokenizer": "^3.0.4"
+ }
+ },
+ "node_modules/@csstools/css-tokenizer": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmmirror.com/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz",
+ "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/csstools"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/csstools"
+ }
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@istanbuljs/load-nyc-config": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmmirror.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
+ "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==",
+ "dev": true,
+ "license": "ISC",
+ "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.6",
+ "resolved": "https://registry.npmmirror.com/@istanbuljs/schema/-/schema-0.1.6.tgz",
+ "integrity": "sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@jest/console": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmmirror.com/@jest/console/-/console-29.7.0.tgz",
+ "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/types": "^29.6.3",
+ "@types/node": "*",
+ "chalk": "^4.0.0",
+ "jest-message-util": "^29.7.0",
+ "jest-util": "^29.7.0",
+ "slash": "^3.0.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/@jest/core": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmmirror.com/@jest/core/-/core-29.7.0.tgz",
+ "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/console": "^29.7.0",
+ "@jest/reporters": "^29.7.0",
+ "@jest/test-result": "^29.7.0",
+ "@jest/transform": "^29.7.0",
+ "@jest/types": "^29.6.3",
+ "@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.7.0",
+ "jest-config": "^29.7.0",
+ "jest-haste-map": "^29.7.0",
+ "jest-message-util": "^29.7.0",
+ "jest-regex-util": "^29.6.3",
+ "jest-resolve": "^29.7.0",
+ "jest-resolve-dependencies": "^29.7.0",
+ "jest-runner": "^29.7.0",
+ "jest-runtime": "^29.7.0",
+ "jest-snapshot": "^29.7.0",
+ "jest-util": "^29.7.0",
+ "jest-validate": "^29.7.0",
+ "jest-watcher": "^29.7.0",
+ "micromatch": "^4.0.4",
+ "pretty-format": "^29.7.0",
+ "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/environment": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmmirror.com/@jest/environment/-/environment-29.7.0.tgz",
+ "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/fake-timers": "^29.7.0",
+ "@jest/types": "^29.6.3",
+ "@types/node": "*",
+ "jest-mock": "^29.7.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/@jest/environment-jsdom-abstract": {
+ "version": "30.4.1",
+ "resolved": "https://registry.npmmirror.com/@jest/environment-jsdom-abstract/-/environment-jsdom-abstract-30.4.1.tgz",
+ "integrity": "sha512-dSlKrqug3siYNHVnjwIldShY12wAH3spwRltO/+8VOjg0X+xEq7vOs3DbBs4LRKsu7OH+NUb9kuZUNBF9Ho3TA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/environment": "30.4.1",
+ "@jest/fake-timers": "30.4.1",
+ "@jest/types": "30.4.1",
+ "@types/jsdom": "^21.1.7",
+ "@types/node": "*",
+ "jest-mock": "30.4.1",
+ "jest-util": "30.4.1"
+ },
+ "engines": {
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
+ },
+ "peerDependencies": {
+ "canvas": "^3.0.0",
+ "jsdom": "*"
+ },
+ "peerDependenciesMeta": {
+ "canvas": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@jest/environment-jsdom-abstract/node_modules/@jest/environment": {
+ "version": "30.4.1",
+ "resolved": "https://registry.npmmirror.com/@jest/environment/-/environment-30.4.1.tgz",
+ "integrity": "sha512-AK9yNRqgKxiabqMoe4oW+3/TSSeV8vkdC7BGaxZdU0AFXfOpofTLqdru2GXKZghP3sdgwE9XXpnVwfZ8JnFV4w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/fake-timers": "30.4.1",
+ "@jest/types": "30.4.1",
+ "@types/node": "*",
+ "jest-mock": "30.4.1"
+ },
+ "engines": {
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
+ }
+ },
+ "node_modules/@jest/environment-jsdom-abstract/node_modules/@jest/fake-timers": {
+ "version": "30.4.1",
+ "resolved": "https://registry.npmmirror.com/@jest/fake-timers/-/fake-timers-30.4.1.tgz",
+ "integrity": "sha512-iW5umdmfPeWzehrVhugFQZqCchSCud5S1l2YT0O9ZhjRR0ExclANDZkiSBwzqtnlOn0J1JXvO+HZ6rkuyOVOgQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/types": "30.4.1",
+ "@sinonjs/fake-timers": "^15.4.0",
+ "@types/node": "*",
+ "jest-message-util": "30.4.1",
+ "jest-mock": "30.4.1",
+ "jest-util": "30.4.1"
+ },
+ "engines": {
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
+ }
+ },
+ "node_modules/@jest/environment-jsdom-abstract/node_modules/@jest/schemas": {
+ "version": "30.4.1",
+ "resolved": "https://registry.npmmirror.com/@jest/schemas/-/schemas-30.4.1.tgz",
+ "integrity": "sha512-i6b4qw5qnP8c5FEeBJg/uZQ4ddrkN6Ca8qISJh0pr7a5hfn3h3v5x60BEbOC7OYAGZNMs1LfFLwnW2CuK8F57Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@sinclair/typebox": "^0.34.0"
+ },
+ "engines": {
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
+ }
+ },
+ "node_modules/@jest/environment-jsdom-abstract/node_modules/@jest/types": {
+ "version": "30.4.1",
+ "resolved": "https://registry.npmmirror.com/@jest/types/-/types-30.4.1.tgz",
+ "integrity": "sha512-f1x/vJXIfjOlEmejYpbkbgw1gOqpPECwMvMEtBqe47j7H2Hg8h8w3o3ikhSXq3MI15kg+oQ0exWO0uCtTNJLoQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/pattern": "30.4.0",
+ "@jest/schemas": "30.4.1",
+ "@types/istanbul-lib-coverage": "^2.0.6",
+ "@types/istanbul-reports": "^3.0.4",
+ "@types/node": "*",
+ "@types/yargs": "^17.0.33",
+ "chalk": "^4.1.2"
+ },
+ "engines": {
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
+ }
+ },
+ "node_modules/@jest/environment-jsdom-abstract/node_modules/@sinclair/typebox": {
+ "version": "0.34.52",
+ "resolved": "https://registry.npmmirror.com/@sinclair/typebox/-/typebox-0.34.52.tgz",
+ "integrity": "sha512-XiMQh7qqVlxZzcVD+kkGMNGMzcTrDMLWI7S4x7z1MkCkbDPrekpZXEUK0eZqZFMuHQg2a2DZOcDIh9o5v3Gonw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@jest/environment-jsdom-abstract/node_modules/@sinonjs/fake-timers": {
+ "version": "15.4.0",
+ "resolved": "https://registry.npmmirror.com/@sinonjs/fake-timers/-/fake-timers-15.4.0.tgz",
+ "integrity": "sha512-DsG+8/LscQIQg68J6Ef3dv10u6nVyetYn923s3/sus5eaGfTo1of5WMZSLf0UJc9KDuKPilPH0UDJCjvNbDNCA==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "@sinonjs/commons": "^3.0.1"
+ }
+ },
+ "node_modules/@jest/environment-jsdom-abstract/node_modules/ansi-styles": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-5.2.0.tgz",
+ "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/@jest/environment-jsdom-abstract/node_modules/ci-info": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmmirror.com/ci-info/-/ci-info-4.4.0.tgz",
+ "integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/sibiraj-s"
+ }
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@jest/environment-jsdom-abstract/node_modules/jest-message-util": {
+ "version": "30.4.1",
+ "resolved": "https://registry.npmmirror.com/jest-message-util/-/jest-message-util-30.4.1.tgz",
+ "integrity": "sha512-kwCKIvq0MCW1HzLoGola9Te6JUdzgV0loyKJ3Qghrkz9i5/RRIHsL95BMQc2HBBhlBKC4j22K9p11TGHH8RBpQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.27.1",
+ "@jest/types": "30.4.1",
+ "@types/stack-utils": "^2.0.3",
+ "chalk": "^4.1.2",
+ "graceful-fs": "^4.2.11",
+ "jest-util": "30.4.1",
+ "picomatch": "^4.0.3",
+ "pretty-format": "30.4.1",
+ "slash": "^3.0.0",
+ "stack-utils": "^2.0.6"
+ },
+ "engines": {
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
+ }
+ },
+ "node_modules/@jest/environment-jsdom-abstract/node_modules/jest-mock": {
+ "version": "30.4.1",
+ "resolved": "https://registry.npmmirror.com/jest-mock/-/jest-mock-30.4.1.tgz",
+ "integrity": "sha512-/i8SVb8/NSB7RfNi8gfqu8gxLV23KaL5EpAttyb9iz8qWRIqXRLflycz/32wXsYkOnaUlx8NAKnJYtpsmXUmfw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/types": "30.4.1",
+ "@types/node": "*",
+ "jest-util": "30.4.1"
+ },
+ "engines": {
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
+ }
+ },
+ "node_modules/@jest/environment-jsdom-abstract/node_modules/jest-util": {
+ "version": "30.4.1",
+ "resolved": "https://registry.npmmirror.com/jest-util/-/jest-util-30.4.1.tgz",
+ "integrity": "sha512-vjQb1sACEiv13DKJMDToJpzVW0joCsIQrmbg0fi7CyOOt+g9jTuQl2A216pWRBYhOVt53XbL/2LbMKg1BECWOw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/types": "30.4.1",
+ "@types/node": "*",
+ "chalk": "^4.1.2",
+ "ci-info": "^4.2.0",
+ "graceful-fs": "^4.2.11",
+ "picomatch": "^4.0.3"
+ },
+ "engines": {
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
+ }
+ },
+ "node_modules/@jest/environment-jsdom-abstract/node_modules/picomatch": {
+ "version": "4.0.5",
+ "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.5.tgz",
+ "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/@jest/environment-jsdom-abstract/node_modules/pretty-format": {
+ "version": "30.4.1",
+ "resolved": "https://registry.npmmirror.com/pretty-format/-/pretty-format-30.4.1.tgz",
+ "integrity": "sha512-K6KiKMHTL4jjX4u3Kir2EW07nRfcqVTXIImx50wbjHQTcZPgg+gjVeNTIT3l3L1Rd4UefxfogquC9J37SoFyyw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/schemas": "30.4.1",
+ "ansi-styles": "^5.2.0",
+ "react-is-18": "npm:react-is@^18.3.1",
+ "react-is-19": "npm:react-is@^19.2.5"
+ },
+ "engines": {
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
+ }
+ },
+ "node_modules/@jest/expect": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmmirror.com/@jest/expect/-/expect-29.7.0.tgz",
+ "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "expect": "^29.7.0",
+ "jest-snapshot": "^29.7.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/@jest/expect-utils": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmmirror.com/@jest/expect-utils/-/expect-utils-29.7.0.tgz",
+ "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "jest-get-type": "^29.6.3"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/@jest/fake-timers": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmmirror.com/@jest/fake-timers/-/fake-timers-29.7.0.tgz",
+ "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/types": "^29.6.3",
+ "@sinonjs/fake-timers": "^10.0.2",
+ "@types/node": "*",
+ "jest-message-util": "^29.7.0",
+ "jest-mock": "^29.7.0",
+ "jest-util": "^29.7.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/@jest/globals": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmmirror.com/@jest/globals/-/globals-29.7.0.tgz",
+ "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/environment": "^29.7.0",
+ "@jest/expect": "^29.7.0",
+ "@jest/types": "^29.6.3",
+ "jest-mock": "^29.7.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/@jest/pattern": {
+ "version": "30.4.0",
+ "resolved": "https://registry.npmmirror.com/@jest/pattern/-/pattern-30.4.0.tgz",
+ "integrity": "sha512-RAWn3+f9u8BsHijKJ71uHcFp6vmyEt6VvoWXkl6hKF3qVIuWNmudVjg12DlBPGup/frIl5UcUlH5HfEuvHpEXg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*",
+ "jest-regex-util": "30.4.0"
+ },
+ "engines": {
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
+ }
+ },
+ "node_modules/@jest/pattern/node_modules/jest-regex-util": {
+ "version": "30.4.0",
+ "resolved": "https://registry.npmmirror.com/jest-regex-util/-/jest-regex-util-30.4.0.tgz",
+ "integrity": "sha512-mWlvLviKIgIQ8VCuM1xRdD0TWp3zlzionlmDBjuXVBs+VkmXq6FgW9T4Emr7oGz/Rk6feDCGyiugolcQEyp3mg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
+ }
+ },
+ "node_modules/@jest/reporters": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmmirror.com/@jest/reporters/-/reporters-29.7.0.tgz",
+ "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@bcoe/v8-coverage": "^0.2.3",
+ "@jest/console": "^29.7.0",
+ "@jest/test-result": "^29.7.0",
+ "@jest/transform": "^29.7.0",
+ "@jest/types": "^29.6.3",
+ "@jridgewell/trace-mapping": "^0.3.18",
+ "@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": "^6.0.0",
+ "istanbul-lib-report": "^3.0.0",
+ "istanbul-lib-source-maps": "^4.0.0",
+ "istanbul-reports": "^3.1.3",
+ "jest-message-util": "^29.7.0",
+ "jest-util": "^29.7.0",
+ "jest-worker": "^29.7.0",
+ "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/schemas": {
+ "version": "29.6.3",
+ "resolved": "https://registry.npmmirror.com/@jest/schemas/-/schemas-29.6.3.tgz",
+ "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@sinclair/typebox": "^0.27.8"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/@jest/source-map": {
+ "version": "29.6.3",
+ "resolved": "https://registry.npmmirror.com/@jest/source-map/-/source-map-29.6.3.tgz",
+ "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/trace-mapping": "^0.3.18",
+ "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.7.0",
+ "resolved": "https://registry.npmmirror.com/@jest/test-result/-/test-result-29.7.0.tgz",
+ "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/console": "^29.7.0",
+ "@jest/types": "^29.6.3",
+ "@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.7.0",
+ "resolved": "https://registry.npmmirror.com/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz",
+ "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/test-result": "^29.7.0",
+ "graceful-fs": "^4.2.9",
+ "jest-haste-map": "^29.7.0",
+ "slash": "^3.0.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/@jest/transform": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmmirror.com/@jest/transform/-/transform-29.7.0.tgz",
+ "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/core": "^7.11.6",
+ "@jest/types": "^29.6.3",
+ "@jridgewell/trace-mapping": "^0.3.18",
+ "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.7.0",
+ "jest-regex-util": "^29.6.3",
+ "jest-util": "^29.7.0",
+ "micromatch": "^4.0.4",
+ "pirates": "^4.0.4",
+ "slash": "^3.0.0",
+ "write-file-atomic": "^4.0.2"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/@jest/types": {
+ "version": "29.6.3",
+ "resolved": "https://registry.npmmirror.com/@jest/types/-/types-29.6.3.tgz",
+ "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/schemas": "^29.6.3",
+ "@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/@jridgewell/gen-mapping": {
+ "version": "0.3.13",
+ "resolved": "https://registry.npmmirror.com/@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/remapping": {
+ "version": "2.3.5",
+ "resolved": "https://registry.npmmirror.com/@jridgewell/remapping/-/remapping-2.3.5.tgz",
+ "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ }
+ },
+ "node_modules/@jridgewell/resolve-uri": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmmirror.com/@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.npmmirror.com/@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.npmmirror.com/@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/@sinclair/typebox": {
+ "version": "0.27.10",
+ "resolved": "https://registry.npmmirror.com/@sinclair/typebox/-/typebox-0.27.10.tgz",
+ "integrity": "sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@sinonjs/commons": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmmirror.com/@sinonjs/commons/-/commons-3.0.1.tgz",
+ "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "type-detect": "4.0.8"
+ }
+ },
+ "node_modules/@sinonjs/fake-timers": {
+ "version": "10.3.0",
+ "resolved": "https://registry.npmmirror.com/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz",
+ "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "@sinonjs/commons": "^3.0.0"
+ }
+ },
+ "node_modules/@types/babel__core": {
+ "version": "7.20.5",
+ "resolved": "https://registry.npmmirror.com/@types/babel__core/-/babel__core-7.20.5.tgz",
+ "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.20.7",
+ "@babel/types": "^7.20.7",
+ "@types/babel__generator": "*",
+ "@types/babel__template": "*",
+ "@types/babel__traverse": "*"
+ }
+ },
+ "node_modules/@types/babel__generator": {
+ "version": "7.27.0",
+ "resolved": "https://registry.npmmirror.com/@types/babel__generator/-/babel__generator-7.27.0.tgz",
+ "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "node_modules/@types/babel__template": {
+ "version": "7.4.4",
+ "resolved": "https://registry.npmmirror.com/@types/babel__template/-/babel__template-7.4.4.tgz",
+ "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.1.0",
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "node_modules/@types/babel__traverse": {
+ "version": "7.28.0",
+ "resolved": "https://registry.npmmirror.com/@types/babel__traverse/-/babel__traverse-7.28.0.tgz",
+ "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.28.2"
+ }
+ },
+ "node_modules/@types/graceful-fs": {
+ "version": "4.1.9",
+ "resolved": "https://registry.npmmirror.com/@types/graceful-fs/-/graceful-fs-4.1.9.tgz",
+ "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/istanbul-lib-coverage": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmmirror.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz",
+ "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/istanbul-lib-report": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmmirror.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz",
+ "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/istanbul-lib-coverage": "*"
+ }
+ },
+ "node_modules/@types/istanbul-reports": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmmirror.com/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz",
+ "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/istanbul-lib-report": "*"
+ }
+ },
+ "node_modules/@types/jsdom": {
+ "version": "21.1.7",
+ "resolved": "https://registry.npmmirror.com/@types/jsdom/-/jsdom-21.1.7.tgz",
+ "integrity": "sha512-yOriVnggzrnQ3a9OKOCxaVuSug3w3/SbOj5i7VwXWZEyUNl3bLF9V3MfxGbZKuwqJOQyRfqXyROBB1CoZLFWzA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*",
+ "@types/tough-cookie": "*",
+ "parse5": "^7.0.0"
+ }
+ },
+ "node_modules/@types/node": {
+ "version": "26.1.1",
+ "resolved": "https://registry.npmmirror.com/@types/node/-/node-26.1.1.tgz",
+ "integrity": "sha512-nxAkRSVkN1Y0JC1W8ky/fTfkGsMmcrRsbx+3XoZE+rMOX71kLYTV7fLXpqud1GpbpP5TuffXFqfX7fH2GgZREw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~8.3.0"
+ }
+ },
+ "node_modules/@types/stack-utils": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmmirror.com/@types/stack-utils/-/stack-utils-2.0.3.tgz",
+ "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/tough-cookie": {
+ "version": "4.0.5",
+ "resolved": "https://registry.npmmirror.com/@types/tough-cookie/-/tough-cookie-4.0.5.tgz",
+ "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/yargs": {
+ "version": "17.0.35",
+ "resolved": "https://registry.npmmirror.com/@types/yargs/-/yargs-17.0.35.tgz",
+ "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/yargs-parser": "*"
+ }
+ },
+ "node_modules/@types/yargs-parser": {
+ "version": "21.0.3",
+ "resolved": "https://registry.npmmirror.com/@types/yargs-parser/-/yargs-parser-21.0.3.tgz",
+ "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/agent-base": {
+ "version": "7.1.4",
+ "resolved": "https://registry.npmmirror.com/agent-base/-/agent-base-7.1.4.tgz",
+ "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/ansi-escapes": {
+ "version": "4.3.2",
+ "resolved": "https://registry.npmmirror.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
+ "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==",
+ "dev": true,
+ "license": "MIT",
+ "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.npmmirror.com/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmmirror.com/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/anymatch": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmmirror.com/anymatch/-/anymatch-3.1.3.tgz",
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/argparse": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmmirror.com/argparse/-/argparse-1.0.10.tgz",
+ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "sprintf-js": "~1.0.2"
+ }
+ },
+ "node_modules/babel-jest": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmmirror.com/babel-jest/-/babel-jest-29.7.0.tgz",
+ "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/transform": "^29.7.0",
+ "@types/babel__core": "^7.1.14",
+ "babel-plugin-istanbul": "^6.1.1",
+ "babel-preset-jest": "^29.6.3",
+ "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-plugin-istanbul": {
+ "version": "6.1.1",
+ "resolved": "https://registry.npmmirror.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz",
+ "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "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-istanbul/node_modules/istanbul-lib-instrument": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmmirror.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz",
+ "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "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/babel-plugin-jest-hoist": {
+ "version": "29.6.3",
+ "resolved": "https://registry.npmmirror.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz",
+ "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==",
+ "dev": true,
+ "license": "MIT",
+ "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-preset-current-node-syntax": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmmirror.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz",
+ "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/plugin-syntax-async-generators": "^7.8.4",
+ "@babel/plugin-syntax-bigint": "^7.8.3",
+ "@babel/plugin-syntax-class-properties": "^7.12.13",
+ "@babel/plugin-syntax-class-static-block": "^7.14.5",
+ "@babel/plugin-syntax-import-attributes": "^7.24.7",
+ "@babel/plugin-syntax-import-meta": "^7.10.4",
+ "@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"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0 || ^8.0.0-0"
+ }
+ },
+ "node_modules/babel-preset-jest": {
+ "version": "29.6.3",
+ "resolved": "https://registry.npmmirror.com/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz",
+ "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "babel-plugin-jest-hoist": "^29.6.3",
+ "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.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/baseline-browser-mapping": {
+ "version": "2.10.43",
+ "resolved": "https://registry.npmmirror.com/baseline-browser-mapping/-/baseline-browser-mapping-2.10.43.tgz",
+ "integrity": "sha512-AjYpR78kDWAY3Efj+cDTFH9t9SCoL7OoTp1BOb0mQV7S+6CiLwnWM3FyxhJtdPufDFKzmCSFoUncKjWgJEZTCQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "baseline-browser-mapping": "dist/cli.cjs"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/brace-expansion": {
+ "version": "1.1.16",
+ "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.16.tgz",
+ "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/braces": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmmirror.com/braces/-/braces-3.0.3.tgz",
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fill-range": "^7.1.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/browserslist": {
+ "version": "4.28.6",
+ "resolved": "https://registry.npmmirror.com/browserslist/-/browserslist-4.28.6.tgz",
+ "integrity": "sha512-FQBYNK15VMslhLHpA7+n+n1GOlF1kId2xcCg7/j95f24AOF6VDYMNH4mFxF7KuaTdv627faazpOAjFzMrfJOUw==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "baseline-browser-mapping": "^2.10.42",
+ "caniuse-lite": "^1.0.30001803",
+ "electron-to-chromium": "^1.5.389",
+ "node-releases": "^2.0.51",
+ "update-browserslist-db": "^1.2.3"
+ },
+ "bin": {
+ "browserslist": "cli.js"
+ },
+ "engines": {
+ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+ }
+ },
+ "node_modules/bser": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmmirror.com/bser/-/bser-2.1.1.tgz",
+ "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "node-int64": "^0.4.0"
+ }
+ },
+ "node_modules/buffer-from": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmmirror.com/buffer-from/-/buffer-from-1.1.2.tgz",
+ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/callsites": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmmirror.com/callsites/-/callsites-3.1.0.tgz",
+ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/camelcase": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmmirror.com/camelcase/-/camelcase-5.3.1.tgz",
+ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/caniuse-lite": {
+ "version": "1.0.30001805",
+ "resolved": "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001805.tgz",
+ "integrity": "sha512-52noaS3DubycKSXaU30TwPGIp+POyQSUVa5jBEq3vkRkY0kjyb3LQgvhU6WGyCcyXqVLWO0Cw0Q6BSdD0kUfVA==",
+ "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"
+ }
+ ],
+ "license": "CC-BY-4.0"
+ },
+ "node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "license": "MIT",
+ "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/char-regex": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmmirror.com/char-regex/-/char-regex-1.0.2.tgz",
+ "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/ci-info": {
+ "version": "3.9.0",
+ "resolved": "https://registry.npmmirror.com/ci-info/-/ci-info-3.9.0.tgz",
+ "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/sibiraj-s"
+ }
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/cjs-module-lexer": {
+ "version": "1.4.3",
+ "resolved": "https://registry.npmmirror.com/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz",
+ "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/cliui": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmmirror.com/cliui/-/cliui-8.0.1.tgz",
+ "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.1",
+ "wrap-ansi": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/co": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmmirror.com/co/-/co-4.6.0.tgz",
+ "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "iojs": ">= 1.0.0",
+ "node": ">= 0.12.0"
+ }
+ },
+ "node_modules/collect-v8-coverage": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmmirror.com/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz",
+ "integrity": "sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmmirror.com/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.npmmirror.com/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmmirror.com/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/convert-source-map": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmmirror.com/convert-source-map/-/convert-source-map-2.0.0.tgz",
+ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/create-jest": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmmirror.com/create-jest/-/create-jest-29.7.0.tgz",
+ "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/types": "^29.6.3",
+ "chalk": "^4.0.0",
+ "exit": "^0.1.2",
+ "graceful-fs": "^4.2.9",
+ "jest-config": "^29.7.0",
+ "jest-util": "^29.7.0",
+ "prompts": "^2.0.1"
+ },
+ "bin": {
+ "create-jest": "bin/create-jest.js"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/cross-spawn": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmmirror.com/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/cssstyle": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmmirror.com/cssstyle/-/cssstyle-4.6.0.tgz",
+ "integrity": "sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@asamuzakjp/css-color": "^3.2.0",
+ "rrweb-cssom": "^0.8.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/data-urls": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmmirror.com/data-urls/-/data-urls-5.0.0.tgz",
+ "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "whatwg-mimetype": "^4.0.0",
+ "whatwg-url": "^14.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/debug": {
+ "version": "4.4.3",
+ "resolved": "https://registry.npmmirror.com/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/decimal.js": {
+ "version": "10.6.0",
+ "resolved": "https://registry.npmmirror.com/decimal.js/-/decimal.js-10.6.0.tgz",
+ "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/dedent": {
+ "version": "1.7.2",
+ "resolved": "https://registry.npmmirror.com/dedent/-/dedent-1.7.2.tgz",
+ "integrity": "sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "babel-plugin-macros": "^3.1.0"
+ },
+ "peerDependenciesMeta": {
+ "babel-plugin-macros": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/deepmerge": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmmirror.com/deepmerge/-/deepmerge-4.3.1.tgz",
+ "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/detect-newline": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmmirror.com/detect-newline/-/detect-newline-3.1.0.tgz",
+ "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/diff-sequences": {
+ "version": "29.6.3",
+ "resolved": "https://registry.npmmirror.com/diff-sequences/-/diff-sequences-29.6.3.tgz",
+ "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/electron-to-chromium": {
+ "version": "1.5.391",
+ "resolved": "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.5.391.tgz",
+ "integrity": "sha512-YmCu4856jkgKT1Nh6fwRdeVrM6Ydf/fBnq51tpmSfX+jOcUMTxh31yH6hjKScRenhB2oDSvA9oooxcpjogPeig==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/emittery": {
+ "version": "0.13.1",
+ "resolved": "https://registry.npmmirror.com/emittery/-/emittery-0.13.1.tgz",
+ "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sindresorhus/emittery?sponsor=1"
+ }
+ },
+ "node_modules/emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/entities": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmmirror.com/entities/-/entities-6.0.1.tgz",
+ "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
+ "node_modules/error-ex": {
+ "version": "1.3.4",
+ "resolved": "https://registry.npmmirror.com/error-ex/-/error-ex-1.3.4.tgz",
+ "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-arrayish": "^0.2.1"
+ }
+ },
+ "node_modules/es-errors": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmmirror.com/es-errors/-/es-errors-1.3.0.tgz",
+ "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/escalade": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmmirror.com/escalade/-/escalade-3.2.0.tgz",
+ "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/escape-string-regexp": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz",
+ "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/esprima": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmmirror.com/esprima/-/esprima-4.0.1.tgz",
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "bin": {
+ "esparse": "bin/esparse.js",
+ "esvalidate": "bin/esvalidate.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/execa": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmmirror.com/execa/-/execa-5.1.1.tgz",
+ "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==",
+ "dev": true,
+ "license": "MIT",
+ "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.npmmirror.com/exit/-/exit-0.1.2.tgz",
+ "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/expect": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmmirror.com/expect/-/expect-29.7.0.tgz",
+ "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/expect-utils": "^29.7.0",
+ "jest-get-type": "^29.6.3",
+ "jest-matcher-utils": "^29.7.0",
+ "jest-message-util": "^29.7.0",
+ "jest-util": "^29.7.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/fast-json-stable-stringify": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmmirror.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/fb-watchman": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmmirror.com/fb-watchman/-/fb-watchman-2.0.2.tgz",
+ "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "bser": "2.1.1"
+ }
+ },
+ "node_modules/fill-range": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmmirror.com/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/find-up": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmmirror.com/find-up/-/find-up-4.1.0.tgz",
+ "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "locate-path": "^5.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmmirror.com/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmmirror.com/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/function-bind": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz",
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/gensync": {
+ "version": "1.0.0-beta.2",
+ "resolved": "https://registry.npmmirror.com/gensync/-/gensync-1.0.0-beta.2.tgz",
+ "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/get-caller-file": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmmirror.com/get-caller-file/-/get-caller-file-2.0.5.tgz",
+ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": "6.* || 8.* || >= 10.*"
+ }
+ },
+ "node_modules/get-package-type": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmmirror.com/get-package-type/-/get-package-type-0.1.0.tgz",
+ "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/get-stream": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmmirror.com/get-stream/-/get-stream-6.0.1.tgz",
+ "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/glob": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmmirror.com/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+ "deprecated": "Glob versions prior to v9 are no longer supported",
+ "dev": true,
+ "license": "ISC",
+ "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/graceful-fs": {
+ "version": "4.2.11",
+ "resolved": "https://registry.npmmirror.com/graceful-fs/-/graceful-fs-4.2.11.tgz",
+ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/hasown": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmmirror.com/hasown/-/hasown-2.0.4.tgz",
+ "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/html-encoding-sniffer": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmmirror.com/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz",
+ "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "whatwg-encoding": "^3.1.1"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/html-escaper": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmmirror.com/html-escaper/-/html-escaper-2.0.2.tgz",
+ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/http-proxy-agent": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmmirror.com/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
+ "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "agent-base": "^7.1.0",
+ "debug": "^4.3.4"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/https-proxy-agent": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmmirror.com/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
+ "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "agent-base": "^7.1.2",
+ "debug": "4"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/human-signals": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmmirror.com/human-signals/-/human-signals-2.1.0.tgz",
+ "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=10.17.0"
+ }
+ },
+ "node_modules/iconv-lite": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.6.3.tgz",
+ "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/import-local": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmmirror.com/import-local/-/import-local-3.2.0.tgz",
+ "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==",
+ "dev": true,
+ "license": "MIT",
+ "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/imurmurhash": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmmirror.com/imurmurhash/-/imurmurhash-0.1.4.tgz",
+ "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8.19"
+ }
+ },
+ "node_modules/inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmmirror.com/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+ "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/is-arrayish": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmmirror.com/is-arrayish/-/is-arrayish-0.2.1.tgz",
+ "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/is-core-module": {
+ "version": "2.16.2",
+ "resolved": "https://registry.npmmirror.com/is-core-module/-/is-core-module-2.16.2.tgz",
+ "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "hasown": "^2.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmmirror.com/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/is-generator-fn": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmmirror.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz",
+ "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmmirror.com/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/is-potential-custom-element-name": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmmirror.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz",
+ "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/is-stream": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmmirror.com/is-stream/-/is-stream-2.0.1.tgz",
+ "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmmirror.com/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.npmmirror.com/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-instrument": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmmirror.com/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz",
+ "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "@babel/core": "^7.23.9",
+ "@babel/parser": "^7.23.9",
+ "@istanbuljs/schema": "^0.1.3",
+ "istanbul-lib-coverage": "^3.2.0",
+ "semver": "^7.5.4"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/istanbul-lib-instrument/node_modules/semver": {
+ "version": "7.8.5",
+ "resolved": "https://registry.npmmirror.com/semver/-/semver-7.8.5.tgz",
+ "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/istanbul-lib-report": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmmirror.com/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": "4.0.1",
+ "resolved": "https://registry.npmmirror.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz",
+ "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "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.2.0",
+ "resolved": "https://registry.npmmirror.com/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/jest": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmmirror.com/jest/-/jest-29.7.0.tgz",
+ "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/core": "^29.7.0",
+ "@jest/types": "^29.6.3",
+ "import-local": "^3.0.2",
+ "jest-cli": "^29.7.0"
+ },
+ "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.7.0",
+ "resolved": "https://registry.npmmirror.com/jest-changed-files/-/jest-changed-files-29.7.0.tgz",
+ "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "execa": "^5.0.0",
+ "jest-util": "^29.7.0",
+ "p-limit": "^3.1.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-circus": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmmirror.com/jest-circus/-/jest-circus-29.7.0.tgz",
+ "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/environment": "^29.7.0",
+ "@jest/expect": "^29.7.0",
+ "@jest/test-result": "^29.7.0",
+ "@jest/types": "^29.6.3",
+ "@types/node": "*",
+ "chalk": "^4.0.0",
+ "co": "^4.6.0",
+ "dedent": "^1.0.0",
+ "is-generator-fn": "^2.0.0",
+ "jest-each": "^29.7.0",
+ "jest-matcher-utils": "^29.7.0",
+ "jest-message-util": "^29.7.0",
+ "jest-runtime": "^29.7.0",
+ "jest-snapshot": "^29.7.0",
+ "jest-util": "^29.7.0",
+ "p-limit": "^3.1.0",
+ "pretty-format": "^29.7.0",
+ "pure-rand": "^6.0.0",
+ "slash": "^3.0.0",
+ "stack-utils": "^2.0.3"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-cli": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmmirror.com/jest-cli/-/jest-cli-29.7.0.tgz",
+ "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/core": "^29.7.0",
+ "@jest/test-result": "^29.7.0",
+ "@jest/types": "^29.6.3",
+ "chalk": "^4.0.0",
+ "create-jest": "^29.7.0",
+ "exit": "^0.1.2",
+ "import-local": "^3.0.2",
+ "jest-config": "^29.7.0",
+ "jest-util": "^29.7.0",
+ "jest-validate": "^29.7.0",
+ "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-config": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmmirror.com/jest-config/-/jest-config-29.7.0.tgz",
+ "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/core": "^7.11.6",
+ "@jest/test-sequencer": "^29.7.0",
+ "@jest/types": "^29.6.3",
+ "babel-jest": "^29.7.0",
+ "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.7.0",
+ "jest-environment-node": "^29.7.0",
+ "jest-get-type": "^29.6.3",
+ "jest-regex-util": "^29.6.3",
+ "jest-resolve": "^29.7.0",
+ "jest-runner": "^29.7.0",
+ "jest-util": "^29.7.0",
+ "jest-validate": "^29.7.0",
+ "micromatch": "^4.0.4",
+ "parse-json": "^5.2.0",
+ "pretty-format": "^29.7.0",
+ "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-diff": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmmirror.com/jest-diff/-/jest-diff-29.7.0.tgz",
+ "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "chalk": "^4.0.0",
+ "diff-sequences": "^29.6.3",
+ "jest-get-type": "^29.6.3",
+ "pretty-format": "^29.7.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-docblock": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmmirror.com/jest-docblock/-/jest-docblock-29.7.0.tgz",
+ "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "detect-newline": "^3.0.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-each": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmmirror.com/jest-each/-/jest-each-29.7.0.tgz",
+ "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/types": "^29.6.3",
+ "chalk": "^4.0.0",
+ "jest-get-type": "^29.6.3",
+ "jest-util": "^29.7.0",
+ "pretty-format": "^29.7.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-environment-jsdom": {
+ "version": "30.4.1",
+ "resolved": "https://registry.npmmirror.com/jest-environment-jsdom/-/jest-environment-jsdom-30.4.1.tgz",
+ "integrity": "sha512-o3nfaN4zej7qgk2X0j8Jhq/S9nAVKs2xK3QeQxeHVvpkEPxaA1yxDGydR+iVI7zPy7Cp62Aq2h3Ja46QvfWHGA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/environment": "30.4.1",
+ "@jest/environment-jsdom-abstract": "30.4.1",
+ "jsdom": "^26.1.0"
+ },
+ "engines": {
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
+ },
+ "peerDependencies": {
+ "canvas": "^3.0.0"
+ },
+ "peerDependenciesMeta": {
+ "canvas": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/jest-environment-jsdom/node_modules/@jest/environment": {
+ "version": "30.4.1",
+ "resolved": "https://registry.npmmirror.com/@jest/environment/-/environment-30.4.1.tgz",
+ "integrity": "sha512-AK9yNRqgKxiabqMoe4oW+3/TSSeV8vkdC7BGaxZdU0AFXfOpofTLqdru2GXKZghP3sdgwE9XXpnVwfZ8JnFV4w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/fake-timers": "30.4.1",
+ "@jest/types": "30.4.1",
+ "@types/node": "*",
+ "jest-mock": "30.4.1"
+ },
+ "engines": {
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
+ }
+ },
+ "node_modules/jest-environment-jsdom/node_modules/@jest/fake-timers": {
+ "version": "30.4.1",
+ "resolved": "https://registry.npmmirror.com/@jest/fake-timers/-/fake-timers-30.4.1.tgz",
+ "integrity": "sha512-iW5umdmfPeWzehrVhugFQZqCchSCud5S1l2YT0O9ZhjRR0ExclANDZkiSBwzqtnlOn0J1JXvO+HZ6rkuyOVOgQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/types": "30.4.1",
+ "@sinonjs/fake-timers": "^15.4.0",
+ "@types/node": "*",
+ "jest-message-util": "30.4.1",
+ "jest-mock": "30.4.1",
+ "jest-util": "30.4.1"
+ },
+ "engines": {
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
+ }
+ },
+ "node_modules/jest-environment-jsdom/node_modules/@jest/schemas": {
+ "version": "30.4.1",
+ "resolved": "https://registry.npmmirror.com/@jest/schemas/-/schemas-30.4.1.tgz",
+ "integrity": "sha512-i6b4qw5qnP8c5FEeBJg/uZQ4ddrkN6Ca8qISJh0pr7a5hfn3h3v5x60BEbOC7OYAGZNMs1LfFLwnW2CuK8F57Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@sinclair/typebox": "^0.34.0"
+ },
+ "engines": {
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
+ }
+ },
+ "node_modules/jest-environment-jsdom/node_modules/@jest/types": {
+ "version": "30.4.1",
+ "resolved": "https://registry.npmmirror.com/@jest/types/-/types-30.4.1.tgz",
+ "integrity": "sha512-f1x/vJXIfjOlEmejYpbkbgw1gOqpPECwMvMEtBqe47j7H2Hg8h8w3o3ikhSXq3MI15kg+oQ0exWO0uCtTNJLoQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/pattern": "30.4.0",
+ "@jest/schemas": "30.4.1",
+ "@types/istanbul-lib-coverage": "^2.0.6",
+ "@types/istanbul-reports": "^3.0.4",
+ "@types/node": "*",
+ "@types/yargs": "^17.0.33",
+ "chalk": "^4.1.2"
+ },
+ "engines": {
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
+ }
+ },
+ "node_modules/jest-environment-jsdom/node_modules/@sinclair/typebox": {
+ "version": "0.34.52",
+ "resolved": "https://registry.npmmirror.com/@sinclair/typebox/-/typebox-0.34.52.tgz",
+ "integrity": "sha512-XiMQh7qqVlxZzcVD+kkGMNGMzcTrDMLWI7S4x7z1MkCkbDPrekpZXEUK0eZqZFMuHQg2a2DZOcDIh9o5v3Gonw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/jest-environment-jsdom/node_modules/@sinonjs/fake-timers": {
+ "version": "15.4.0",
+ "resolved": "https://registry.npmmirror.com/@sinonjs/fake-timers/-/fake-timers-15.4.0.tgz",
+ "integrity": "sha512-DsG+8/LscQIQg68J6Ef3dv10u6nVyetYn923s3/sus5eaGfTo1of5WMZSLf0UJc9KDuKPilPH0UDJCjvNbDNCA==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "@sinonjs/commons": "^3.0.1"
+ }
+ },
+ "node_modules/jest-environment-jsdom/node_modules/ansi-styles": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-5.2.0.tgz",
+ "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/jest-environment-jsdom/node_modules/ci-info": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmmirror.com/ci-info/-/ci-info-4.4.0.tgz",
+ "integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/sibiraj-s"
+ }
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/jest-environment-jsdom/node_modules/jest-message-util": {
+ "version": "30.4.1",
+ "resolved": "https://registry.npmmirror.com/jest-message-util/-/jest-message-util-30.4.1.tgz",
+ "integrity": "sha512-kwCKIvq0MCW1HzLoGola9Te6JUdzgV0loyKJ3Qghrkz9i5/RRIHsL95BMQc2HBBhlBKC4j22K9p11TGHH8RBpQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.27.1",
+ "@jest/types": "30.4.1",
+ "@types/stack-utils": "^2.0.3",
+ "chalk": "^4.1.2",
+ "graceful-fs": "^4.2.11",
+ "jest-util": "30.4.1",
+ "picomatch": "^4.0.3",
+ "pretty-format": "30.4.1",
+ "slash": "^3.0.0",
+ "stack-utils": "^2.0.6"
+ },
+ "engines": {
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
+ }
+ },
+ "node_modules/jest-environment-jsdom/node_modules/jest-mock": {
+ "version": "30.4.1",
+ "resolved": "https://registry.npmmirror.com/jest-mock/-/jest-mock-30.4.1.tgz",
+ "integrity": "sha512-/i8SVb8/NSB7RfNi8gfqu8gxLV23KaL5EpAttyb9iz8qWRIqXRLflycz/32wXsYkOnaUlx8NAKnJYtpsmXUmfw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/types": "30.4.1",
+ "@types/node": "*",
+ "jest-util": "30.4.1"
+ },
+ "engines": {
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
+ }
+ },
+ "node_modules/jest-environment-jsdom/node_modules/jest-util": {
+ "version": "30.4.1",
+ "resolved": "https://registry.npmmirror.com/jest-util/-/jest-util-30.4.1.tgz",
+ "integrity": "sha512-vjQb1sACEiv13DKJMDToJpzVW0joCsIQrmbg0fi7CyOOt+g9jTuQl2A216pWRBYhOVt53XbL/2LbMKg1BECWOw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/types": "30.4.1",
+ "@types/node": "*",
+ "chalk": "^4.1.2",
+ "ci-info": "^4.2.0",
+ "graceful-fs": "^4.2.11",
+ "picomatch": "^4.0.3"
+ },
+ "engines": {
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
+ }
+ },
+ "node_modules/jest-environment-jsdom/node_modules/picomatch": {
+ "version": "4.0.5",
+ "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.5.tgz",
+ "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/jest-environment-jsdom/node_modules/pretty-format": {
+ "version": "30.4.1",
+ "resolved": "https://registry.npmmirror.com/pretty-format/-/pretty-format-30.4.1.tgz",
+ "integrity": "sha512-K6KiKMHTL4jjX4u3Kir2EW07nRfcqVTXIImx50wbjHQTcZPgg+gjVeNTIT3l3L1Rd4UefxfogquC9J37SoFyyw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/schemas": "30.4.1",
+ "ansi-styles": "^5.2.0",
+ "react-is-18": "npm:react-is@^18.3.1",
+ "react-is-19": "npm:react-is@^19.2.5"
+ },
+ "engines": {
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
+ }
+ },
+ "node_modules/jest-environment-node": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmmirror.com/jest-environment-node/-/jest-environment-node-29.7.0.tgz",
+ "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/environment": "^29.7.0",
+ "@jest/fake-timers": "^29.7.0",
+ "@jest/types": "^29.6.3",
+ "@types/node": "*",
+ "jest-mock": "^29.7.0",
+ "jest-util": "^29.7.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-get-type": {
+ "version": "29.6.3",
+ "resolved": "https://registry.npmmirror.com/jest-get-type/-/jest-get-type-29.6.3.tgz",
+ "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-haste-map": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmmirror.com/jest-haste-map/-/jest-haste-map-29.7.0.tgz",
+ "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/types": "^29.6.3",
+ "@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.6.3",
+ "jest-util": "^29.7.0",
+ "jest-worker": "^29.7.0",
+ "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.7.0",
+ "resolved": "https://registry.npmmirror.com/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz",
+ "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "jest-get-type": "^29.6.3",
+ "pretty-format": "^29.7.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-matcher-utils": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmmirror.com/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz",
+ "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "chalk": "^4.0.0",
+ "jest-diff": "^29.7.0",
+ "jest-get-type": "^29.6.3",
+ "pretty-format": "^29.7.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-message-util": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmmirror.com/jest-message-util/-/jest-message-util-29.7.0.tgz",
+ "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.12.13",
+ "@jest/types": "^29.6.3",
+ "@types/stack-utils": "^2.0.0",
+ "chalk": "^4.0.0",
+ "graceful-fs": "^4.2.9",
+ "micromatch": "^4.0.4",
+ "pretty-format": "^29.7.0",
+ "slash": "^3.0.0",
+ "stack-utils": "^2.0.3"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-mock": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmmirror.com/jest-mock/-/jest-mock-29.7.0.tgz",
+ "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/types": "^29.6.3",
+ "@types/node": "*",
+ "jest-util": "^29.7.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-pnp-resolver": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmmirror.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz",
+ "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ },
+ "peerDependencies": {
+ "jest-resolve": "*"
+ },
+ "peerDependenciesMeta": {
+ "jest-resolve": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/jest-regex-util": {
+ "version": "29.6.3",
+ "resolved": "https://registry.npmmirror.com/jest-regex-util/-/jest-regex-util-29.6.3.tgz",
+ "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-resolve": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmmirror.com/jest-resolve/-/jest-resolve-29.7.0.tgz",
+ "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "chalk": "^4.0.0",
+ "graceful-fs": "^4.2.9",
+ "jest-haste-map": "^29.7.0",
+ "jest-pnp-resolver": "^1.2.2",
+ "jest-util": "^29.7.0",
+ "jest-validate": "^29.7.0",
+ "resolve": "^1.20.0",
+ "resolve.exports": "^2.0.0",
+ "slash": "^3.0.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-resolve-dependencies": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmmirror.com/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz",
+ "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "jest-regex-util": "^29.6.3",
+ "jest-snapshot": "^29.7.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-runner": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmmirror.com/jest-runner/-/jest-runner-29.7.0.tgz",
+ "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/console": "^29.7.0",
+ "@jest/environment": "^29.7.0",
+ "@jest/test-result": "^29.7.0",
+ "@jest/transform": "^29.7.0",
+ "@jest/types": "^29.6.3",
+ "@types/node": "*",
+ "chalk": "^4.0.0",
+ "emittery": "^0.13.1",
+ "graceful-fs": "^4.2.9",
+ "jest-docblock": "^29.7.0",
+ "jest-environment-node": "^29.7.0",
+ "jest-haste-map": "^29.7.0",
+ "jest-leak-detector": "^29.7.0",
+ "jest-message-util": "^29.7.0",
+ "jest-resolve": "^29.7.0",
+ "jest-runtime": "^29.7.0",
+ "jest-util": "^29.7.0",
+ "jest-watcher": "^29.7.0",
+ "jest-worker": "^29.7.0",
+ "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-runtime": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmmirror.com/jest-runtime/-/jest-runtime-29.7.0.tgz",
+ "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/environment": "^29.7.0",
+ "@jest/fake-timers": "^29.7.0",
+ "@jest/globals": "^29.7.0",
+ "@jest/source-map": "^29.6.3",
+ "@jest/test-result": "^29.7.0",
+ "@jest/transform": "^29.7.0",
+ "@jest/types": "^29.6.3",
+ "@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.7.0",
+ "jest-message-util": "^29.7.0",
+ "jest-mock": "^29.7.0",
+ "jest-regex-util": "^29.6.3",
+ "jest-resolve": "^29.7.0",
+ "jest-snapshot": "^29.7.0",
+ "jest-util": "^29.7.0",
+ "slash": "^3.0.0",
+ "strip-bom": "^4.0.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-snapshot": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmmirror.com/jest-snapshot/-/jest-snapshot-29.7.0.tgz",
+ "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==",
+ "dev": true,
+ "license": "MIT",
+ "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/types": "^7.3.3",
+ "@jest/expect-utils": "^29.7.0",
+ "@jest/transform": "^29.7.0",
+ "@jest/types": "^29.6.3",
+ "babel-preset-current-node-syntax": "^1.0.0",
+ "chalk": "^4.0.0",
+ "expect": "^29.7.0",
+ "graceful-fs": "^4.2.9",
+ "jest-diff": "^29.7.0",
+ "jest-get-type": "^29.6.3",
+ "jest-matcher-utils": "^29.7.0",
+ "jest-message-util": "^29.7.0",
+ "jest-util": "^29.7.0",
+ "natural-compare": "^1.4.0",
+ "pretty-format": "^29.7.0",
+ "semver": "^7.5.3"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-snapshot/node_modules/semver": {
+ "version": "7.8.5",
+ "resolved": "https://registry.npmmirror.com/semver/-/semver-7.8.5.tgz",
+ "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/jest-util": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmmirror.com/jest-util/-/jest-util-29.7.0.tgz",
+ "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/types": "^29.6.3",
+ "@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-validate": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmmirror.com/jest-validate/-/jest-validate-29.7.0.tgz",
+ "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/types": "^29.6.3",
+ "camelcase": "^6.2.0",
+ "chalk": "^4.0.0",
+ "jest-get-type": "^29.6.3",
+ "leven": "^3.1.0",
+ "pretty-format": "^29.7.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-validate/node_modules/camelcase": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmmirror.com/camelcase/-/camelcase-6.3.0.tgz",
+ "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/jest-watcher": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmmirror.com/jest-watcher/-/jest-watcher-29.7.0.tgz",
+ "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/test-result": "^29.7.0",
+ "@jest/types": "^29.6.3",
+ "@types/node": "*",
+ "ansi-escapes": "^4.2.1",
+ "chalk": "^4.0.0",
+ "emittery": "^0.13.1",
+ "jest-util": "^29.7.0",
+ "string-length": "^4.0.1"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-worker": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmmirror.com/jest-worker/-/jest-worker-29.7.0.tgz",
+ "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*",
+ "jest-util": "^29.7.0",
+ "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/supports-color": {
+ "version": "8.1.1",
+ "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-8.1.1.tgz",
+ "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/supports-color?sponsor=1"
+ }
+ },
+ "node_modules/jquery": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmmirror.com/jquery/-/jquery-4.0.0.tgz",
+ "integrity": "sha512-TXCHVR3Lb6TZdtw1l3RTLf8RBWVGexdxL6AC8/e0xZKEpBflBsjh9/8LXw+dkNFuOyW9B7iB3O1sP7hS0Kiacg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/js-yaml": {
+ "version": "3.15.0",
+ "resolved": "https://registry.npmmirror.com/js-yaml/-/js-yaml-3.15.0.tgz",
+ "integrity": "sha512-ttBQIIQPDeLjpPOohtUdXuXUVoA2uIB6fEH9HyJ7234s5mBJ5wTx20njxplLZQgLaOfpmPQA7X2t5AX6tIPbog==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/jsdom": {
+ "version": "26.1.0",
+ "resolved": "https://registry.npmmirror.com/jsdom/-/jsdom-26.1.0.tgz",
+ "integrity": "sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "cssstyle": "^4.2.1",
+ "data-urls": "^5.0.0",
+ "decimal.js": "^10.5.0",
+ "html-encoding-sniffer": "^4.0.0",
+ "http-proxy-agent": "^7.0.2",
+ "https-proxy-agent": "^7.0.6",
+ "is-potential-custom-element-name": "^1.0.1",
+ "nwsapi": "^2.2.16",
+ "parse5": "^7.2.1",
+ "rrweb-cssom": "^0.8.0",
+ "saxes": "^6.0.0",
+ "symbol-tree": "^3.2.4",
+ "tough-cookie": "^5.1.1",
+ "w3c-xmlserializer": "^5.0.0",
+ "webidl-conversions": "^7.0.0",
+ "whatwg-encoding": "^3.1.1",
+ "whatwg-mimetype": "^4.0.0",
+ "whatwg-url": "^14.1.1",
+ "ws": "^8.18.0",
+ "xml-name-validator": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "canvas": "^3.0.0"
+ },
+ "peerDependenciesMeta": {
+ "canvas": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/jsesc": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmmirror.com/jsesc/-/jsesc-3.1.0.tgz",
+ "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "jsesc": "bin/jsesc"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/json-parse-even-better-errors": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmmirror.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
+ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/json5": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmmirror.com/json5/-/json5-2.2.3.tgz",
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "json5": "lib/cli.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/kleur": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmmirror.com/kleur/-/kleur-3.0.3.tgz",
+ "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/leven": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmmirror.com/leven/-/leven-3.1.0.tgz",
+ "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/lines-and-columns": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmmirror.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
+ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/locate-path": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmmirror.com/locate-path/-/locate-path-5.0.0.tgz",
+ "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-locate": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/lru-cache": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-5.1.1.tgz",
+ "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "yallist": "^3.0.2"
+ }
+ },
+ "node_modules/make-dir": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmmirror.com/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/make-dir/node_modules/semver": {
+ "version": "7.8.5",
+ "resolved": "https://registry.npmmirror.com/semver/-/semver-7.8.5.tgz",
+ "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/makeerror": {
+ "version": "1.0.12",
+ "resolved": "https://registry.npmmirror.com/makeerror/-/makeerror-1.0.12.tgz",
+ "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "tmpl": "1.0.5"
+ }
+ },
+ "node_modules/merge-stream": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmmirror.com/merge-stream/-/merge-stream-2.0.0.tgz",
+ "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/micromatch": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmmirror.com/micromatch/-/micromatch-4.0.8.tgz",
+ "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "braces": "^3.0.3",
+ "picomatch": "^2.3.1"
+ },
+ "engines": {
+ "node": ">=8.6"
+ }
+ },
+ "node_modules/mimic-fn": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmmirror.com/mimic-fn/-/mimic-fn-2.1.0.tgz",
+ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "3.1.5",
+ "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.5.tgz",
+ "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/natural-compare": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmmirror.com/natural-compare/-/natural-compare-1.4.0.tgz",
+ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/node-int64": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmmirror.com/node-int64/-/node-int64-0.4.0.tgz",
+ "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/node-releases": {
+ "version": "2.0.51",
+ "resolved": "https://registry.npmmirror.com/node-releases/-/node-releases-2.0.51.tgz",
+ "integrity": "sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmmirror.com/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/npm-run-path": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmmirror.com/npm-run-path/-/npm-run-path-4.0.1.tgz",
+ "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "path-key": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/nwsapi": {
+ "version": "2.2.24",
+ "resolved": "https://registry.npmmirror.com/nwsapi/-/nwsapi-2.2.24.tgz",
+ "integrity": "sha512-7YRhZ3jS45LwmSCT4b2sVFHt/WuovaktDU07QrtOBY2PXskss5a9jfmR9jptyumwXST+rFjrmppMY1KT/yn35A==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmmirror.com/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "node_modules/onetime": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmmirror.com/onetime/-/onetime-5.1.2.tgz",
+ "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "mimic-fn": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/p-limit": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmmirror.com/p-limit/-/p-limit-3.1.0.tgz",
+ "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "yocto-queue": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/p-locate": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmmirror.com/p-locate/-/p-locate-4.1.0.tgz",
+ "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-limit": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/p-locate/node_modules/p-limit": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmmirror.com/p-limit/-/p-limit-2.3.0.tgz",
+ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-try": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/p-try": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmmirror.com/p-try/-/p-try-2.2.0.tgz",
+ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/parse-json": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmmirror.com/parse-json/-/parse-json-5.2.0.tgz",
+ "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
+ "dev": true,
+ "license": "MIT",
+ "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/parse5": {
+ "version": "7.3.0",
+ "resolved": "https://registry.npmmirror.com/parse5/-/parse5-7.3.0.tgz",
+ "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "entities": "^6.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/inikulin/parse5?sponsor=1"
+ }
+ },
+ "node_modules/path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmmirror.com/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmmirror.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmmirror.com/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-parse": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmmirror.com/path-parse/-/path-parse-1.0.7.tgz",
+ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/picocolors": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz",
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/picomatch": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.2.tgz",
+ "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/pirates": {
+ "version": "4.0.7",
+ "resolved": "https://registry.npmmirror.com/pirates/-/pirates-4.0.7.tgz",
+ "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/pkg-dir": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmmirror.com/pkg-dir/-/pkg-dir-4.2.0.tgz",
+ "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "find-up": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/pretty-format": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmmirror.com/pretty-format/-/pretty-format-29.7.0.tgz",
+ "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/schemas": "^29.6.3",
+ "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.npmmirror.com/ansi-styles/-/ansi-styles-5.2.0.tgz",
+ "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/prompts": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmmirror.com/prompts/-/prompts-2.4.2.tgz",
+ "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "kleur": "^3.0.3",
+ "sisteransi": "^1.0.5"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/punycode": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmmirror.com/punycode/-/punycode-2.3.1.tgz",
+ "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/pure-rand": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmmirror.com/pure-rand/-/pure-rand-6.1.0.tgz",
+ "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/dubzzz"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/fast-check"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/react-is": {
+ "version": "18.3.1",
+ "resolved": "https://registry.npmmirror.com/react-is/-/react-is-18.3.1.tgz",
+ "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/react-is-18": {
+ "name": "react-is",
+ "version": "18.3.1",
+ "resolved": "https://registry.npmmirror.com/react-is/-/react-is-18.3.1.tgz",
+ "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/react-is-19": {
+ "name": "react-is",
+ "version": "19.2.7",
+ "resolved": "https://registry.npmmirror.com/react-is/-/react-is-19.2.7.tgz",
+ "integrity": "sha512-kZFnouyVv7eP/Phmrlo9FK+zcAdriZJvzxXHF1Sl1P377WSGe2G/JxVolhTrB/jeV47lKImhNUsijjHAAbcl/A==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/require-directory": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmmirror.com/require-directory/-/require-directory-2.1.1.tgz",
+ "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/resolve": {
+ "version": "1.22.12",
+ "resolved": "https://registry.npmmirror.com/resolve/-/resolve-1.22.12.tgz",
+ "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "is-core-module": "^2.16.1",
+ "path-parse": "^1.0.7",
+ "supports-preserve-symlinks-flag": "^1.0.0"
+ },
+ "bin": {
+ "resolve": "bin/resolve"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/resolve-cwd": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmmirror.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz",
+ "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "resolve-from": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/resolve-from": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmmirror.com/resolve-from/-/resolve-from-5.0.0.tgz",
+ "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/resolve.exports": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmmirror.com/resolve.exports/-/resolve.exports-2.0.3.tgz",
+ "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/rrweb-cssom": {
+ "version": "0.8.0",
+ "resolved": "https://registry.npmmirror.com/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz",
+ "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmmirror.com/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/saxes": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmmirror.com/saxes/-/saxes-6.0.0.tgz",
+ "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "xmlchars": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=v12.22.7"
+ }
+ },
+ "node_modules/semver": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmmirror.com/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/shebang-command": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmmirror.com/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.npmmirror.com/shebang-regex/-/shebang-regex-3.0.0.tgz",
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/signal-exit": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmmirror.com/signal-exit/-/signal-exit-3.0.7.tgz",
+ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/sisteransi": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmmirror.com/sisteransi/-/sisteransi-1.0.5.tgz",
+ "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/slash": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmmirror.com/slash/-/slash-3.0.0.tgz",
+ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/source-map-support": {
+ "version": "0.5.13",
+ "resolved": "https://registry.npmmirror.com/source-map-support/-/source-map-support-0.5.13.tgz",
+ "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "buffer-from": "^1.0.0",
+ "source-map": "^0.6.0"
+ }
+ },
+ "node_modules/sprintf-js": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmmirror.com/sprintf-js/-/sprintf-js-1.0.3.tgz",
+ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
+ "dev": true,
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/stack-utils": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmmirror.com/stack-utils/-/stack-utils-2.0.6.tgz",
+ "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "escape-string-regexp": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/string-length": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmmirror.com/string-length/-/string-length-4.0.2.tgz",
+ "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==",
+ "dev": true,
+ "license": "MIT",
+ "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.npmmirror.com/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/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmmirror.com/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-bom": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmmirror.com/strip-bom/-/strip-bom-4.0.0.tgz",
+ "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-final-newline": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmmirror.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
+ "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/strip-json-comments": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmmirror.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmmirror.com/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/supports-preserve-symlinks-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmmirror.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/symbol-tree": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmmirror.com/symbol-tree/-/symbol-tree-3.2.4.tgz",
+ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/test-exclude": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmmirror.com/test-exclude/-/test-exclude-6.0.0.tgz",
+ "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "@istanbuljs/schema": "^0.1.2",
+ "glob": "^7.1.4",
+ "minimatch": "^3.0.4"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/tldts": {
+ "version": "6.1.86",
+ "resolved": "https://registry.npmmirror.com/tldts/-/tldts-6.1.86.tgz",
+ "integrity": "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "tldts-core": "^6.1.86"
+ },
+ "bin": {
+ "tldts": "bin/cli.js"
+ }
+ },
+ "node_modules/tldts-core": {
+ "version": "6.1.86",
+ "resolved": "https://registry.npmmirror.com/tldts-core/-/tldts-core-6.1.86.tgz",
+ "integrity": "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/tmpl": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmmirror.com/tmpl/-/tmpl-1.0.5.tgz",
+ "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==",
+ "dev": true,
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmmirror.com/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/tough-cookie": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmmirror.com/tough-cookie/-/tough-cookie-5.1.2.tgz",
+ "integrity": "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "tldts": "^6.1.32"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/tr46": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmmirror.com/tr46/-/tr46-5.1.1.tgz",
+ "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "punycode": "^2.3.1"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/type-detect": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmmirror.com/type-detect/-/type-detect-4.0.8.tgz",
+ "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/type-fest": {
+ "version": "0.21.3",
+ "resolved": "https://registry.npmmirror.com/type-fest/-/type-fest-0.21.3.tgz",
+ "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==",
+ "dev": true,
+ "license": "(MIT OR CC0-1.0)",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/undici-types": {
+ "version": "8.3.0",
+ "resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-8.3.0.tgz",
+ "integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/update-browserslist-db": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmmirror.com/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
+ "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "escalade": "^3.2.0",
+ "picocolors": "^1.1.1"
+ },
+ "bin": {
+ "update-browserslist-db": "cli.js"
+ },
+ "peerDependencies": {
+ "browserslist": ">= 4.21.0"
+ }
+ },
+ "node_modules/v8-to-istanbul": {
+ "version": "9.3.0",
+ "resolved": "https://registry.npmmirror.com/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz",
+ "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "@jridgewell/trace-mapping": "^0.3.12",
+ "@types/istanbul-lib-coverage": "^2.0.1",
+ "convert-source-map": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10.12.0"
+ }
+ },
+ "node_modules/w3c-xmlserializer": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmmirror.com/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz",
+ "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "xml-name-validator": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/walker": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmmirror.com/walker/-/walker-1.0.8.tgz",
+ "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "makeerror": "1.0.12"
+ }
+ },
+ "node_modules/webidl-conversions": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmmirror.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
+ "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/whatwg-encoding": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmmirror.com/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz",
+ "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==",
+ "deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "iconv-lite": "0.6.3"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/whatwg-mimetype": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmmirror.com/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz",
+ "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/whatwg-url": {
+ "version": "14.2.0",
+ "resolved": "https://registry.npmmirror.com/whatwg-url/-/whatwg-url-14.2.0.tgz",
+ "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "tr46": "^5.1.0",
+ "webidl-conversions": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmmirror.com/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/wrap-ansi": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmmirror.com/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/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/write-file-atomic": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmmirror.com/write-file-atomic/-/write-file-atomic-4.0.2.tgz",
+ "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==",
+ "dev": true,
+ "license": "ISC",
+ "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": "8.21.1",
+ "resolved": "https://registry.npmmirror.com/ws/-/ws-8.21.1.tgz",
+ "integrity": "sha512-+0NTnW77fFN/DjQi6k/Sq/Yvk4Sgajw7urW8V+asjXnRgDs9gyGkdb7EzgfhA4goXsRIZKE28fzIXBHEzhuiWw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10.0.0"
+ },
+ "peerDependencies": {
+ "bufferutil": "^4.0.1",
+ "utf-8-validate": ">=5.0.2"
+ },
+ "peerDependenciesMeta": {
+ "bufferutil": {
+ "optional": true
+ },
+ "utf-8-validate": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/xml-name-validator": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmmirror.com/xml-name-validator/-/xml-name-validator-5.0.0.tgz",
+ "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/xmlchars": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmmirror.com/xmlchars/-/xmlchars-2.2.0.tgz",
+ "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/y18n": {
+ "version": "5.0.8",
+ "resolved": "https://registry.npmmirror.com/y18n/-/y18n-5.0.8.tgz",
+ "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/yallist": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmmirror.com/yallist/-/yallist-3.1.1.tgz",
+ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/yargs": {
+ "version": "17.7.3",
+ "resolved": "https://registry.npmmirror.com/yargs/-/yargs-17.7.3.tgz",
+ "integrity": "sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==",
+ "dev": true,
+ "license": "MIT",
+ "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.npmmirror.com/yargs-parser/-/yargs-parser-21.1.1.tgz",
+ "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/yocto-queue": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmmirror.com/yocto-queue/-/yocto-queue-0.1.0.tgz",
+ "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ }
+ }
+}
diff --git a/YLErpWeb/fe-tests/package.json b/YLErpWeb/fe-tests/package.json
new file mode 100644
index 00000000..2ac293e5
--- /dev/null
+++ b/YLErpWeb/fe-tests/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "zszq-trs-fe-tests",
+ "version": "1.0.0",
+ "private": true,
+ "description": "前端 JS 单元测试:守卫互换结算/平仓的小数点 bug(与 C# FrontendCalcReference 交叉校验)",
+ "scripts": {
+ "test": "jest"
+ },
+ "devDependencies": {
+ "jest": "^29.7.0",
+ "jest-environment-jsdom": "^30.4.1",
+ "jquery": "^4.0.0"
+ }
+}
diff --git a/YLErpWeb/fe-tests/parity.test.js b/YLErpWeb/fe-tests/parity.test.js
new file mode 100644
index 00000000..a9ba5053
--- /dev/null
+++ b/YLErpWeb/fe-tests/parity.test.js
@@ -0,0 +1,96 @@
+/**
+ * parity.test.js — 生产代码 vs SwapCalc 等价性证明(替换前的"零风险闸门")
+ * ============================================================================
+ * 方法:把 incomeSwapTrade.js / swapTradeEdit.js 里 4 个公式的【生产表达式逐字】
+ * 抄成 PROD_* 函数,与 SwapCalc.* 在 FC 场景 + 随机 + 精度边界上对比。
+ * 只有本文件 100% 绿灯,才允许把生产内联表达式替换为 SwapCalc.* 调用。
+ * 本文件只读对比,不改动任何生产代码。
+ */
+const SwapCalc = require('../wwwroot/Scripts/app/swaptrade/swapCalc.js');
+
+// ---- 生产表达式逐字抄录(来源见注释行号) ----
+// incomeSwapTrade.js L76
+function PROD_getPriceScale(multiplier) { return multiplier == 100 ? 0.01 : 1; }
+// incomeSwapTrade.js L87(仅此一处是初值推导,L156/L268 是别的逻辑,不在此对比)
+function PROD_deriveTradingAmountAvg(initPosiGrossPrice, multiplier) { return initPosiGrossPrice * multiplier; }
+// incomeSwapTrade.js L179:4 个加数均为 2 位小数,.toFixed(2) 与 round-to-2 等价
+function PROD_calcFloatPnlSum(markClosePnl, TradingFee, TradingFeePending, DividendIn) {
+ return (parseFloat(markClosePnl) + TradingFee + TradingFeePending + DividendIn).toFixed(2);
+}
+// swapTradeEdit.js L360:lodash _.round(x,2) === Math.round(x*100)/100
+function lodashRound(x, d) { var f = Math.pow(10, d); return Math.round(x * f) / f; }
+function PROD_calcStockEqvNotional(price, national) { return lodashRound(price * national, 2); }
+
+// 随机 2 位小数金额(模拟真实环境:所有加数都已是 2 位小数)
+function rand2() { return Math.round(Math.random() * 2000000) / 100; } // 0.00 ~ 20000.00
+
+describe('parity: getPriceScale (incomeSwapTrade.js L76)', () => {
+ const cases = [100, 1, 1000, 0, 200, 10];
+ cases.forEach((m) => {
+ test('multiplier=' + m, () => {
+ expect(PROD_getPriceScale(m)).toBe(SwapCalc.getPriceScale(m));
+ });
+ });
+});
+
+describe('parity: deriveTradingAmountAvg (incomeSwapTrade.js L87)', () => {
+ // FC 场景的 (grossPrice, multiplier)
+ const cases = [
+ [1.02, 100], [100, 1], [1.02, 100], [95.5, 100], [102.34, 100], [50, 1],
+ ];
+ cases.forEach(([p, m]) => {
+ test('gross=' + p + ' mult=' + m, () => {
+ expect(PROD_deriveTradingAmountAvg(p, m)).toBe(SwapCalc.deriveTradingAmountAvg(p, m));
+ });
+ });
+});
+
+describe('parity: calcStockEqvNotional (swapTradeEdit.js L360)', () => {
+ const cases = [
+ [1.02, 10000], [100, 1000], [1.0235, 5000], [99.99, 100], [0.5, 200],
+ ];
+ cases.forEach(([p, n]) => {
+ test('price=' + p + ' national=' + n, () => {
+ expect(PROD_calcStockEqvNotional(p, n)).toBe(SwapCalc.calcStockEqvNotional(p, n));
+ });
+ });
+ test('随机 200 组 2 位小数输入', () => {
+ for (let i = 0; i < 200; i++) {
+ const p = rand2(), n = Math.round(Math.random() * 100000);
+ expect(PROD_calcStockEqvNotional(p, n)).toBe(SwapCalc.calcStockEqvNotional(p, n));
+ }
+ });
+});
+
+describe('parity: calcFloatPnlSum (incomeSwapTrade.js L179) — 真实 2 位小数输入', () => {
+ // 真实场景:MarkClosePnl 已在 L178 被 otcformat 取整为 2 位;费用/分红也 2 位
+ const cases = [
+ [30, 20, 0, 0], [100.456, 1, 0.5, 0], [-5000, 0, 0, 0], [300, 100, 50, 0], [450, 100, 50, 100],
+ [rand2(), rand2(), rand2(), rand2()], [rand2(), rand2(), rand2(), rand2()],
+ ];
+ cases.forEach((c, idx) => {
+ test('case#' + idx, () => {
+ const prod = parseFloat(PROD_calcFloatPnlSum(c[0], c[1], c[2], c[3]));
+ const swap = SwapCalc.calcFloatPnlSum(c[0], c[1], c[2], c[3]);
+ expect(prod).toBe(swap); // 2 位小数输入下 .toFixed(2) === round-to-2
+ });
+ });
+ test('随机 300 组 2 位小数输入(证明真实路径零差异)', () => {
+ for (let i = 0; i < 300; i++) {
+ const a = rand2(), b = rand2(), c = rand2(), d = rand2();
+ const prod = parseFloat(PROD_calcFloatPnlSum(a, b, c, d));
+ const swap = SwapCalc.calcFloatPnlSum(a, b, c, d);
+ expect(prod).toBe(swap);
+ }
+ });
+});
+
+// 最坏输入验证:即便喂入未取整的原始值(如 1.005),toFixed 与 round-half-away 在浮点现实下
+// 同样得到 1.00,证明不存在舍入接缝。生产环境 4 个加数恒为 2 位小数,更不可能分歧。
+describe('parity: 最坏输入也无舍入接缝', () => {
+ test('原始 1.005 输入下两者仍一致', () => {
+ const prod = parseFloat(PROD_calcFloatPnlSum(1.005, 0, 0, 0)); // "1.00"
+ const swap = SwapCalc.calcFloatPnlSum(1.005, 0, 0, 0); // 1.00
+ expect(prod).toBe(swap);
+ });
+});
diff --git a/YLErpWeb/fe-tests/swapCalc.test.js b/YLErpWeb/fe-tests/swapCalc.test.js
new file mode 100644
index 00000000..71c4993e
--- /dev/null
+++ b/YLErpWeb/fe-tests/swapCalc.test.js
@@ -0,0 +1,293 @@
+/**
+ * swapCalc.test.js — 前端计算逻辑单元测试
+ * ============================================================================
+ * 双重目的:
+ * 1) 回归守卫:锁定 4 个曾出 bug 的纯函数(dcf649f2 / 20ea93d8 / 3c5f25a5 / f873239a)
+ * 2) 交叉校验:用 8 个场景(FC_001~FC_008)对齐 C# FrontendCalcCharacterizationTest 金标准,
+ * 一旦 JS 公式与后端 FrontendCalcReference 分叉,测试即红。
+ *
+ * 运行:cd YLErpWeb/fe-tests && npm i && npm test
+ */
+const SwapCalc = require('../wwwroot/Scripts/app/swaptrade/swapCalc.js');
+
+const TOL = 1e-6;
+function expectClose(actual, expected, msg) {
+ expect(Math.abs(actual - expected)).toBeLessThanOrEqual(TOL, msg || '');
+}
+
+describe('回归守卫:曾出 bug 的纯函数', () => {
+ // 20ea93d8 / dcf649f2:必须用全价(PosiGrossPrice) 且债券 ×100
+ test('deriveTradingAmountAvg 债券用全价并 ×100 (守卫 20ea93d8/dcf649f2)', () => {
+ expectClose(SwapCalc.deriveTradingAmountAvg(1.02, 100), 102, '债券: 1.02×100=102(界面百分比态)');
+ expectClose(SwapCalc.deriveTradingAmountAvg(1.02, 1), 1.02, '非债券: 不缩放');
+ // 若误用净价(PosiNetPrice) 会偏离,这里锁定"全价"语义
+ expect(SwapCalc.deriveTradingAmountAvg(1.02, 100)).toBe(102);
+ });
+
+ test('收益结算审批回显提交的期末价格', () => {
+ expectClose(
+ SwapCalc.resolveIncomeTradingAmountAvg(0.98, 0.80, 100, true),
+ 80,
+ '债券审批应把已提交相对价0.80还原为界面值80');
+ expectClose(
+ SwapCalc.resolveIncomeTradingAmountAvg(0.98, 0.80, 100, false),
+ 98,
+ '普通打开仍以期初全价98作为默认期末价');
+ });
+
+ // 3c5f25a5:FloatPnlSum 必须保留 2 位小数
+ test('calcFloatPnlSum 保留 2 位 (守卫 3c5f25a5)', () => {
+ expectClose(SwapCalc.calcFloatPnlSum(100.456, 1, 0.5, 0), 101.96, '100.456+1+0.5=101.956→101.96');
+ expectClose(SwapCalc.calcFloatPnlSum(30, 20, 0, 0), 50, '30+20=50');
+ expect(SwapCalc.calcFloatPnlSum(30, 20, 0, 0)).toBe(50);
+ });
+
+ // f873239a:名义本金 round 到 2 位
+ test('calcStockEqvNotional round 2 位 (守卫 f873239a)', () => {
+ expectClose(SwapCalc.calcStockEqvNotional(1.02, 100 * 100), 10200, '1.02×10000=10200');
+ expectClose(SwapCalc.calcStockEqvNotional(10.005, 100), 1000.5, '10.005×100=1000.50');
+ });
+
+ test('getPriceScale 债券=0.01 非债券=1', () => {
+ expect(SwapCalc.getPriceScale(100)).toBe(0.01);
+ expect(SwapCalc.getPriceScale(1)).toBe(1);
+ });
+});
+
+// ============================================================================
+// 多次部分平仓:平仓比例 ↔ 平仓名义本金 换算必须以"剩余持仓名义本金"为基准
+// 守卫 unwindSwapTrade.js changeCloseQty/changeClosePercent/changeCloseNotionalValue
+// 旧 bug:用原始 NotionalValue 换算,首次部分平仓后 PosiNotionalValue 被扣减,
+// 导致 ClosePercent 偏小 / CloseNotionalValue 偏大,后端预付金返还本金计算错误
+// ============================================================================
+describe('多次部分平仓:比例↔名义本金换算以 PosiNotionalValue 为基准', () => {
+ // 场景:原始名义本金 1,000,000,首次平 30% 后剩余 700,000
+ // 第 2 次按名义本金输入 350,000(意图平剩余 50%)
+ const NotionalValue = 1_000_000; // 原始(不变)
+ const PosiNotionalValue = 700_000; // 首次部分平仓后剩余
+
+ test('按名义本金反算比例:应=0.5(用剩余),旧 bug 会算成 0.35(用原始)', () => {
+ const closeNotionalValue = 350_000;
+ const correctPct = SwapCalc.calcClosePercentByRemaining(closeNotionalValue, PosiNotionalValue);
+ const buggyPct = SwapCalc.calcClosePercentByRemaining(closeNotionalValue, NotionalValue);
+ expectClose(correctPct, 0.5, '剩余本金为分母应得 50%');
+ expectClose(buggyPct, 0.35, '旧 bug 用原始本金会算成 0.35');
+ expect(Math.abs(correctPct - buggyPct)).toBeGreaterThan(TOL);
+ });
+
+ test('按比例正算名义本金:应=350,000(用剩余),旧 bug 会算成 500,000(用原始)', () => {
+ const closePercent = 0.5;
+ const correctNotional = SwapCalc.calcCloseNotionalByRemaining(closePercent, PosiNotionalValue);
+ const buggyNotional = SwapCalc.calcCloseNotionalByRemaining(closePercent, NotionalValue);
+ expectClose(correctNotional, 350_000, '剩余本金×50%应=350,000');
+ expectClose(buggyNotional, 500_000, '旧 bug 用原始本金会算成 500,000');
+ expect(Math.abs(correctNotional - buggyNotional)).toBeGreaterThan(TOL);
+ });
+
+ test('第 3 次全平剩余 350,000:比例应=1.0(用剩余),旧 bug 会算成 0.35', () => {
+ const remaining = 350_000;
+ const closeNotionalValue = 350_000;
+ const correctPct = SwapCalc.calcClosePercentByRemaining(closeNotionalValue, remaining);
+ const buggyPct = SwapCalc.calcClosePercentByRemaining(closeNotionalValue, NotionalValue);
+ expectClose(correctPct, 1.0, '剩余全平应=100%');
+ expectClose(buggyPct, 0.35, '旧 bug 用原始本金会算成 0.35');
+ });
+
+ test('多次部分平仓合计本金应=原始名义本金(3 次:30% / 50% / 全平)', () => {
+ // 模拟 3 次部分平仓的换算,每次以"当前剩余"为基准
+ let remaining = 1_000_000;
+ const steps = [0.3, 0.5, 1.0];
+ let totalClosed = 0;
+ steps.forEach((pct) => {
+ const closed = SwapCalc.calcCloseNotionalByRemaining(pct, remaining);
+ totalClosed += closed;
+ remaining -= closed;
+ });
+ expectClose(totalClosed, 1_000_000, '3 次部分平仓合计应=原始名义本金');
+ expectClose(remaining, 0, '剩余应为 0');
+ });
+
+ test('除零保护:剩余本金为 0 时比例返回 0', () => {
+ expect(SwapCalc.calcClosePercentByRemaining(100, 0)).toBe(0);
+ });
+});
+
+// ============================================================================
+// 多次部分平仓:全部↔部分切换时 CloseQty 不应随 ClosePercent 口径变化而跳变
+// 守卫 unwindSwapTrade.js changeCloseMethod/changeClosePercent/changeCloseQty/changeCloseNotionalValue
+// 旧 bug:ClosePercent 是占期初口径(A),但 CloseQty=PositionQty*ClosePercent 错当占剩余(B)用
+// 全部(ClosePercent=0.7,CloseQty=720000) → 部分(ClosePercent没变, CloseQty=504000) ❌ 跳变
+// 修复:CloseQty = PositionQty × (ClosePercent / oriClosePercent)
+// ============================================================================
+describe('多次部分平仓:全部↔部分切换 CloseQty 不跳变(占期初口径自洽)', () => {
+ // 场景基于 GLMS-20260701-0013:
+ // 期初 NotionalValue=980000,已平两次剩 PosiNotionalValue=686000, PositionQty=720000
+ // oriClosePercent = 686000/980000 = 0.7
+ const NotionalValue = 980000;
+ const PosiNotionalValue = 686000;
+ const PositionQty = 720000;
+ const oriClosePercent = PosiNotionalValue / NotionalValue; // 0.7
+
+ test('全部平仓 ClosePercent=0.7 → CloseQty=720000(剩余全部)', () => {
+ const closePercent = oriClosePercent; // 全部平仓 = oriClosePercent
+ const closeQty = SwapCalc.calcCloseQtyByOriginalPercent(closePercent, oriClosePercent, PositionQty);
+ expectClose(closeQty, 720000, '全部平仓应平剩余全部数量');
+ });
+
+ test('全部→部分切换(ClosePercent 没变=0.7):CloseQty 应保持 720000 不跳变', () => {
+ // 旧 bug:CloseQty = 720000 * 0.7 = 504000(错误跳变)
+ // 修复:CloseQty = 720000 * (0.7/0.7) = 720000(不变)
+ const closePercent = oriClosePercent;
+ const closeQty = SwapCalc.calcCloseQtyByOriginalPercent(closePercent, oriClosePercent, PositionQty);
+ const buggyCloseQty = Math.round(PositionQty * closePercent * 100) / 100; // 旧 bug 公式
+ expectClose(closeQty, 720000, '修复后应不变');
+ expect(Math.abs(buggyCloseQty - 504000)).toBeLessThanOrEqual(TOL, '旧 bug 会跳变到 504000');
+ expect(Math.abs(closeQty - buggyCloseQty)).toBeGreaterThan(TOL, '修复与旧 bug 必须有差异');
+ });
+
+ test('改比例 0.5(占期初)→ CloseQty=720000×(0.5/0.7)=514285.71', () => {
+ const closePercent = 0.5;
+ const closeQty = SwapCalc.calcCloseQtyByOriginalPercent(closePercent, oriClosePercent, PositionQty);
+ expectClose(closeQty, 514285.71, '占期初 50% 对应占剩余 71.43%,×720000=514285.71');
+ });
+
+ test('逆运算:CloseQty=514285.71 → ClosePercent=0.5(占期初)', () => {
+ const closeQty = 514285.71;
+ const closePercent = SwapCalc.calcOriginalClosePercentByQty(closeQty, PositionQty, oriClosePercent);
+ expectClose(closePercent, 0.5, '逆运算应还原为占期初 0.5');
+ });
+
+ test('逆运算自洽:CloseQty=720000(=PositionQty)→ ClosePercent=0.7(=oriClosePercent)', () => {
+ const closeQty = PositionQty; // 720000
+ const closePercent = SwapCalc.calcOriginalClosePercentByQty(closeQty, PositionQty, oriClosePercent);
+ expectClose(closePercent, oriClosePercent, '平全部剩余 → ClosePercent=oriClosePercent');
+ });
+
+ test('除零保护:oriClosePercent=0(已全平完)→ CloseQty=0', () => {
+ expect(SwapCalc.calcCloseQtyByOriginalPercent(0.5, 0, 720000)).toBe(0);
+ });
+
+ test('除零保护:PositionQty=0 → ClosePercent=0', () => {
+ expect(SwapCalc.calcOriginalClosePercentByQty(100, 0, oriClosePercent)).toBe(0);
+ });
+
+ // GLMS-20260701-0006 生产 bug:第二次部分平仓 50%(占期初) 时
+ // 32500000 * (0.5 / 0.65) = 24999999.999999996(JS 浮点精度偏差)
+ // roundHalfAwayFromZero 应正确舍入为 25000000
+ test('GLMS-20260701-0006:32500000×(0.5/0.65) 应=25000000 而非 24999999.999999996', () => {
+ const closePercent = 0.5; // 占期初 50%
+ const oriClosePercent = 0.65; // 剩余/期初 = 32500000/50000000
+ const positionQty = 32500000; // 剩余持仓
+ const closeQty = SwapCalc.calcCloseQtyByOriginalPercent(closePercent, oriClosePercent, positionQty);
+ expectClose(closeQty, 25000000, '应=25000000 不受 JS 浮点偏差影响');
+ expect(closeQty).not.toBe(24999999.999999996);
+ });
+});
+
+describe('交叉校验:对齐 C# FrontendCalcCharacterizationTest 金标准', () => {
+ // FC_001 平仓-债券多头-默认
+ test('FC_001 平仓 债券多头 默认', () => {
+ const r = SwapCalc.calcUnwind({
+ multiplier: 100, posiGrossPrice: 1.02, tradingAmountAvg: 105,
+ closeQty: 1000, payDirection: 1, positionType: 1,
+ tradingFee: '20', tradingFeePending: '0', dividendIn: '0'
+ });
+ expectClose(r.MarkClosePnl, 30, 'MarkClosePnl');
+ expectClose(r.FloatPnlSum, 50, 'FloatPnlSum');
+ expectClose(r.SwapRealizedPnL, 50, 'SwapRealizedPnL');
+ });
+
+ // FC_002 改标的价格 105→110
+ test('FC_002 平仓 改标的价格', () => {
+ const r = SwapCalc.calcUnwind({
+ multiplier: 100, posiGrossPrice: 1.02, tradingAmountAvg: 110,
+ closeQty: 1000, payDirection: 1, positionType: 1,
+ tradingFee: '20', tradingFeePending: '0', dividendIn: '0'
+ });
+ expectClose(r.MarkClosePnl, 80, 'MarkClosePnl');
+ expectClose(r.FloatPnlSum, 100, 'FloatPnlSum');
+ });
+
+ // FC_003 改平仓数量 1000→500
+ test('FC_003 平仓 改平仓数量', () => {
+ const r = SwapCalc.calcUnwind({
+ multiplier: 100, posiGrossPrice: 1.02, tradingAmountAvg: 105,
+ closeQty: 500, payDirection: 1, positionType: 1,
+ tradingFee: '20', tradingFeePending: '10', dividendIn: '0'
+ });
+ expectClose(r.MarkClosePnl, 15, 'MarkClosePnl');
+ expectClose(r.FloatPnlSum, 45, 'FloatPnlSum');
+ });
+
+ // FC_004 改利息金额 +100
+ test('FC_004 平仓 改利息金额', () => {
+ const r = SwapCalc.calcUnwind({
+ multiplier: 100, posiGrossPrice: 1.02, tradingAmountAvg: 105,
+ closeQty: 1000, payDirection: 1, positionType: 1,
+ tradingFee: '20', tradingFeePending: '0', dividendIn: '0',
+ interestLegs: [{ interestClosePnL: 100 }]
+ });
+ expectClose(r.MarkClosePnl, 30, 'MarkClosePnl 不受利息影响');
+ expectClose(r.SwapRealizedPnL, 150, '含利息 SwapRealizedPnL');
+ });
+
+ // FC_005 非债券空头 方向因子
+ test('FC_005 平仓 非债券空头 方向因子', () => {
+ const r = SwapCalc.calcUnwind({
+ multiplier: 1, posiGrossPrice: 100, tradingAmountAvg: 105,
+ closeQty: 1000, payDirection: 1, positionType: 2,
+ tradingFee: '0', tradingFeePending: '0', dividendIn: '0'
+ });
+ expectClose(r.MarkClosePnl, -5000, '空头价格涨=亏损');
+ });
+
+ // FC_006 结息 债券多头 全量
+ test('FC_006 结息 债券多头 全量', () => {
+ const r = SwapCalc.calcIncome({
+ multiplier: 100, posiGrossPrice: 1.02, tradingAmountAvg: 105,
+ positionQty: 10000, contractSize: 1,
+ closeNotionalValue: 10200, closeQty: 0, payDirection: 1, positionType: 1,
+ tradingFee: '0', tradingFeePending: '0', dividendIn: '0'
+ });
+ expectClose(r.MarkClosePnl, 300, 'income MarkClosePnl');
+ expectClose(r.SwapRealizedPnL, 300, 'income SwapRealizedPnL');
+ });
+
+ // FC_007 结息 改标的价格 105→110
+ test('FC_007 结息 改标的价格', () => {
+ const r = SwapCalc.calcIncome({
+ multiplier: 100, posiGrossPrice: 1.02, tradingAmountAvg: 110,
+ positionQty: 10000, contractSize: 1,
+ closeNotionalValue: 10200, closeQty: 0, payDirection: 1, positionType: 1,
+ tradingFee: '0', tradingFeePending: '0', dividendIn: '0'
+ });
+ expectClose(r.MarkClosePnl, 800, '改价格后 income MarkClosePnl');
+ });
+
+ // FC_008 结息 含利息腿+预付金腿
+ test('FC_008 结息 含利息腿与预付金腿 总额', () => {
+ const r = SwapCalc.calcIncome({
+ multiplier: 100, posiGrossPrice: 1.02, tradingAmountAvg: 105,
+ positionQty: 10000, contractSize: 1,
+ closeNotionalValue: 10200, closeQty: 0, payDirection: 1, positionType: 1,
+ tradingFee: '0', tradingFeePending: '0', dividendIn: '0',
+ interestLegs: [{ interestClosePnL: 100 }],
+ marginLegs: [{ interestClosePnL: 50 }]
+ });
+ expectClose(r.SwapRealizedPnL, 450, '含利息+预付金 SwapRealizedPnL');
+ expectClose(r.SwapMarginRebatePnl, 50, 'SwapMarginRebatePnl');
+ });
+
+ // FC_009 真实回归:债券结息价差按数量计算,不能误用期初名义本金
+ test('FC_009 结息 债券价差按数量计算', () => {
+ const r = SwapCalc.calcIncome({
+ multiplier: 100, posiGrossPrice: 0.98, tradingAmountAvg: 80,
+ positionQty: 30000000, contractSize: 1,
+ closeNotionalValue: 29400000, closeQty: 0,
+ payDirection: 2, positionType: 1,
+ tradingFee: '0', tradingFeePending: '0', dividendIn: '-45000'
+ });
+ expectClose(r.MarkClosePnl, 5400000, 'income MarkClosePnl按数量计算');
+ expectClose(r.FloatPnlSum, 5355000, 'income FloatPnlSum包含分红');
+ });
+});
diff --git a/YLErpWeb/wwwroot/Scripts/app/eod/eodPriceList.js b/YLErpWeb/wwwroot/Scripts/app/eod/eodPriceList.js
index 2a90fbe5..71843e93 100644
--- a/YLErpWeb/wwwroot/Scripts/app/eod/eodPriceList.js
+++ b/YLErpWeb/wwwroot/Scripts/app/eod/eodPriceList.js
@@ -97,6 +97,21 @@ function SearchClick(isSearchclick) {
listGrid.trigger('reloadGrid');
}
+function openEodPriceAdd() {
+ var html = '
'
+ + '
请选择要新增的日终价格类型:
'
+ + '
'
+ + '
'
+ + '
'
+ + '
';
+ layer.open({ type: 1, title: '新增日终价格', content: html, area: ['300px', '170px'] });
+}
+function chooseEodAdd(type) {
+ var map = { bond: '/eodPrice/EodBondPriceEdit', CommodityFutures: '/eodPrice/EodFuturePriceEdit', Stock: '/eodPrice/EodStockPriceEdit' };
+ layer.closeAll();
+ main.open("新增日终价格", map[type], { area: ['820px', '620px'] });
+}
+
function uploadSettlementBill() {
layer.open({
type: 1,
diff --git a/YLErpWeb/wwwroot/Scripts/app/eod/eodUnderlyingSuggest.js b/YLErpWeb/wwwroot/Scripts/app/eod/eodUnderlyingSuggest.js
new file mode 100644
index 00000000..1c806676
--- /dev/null
+++ b/YLErpWeb/wwwroot/Scripts/app/eod/eodUnderlyingSuggest.js
@@ -0,0 +1,90 @@
+// 日终价格编辑页公共逻辑:标的代码输入联想(服务端模糊匹配 + 原生下拉)
+// 由 eodBondPriceEdit / eodFuturePriceEdit / eodStockPriceEdit 三个页面共用,避免重复代码。
+// 下拉盒子由本文件动态创建、样式全部内联,不依赖任何 HTML 容器或外部 CSS。
+
+$(function () {
+ $(".datepicker").datepicker({ changeMonth: true, changeYear: true, showButtonPanel: true, showOtherMonths: true, selectOtherMonths: true });
+ $(".form-group").addClass("col-md-6");
+ ensureEodSuggestBox();
+});
+
+function checkSubmitData() {
+ var pass = $('#form1').valid();
+ return pass;
+}
+
+var _eodSuggestTimer = null;
+var _eodSuggestActiveInput = null;
+
+function ensureEodSuggestBox() {
+ if (document.getElementById('eodSuggestBox')) return;
+ var box = document.createElement('div');
+ box.id = 'eodSuggestBox';
+ box.style.cssText = 'display:none;position:fixed;z-index:9999;background:#fff;border:1px solid #ccc;' +
+ 'max-height:240px;overflow:auto;box-shadow:0 2px 8px rgba(0,0,0,.15);font-size:13px;';
+ document.body.appendChild(box);
+}
+
+// 服务端模糊联想:输入时按需查前20条匹配(代码或名称),原生下拉,不用插件
+function eodSuggest(input, kind) {
+ _eodSuggestActiveInput = input;
+ clearTimeout(_eodSuggestTimer);
+ var q = (input.value || '').trim();
+ if (q.length < 1) { eodHideSuggest(); return; }
+ _eodSuggestTimer = setTimeout(function () {
+ main.post('/eodPrice/SuggestUnderlyingForEod', { q: q, kind: kind }).done(function (res) {
+ if (res.success && res.obj && res.obj.length) {
+ eodRenderSuggest(res.obj, input, kind);
+ } else {
+ eodHideSuggest();
+ }
+ });
+ }, 250);
+}
+
+function eodRenderSuggest(list, input, kind) {
+ var box = document.getElementById('eodSuggestBox');
+ if (!box) return;
+ box.innerHTML = '';
+ list.forEach(function (item) {
+ var div = document.createElement('div');
+ div.style.cssText = 'padding:6px 10px;cursor:pointer;white-space:nowrap;border-bottom:1px solid #f0f0f0;';
+ div.onmouseenter = function () { div.style.background = '#f2f6ff'; };
+ div.onmouseleave = function () { div.style.background = '#fff'; };
+
+ var code = document.createElement('span');
+ code.style.cssText = 'display:inline-block;min-width:90px;font-weight:600;color:#333;';
+ code.textContent = item.Code;
+ var name = document.createElement('span');
+ name.style.cssText = 'display:inline-block;color:#888;margin-left:10px;';
+ name.textContent = item.Name || '';
+
+ div.appendChild(code); div.appendChild(name);
+ div.onmousedown = function (e) {
+ e.preventDefault();
+ input.value = item.Code;
+ eodHideSuggest();
+ // 按 kind 安全解析各页面自定义的 lookup 回调(函数名字符串,避免引用未定义函数导致 ReferenceError)
+ var fnName = { bond: 'lookupBond', future: 'lookupFuture', stock: 'lookupStock' }[kind];
+ if (fnName && typeof window[fnName] === 'function') window[fnName]();
+ };
+ box.appendChild(div);
+ });
+ var r = input.getBoundingClientRect();
+ box.style.left = r.left + 'px';
+ box.style.top = (r.bottom + 2) + 'px';
+ box.style.width = Math.max(r.width, 240) + 'px';
+ box.style.display = 'block';
+}
+
+function eodHideSuggest() {
+ var b = document.getElementById('eodSuggestBox');
+ if (b) b.style.display = 'none';
+}
+
+document.addEventListener('click', function (e) {
+ var b = document.getElementById('eodSuggestBox');
+ if (b && b.style.display === 'block' && !b.contains(e.target) && e.target !== _eodSuggestActiveInput) {
+ b.style.display = 'none';
+ }
+});
diff --git a/YLErpWeb/wwwroot/Scripts/app/swaptrade/EodPositionRisks.js b/YLErpWeb/wwwroot/Scripts/app/swaptrade/EodPositionRisks.js
index 5abf3e14..99067de4 100644
--- a/YLErpWeb/wwwroot/Scripts/app/swaptrade/EodPositionRisks.js
+++ b/YLErpWeb/wwwroot/Scripts/app/swaptrade/EodPositionRisks.js
@@ -1,5 +1,6 @@
var queryurl = '/swaptrade2/EodPositionRiskQuery';
var cloumnTargetName = "eodSwapPositionList";
+var eodSwapExportColumnNames = [];
$(function () {
var PostData = {};
$("#DateValueDate").datepicker({
@@ -18,6 +19,11 @@ $(function () {
$("#myTab li:eq(1)").addClass("active");
cloumnTargetName = "eodSwapList";
colModelGrid = colModelGridEodSwap();
+ eodSwapExportColumnNames = colModelGrid.filter(function (col) {
+ return !col.optionHide;
+ }).map(function (col) {
+ return col.name;
+ });
}
PostData.ValueDate = $("#DateValueDate").val();
var grid = jQuery('#listGrid').jqGrid({
@@ -457,6 +463,7 @@ function colModelGridEodPosition() {
}
//框架合约table
function colModelGridEodSwap() {
+ //按需求《估值模块V1》2.2 分组定义排列列顺序,确保组内列连续(setGroupHeaders 要求)
var colModelGrid = [{
name: 'position.id',
label: 'id',
@@ -475,7 +482,9 @@ function colModelGridEodSwap() {
align: 'center',
hidden: true,
optionHide: true
- }, {
+ },
+ //=== 基本信息 ===
+ {
name: 'position.ValueDate',
label: '交易日',
index: 'position.ValueDate',
@@ -513,6 +522,22 @@ function colModelGridEodSwap() {
width: 90,
align: 'center',
}, {
+ name: 'SwapTradeTypeStr',
+ label: '互换类型',
+ index: 'SwapTradeTypeStr',
+ width: 100,
+ align: 'center',
+ sortable: false
+ }, {
+ name: 'UnderlyingType',
+ label: '标的类型',
+ index: 'UnderlyingType',
+ width: 100,
+ align: 'center',
+ sortable: false
+ },
+ //=== 名义本金 ===
+ {
name: 'position.NotionalValue',
label: '合约名义本金',
index: 'position.NotionalValue',
@@ -533,7 +558,9 @@ function colModelGridEodSwap() {
width: 150,
align: 'center',
formatter: StockEqvNotionalFormat
- }, {
+ },
+ //=== 标的市值 ===
+ {
name: 'position.MarketValueLong',
label: '合约多头标的市值',
index: 'position.MarketValueLong',
@@ -547,70 +574,81 @@ function colModelGridEodSwap() {
width: 150,
align: 'center',
formatter: StockEqvNotionalFormat
- }, {
- name: 'position.FloatingPnL',
+ },
+ //=== 浮动端 ===
+ {
+ name: 'FloatingUnrealizedPnl',
label: '合约浮动端待实现收益',
- index: 'position.FloatingPnL',
+ index: 'FloatingUnrealizedPnl',
width: 150,
align: 'center',
formatter: StockEqvNotionalFormat,
}, {
+ name: 'PeriodAmount',
+ label: '期间付息/分红',
+ index: 'PeriodAmount',
+ width: 150,
+ align: 'center',
+ formatter: StockEqvNotionalFormat,
+ cellattr: function () {
+ return ' title="合约期间内的期间付息金额(无关乎派息支付日)"';
+ },
+ },
+ //=== 利息端 ===
+ {
name: 'position.InterestPnL',
- label: '合约利率端待实现收益',
+ label: '合约利息端待实现收益',
index: 'position.InterestPnL',
width: 150,
align: 'center',
formatter: otcformat.trading.notional,
- }, {
- name: 'position.PostionValue',
- label: '合约持仓价值',
- index: 'position.PostionValue',
- width: 150,
- align: 'center',
- formatter: StockEqvNotionalFormat
- }, {
- name: 'position.TdRealizedPnL',
- label: '合约当日实现收益',
- index: 'position.TdRealizedPnL',
- width: 150,
- align: 'center',
- formatter: StockEqvNotionalFormat
- }, {
- name: 'position.RealizedPnL',
- label: '合约已实现收益',
- index: 'position.RealizedPnL',
- width: 150,
- align: 'center',
- formatter: StockEqvNotionalFormat,
- }, {
+ },
+ //=== 保证金 ===
+ {
name: 'position.InitMarginGain',
- label: '收取对手方初始预付金',
+ label: '收取对手方初始保证金',
index: 'position.InitMarginGain',
width: 150,
align: 'center',
formatter: StockEqvNotionalFormat,
}, {
name: 'position.PostionMarginGain',
- label: '收取对手方维持预付金',
+ label: '收取对手方维持保证金',
index: 'position.PostionMarginGain',
width: 150,
align: 'center',
formatter: StockEqvNotionalFormat,
}, {
name: 'position.InitMarginLoss',
- label: '支付初始预付金',
+ label: '支付初始保证金',
index: 'position.InitMarginLoss',
width: 150,
align: 'center',
formatter: StockEqvNotionalFormat,
}, {
name: 'position.PostionMarginLoss',
- label: '支付维持预付金',
+ label: '支付维持保证金',
index: 'position.PostionMarginLoss',
width: 150,
align: 'center',
formatter: StockEqvNotionalFormat,
}, {
+ name: 'MarginInterestGain',
+ label: '收取对手方保证金利息',
+ index: 'MarginInterestGain',
+ width: 170,
+ align: 'center',
+ formatter: StockEqvNotionalFormat,
+ }, {
+ name: 'MarginInterestLoss',
+ label: '支付对手方保证金利息',
+ index: 'MarginInterestLoss',
+ width: 170,
+ align: 'center',
+ formatter: StockEqvNotionalFormat,
+ },
+ //=== 估值与实现收益 ===
+ {
name: 'position.dv01',
label: 'DV',
index: 'position.dv01',
@@ -623,25 +661,67 @@ function colModelGridEodSwap() {
return cellvalue.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 4 });
},
}, {
- name: 'SwapTradeTypeStr',
- label: '互换类型',
- index: 'SwapTradeTypeStr',
- width: 100,
+ name: 'InterestPaymentMethod',
+ label: '付息方式',
+ index: 'InterestPaymentMethod',
+ width: 120,
align: 'center',
- sortable: false
+ }, {
+ name: 'MaturityNettingValuation',
+ label: '合约估值(到期轧差口径)',
+ index: 'MaturityNettingValuation',
+ width: 190,
+ align: 'center',
+ formatter: NullableStockEqvNotionalFormat,
+ }, {
+ name: 'PeriodPaymentValuation',
+ label: '合约估值(期间支付派息口径)',
+ index: 'PeriodPaymentValuation',
+ width: 210,
+ align: 'center',
+ formatter: NullableStockEqvNotionalFormat,
+ }, {
+ name: 'position.RealizedPnL',
+ label: '合约已实现收益',
+ index: 'position.RealizedPnL',
+ width: 150,
+ align: 'center',
+ formatter: StockEqvNotionalFormat,
}
];
return colModelGrid;
}
+//框架合约分组配置(对应需求《估值模块V1》2.2 字段定义)
+//columns 使用 colModel.name;组内列在 colModel 中必须连续
+var eodSwapGroupConfig = [
+ { title: '基本信息', columns: ['position.ValueDate', 'AssetBookName', 'ClientName', 'SwapTradeNo', 'StructureType', 'SwapTradeTypeStr', 'UnderlyingType'] },
+ { title: '名义本金', columns: ['position.NotionalValue', 'position.NotionalValueLong', 'position.NotionalValueShort'] },
+ { title: '标的市值', columns: ['position.MarketValueLong', 'position.MarketValueShort'] },
+ { title: '浮动端', columns: ['FloatingUnrealizedPnl', 'PeriodAmount'] },
+ { title: '利息端', columns: ['position.InterestPnL'] },
+ { title: '保证金', columns: ['position.InitMarginGain', 'position.PostionMarginGain', 'position.InitMarginLoss', 'position.PostionMarginLoss', 'MarginInterestGain', 'MarginInterestLoss'] },
+ { title: '估值与实现收益', columns: ['position.dv01', 'InterestPaymentMethod', 'MaturityNettingValuation', 'PeriodPaymentValuation', 'position.RealizedPnL'] }
+];
+
function gridComplete() {
var jgrid = $(this);
if (arguments[0].Sum) {
jgrid.footerData("set", { 'position.dv01': arguments[0].Sum["DV"] });
}
- main.setcolumnChooser(jgrid, page.configcolumn_data);
+ //框架合约Tab:列设置应用完成后补充期间付息提示。
+ if (page.tabIndex == 2) {
+ var defer = main.setcolumnChooser(jgrid, cloumnTargetName);
+ $.when(defer).done(function () {
+ jgrid.jqGrid('setLabel', 'PeriodAmount', null, null, {
+ title: '合约期间内的期间付息金额(无关乎派息支付日)'
+ });
+ });
+ } else {
+ main.setcolumnChooser(jgrid, page.configcolumn_data);
+ }
$(window).resize();
}
@@ -657,6 +737,67 @@ function starttradeView(id) {
main.open("查看交易", srcurl);
}
+function exportVisibleColumns() {
+ var jgrid = jQuery('#listGrid');
+ var dateStr = $("#DateValueDate").val() || '';
+ var tabName = page.tabIndex == 2 ? '框架合约' : '日终持仓';
+ var fileName = '日终持仓风险_互换_' + tabName + (dateStr ? '_' + dateStr : '');
+ if (page.tabIndex != 2) {
+ main.exportVisibleColumnsToExcel(jgrid, fileName, null);
+ return;
+ }
+
+ layer.open({
+ type: 1,
+ title: '选择导出方式',
+ shadeClose: false,
+ shade: 0.4,
+ area: ['300px', '200px'],
+ content: '
',
+ success: function (layero, index) {
+ layero.find('.js-export-eod-swap-standard').on('click', function () {
+ exportEodSwapRows(jgrid, fileName, eodSwapGroupConfig, eodSwapExportColumnNames);
+ layer.close(index);
+ });
+ layero.find('.js-export-eod-swap-visible').on('click', function () {
+ exportEodSwapRows(jgrid, fileName, null, getVisibleEodSwapBusinessColumnNames(jgrid));
+ layer.close(index);
+ });
+ }
+ });
+}
+
+function getVisibleEodSwapBusinessColumnNames(jgrid) {
+ var colModel = jgrid.jqGrid('getGridParam', 'colModel') || [];
+ return colModel.filter(function (col) {
+ return col.hidden !== true && !col.optionHide && col.name !== 'cb' && col.name !== 'rn';
+ }).map(function (col) {
+ return col.name;
+ });
+}
+
+function exportEodSwapRows(jgrid, fileName, groupConfig, exportColumnNames) {
+ var exportPostData = $.extend({}, GetPostData(), {
+ page: 1,
+ rows: 0,
+ sidx: jgrid.jqGrid('getGridParam', 'sortname'),
+ sord: jgrid.jqGrid('getGridParam', 'sortorder')
+ });
+ $.ajax({
+ url: queryurl,
+ type: 'POST',
+ dataType: 'json',
+ traditional: true,
+ data: exportPostData
+ }).done(function (result) {
+ main.exportVisibleColumnsToExcel(jgrid, fileName, groupConfig, result && result.rows ? result.rows : [], exportColumnNames);
+ }).fail(function () {
+ main.message && main.message('导出失败,无法获取筛选后的全部数据');
+ });
+}
//---------------------------Formatter---------------------------------
function PriceFormat(cellValue, options, rowObject) {
return otcformat.trading.umprice(cellValue);
@@ -669,6 +810,12 @@ function RealizedPnlFormat(cellValue, options, rowObject) {
function StockEqvNotionalFormat(cellValue, options, rowObject) {
return otcformat.trading.StockEqvNotional(cellValue);
}
+function NullableStockEqvNotionalFormat(cellValue, options, rowObject) {
+ if (cellValue === null || cellValue === undefined || cellValue === '') {
+ return '';
+ }
+ return StockEqvNotionalFormat(cellValue, options, rowObject);
+}
function PosiStatusFormat(cellValue, options, rowObject) {
return cellValue == 1 ? "已平" : "正常";
}
@@ -767,4 +914,4 @@ function SearchClick(isSearchclick) {
function showcolumnChooser() {
var jgrid = jQuery('#listGrid');
main.showcolumnChooser(jgrid, cloumnTargetName, page.configcolumn_data);
-}
\ No newline at end of file
+}
diff --git a/YLErpWeb/wwwroot/Scripts/app/swaptrade/TradeMarketReport_EodPosition.js b/YLErpWeb/wwwroot/Scripts/app/swaptrade/TradeMarketReport_EodPosition.js
index 15284100..1642cdaf 100644
--- a/YLErpWeb/wwwroot/Scripts/app/swaptrade/TradeMarketReport_EodPosition.js
+++ b/YLErpWeb/wwwroot/Scripts/app/swaptrade/TradeMarketReport_EodPosition.js
@@ -2,32 +2,16 @@
$(function () {
var PostData = {};
- //控件选择时的触发事件
- main.setTradeDatePicker("", "#ValueDate", page.calcDate, function (selectedDate) {
- if (selectedDate) {
- $("#ValueDateFrom").datepicker("option", "maxDate", selectedDate);
- }
- });
- main.setTradeDatePicker("", "#ValueDateFrom", page.calcDate, function (selectedDate) {
- if (selectedDate) {
- $("#ValueDate").datepicker("option", "minDate", selectedDate);
- }
- });
- //手动修改时的触发事件
- $("#ValueDate").change(function () {
- $("#ValueDateFrom").datepicker("option", "maxDate", $("#ValueDate").val());
- });
- $("#ValueDateFrom").change(function () {
- $("#ValueDate").datepicker("option", "minDate", $("#ValueDateFrom").val());
- });
+ main.setTradeDatePicker("", "#ValueDate", page.calcDate);
- //默认初始值赋值逻辑
+ // 互换估值页仅暴露一个估值日。当前后端按 ValueDate 单日查询,
+ // 因此 ValueDateFrom 传同日仅用于保持请求对象和报告参数的日期语义一致。
$("#ValueDate").val(page.EndTime || page.calcDate);
- $("#ValueDateFrom").val(page.StartTime && page.EndTime ? page.StartTime : '');
PostData.StructureType = page.StructureType;
- PostData.ValueDateFrom = $("#ValueDateFrom").val();
+ PostData.ValueDateFrom = $("#ValueDate").val();
PostData.ValueDate = $("#ValueDate").val();
PostData.ClientId = $("#ClientId").val();
+ PostData.BookId = $("#BookId").val();
var grid = jQuery('#listGrid').jqGrid({
url: '/swaptrade2/clientEodSwapPositionQuery',
@@ -50,8 +34,7 @@ $(function () {
pagerpos: 'left',
rowNum: 100,
rowList: [100, 1000],
- loadComplete: gridComplete,
- grouping: true
+ loadComplete: gridComplete
});
g_grid = jQuery('#listGrid');
@@ -91,6 +74,8 @@ function SearchTable(isSearchclick) {
function searchPositionDetials(isSearchclick) {
var listGrid = $('#listGrid');
listGrid.appendPostData({ ClientId: $("#ClientId").val() });
+ //簿记账户筛选(需求3.1):未选择时传空,后端返回该对手方下全部账户的合约
+ listGrid.appendPostData({ BookId: $("#BookId").val() });
listGrid.appendPostData({ ValueDate: $("#ValueDate").val() });
if ($("#ParentFlag").prop("checked"))
listGrid.appendPostData({ ParentFlag: true });
@@ -108,11 +93,7 @@ function searchPositionDetials(isSearchclick) {
// main.message("结束日期不能大于当前系统日期!");
// return;
//}
- if ($("#ValueDate").val() < $("#ValueDateFrom").val()) {
- main.message("起始日期不能大于结束日期!");
- return;
- }
- listGrid.appendPostData({ ValueDateFrom: $("#ValueDateFrom").val() });
+ listGrid.appendPostData({ ValueDateFrom: $("#ValueDate").val() });
listGrid.appendPostData({ ValueDate: $("#ValueDate").val() });
listGrid.appendPostData({ StructureType: page.StructureType });
if (typeof (isSearchclick) != "undefined" && isSearchclick) {
@@ -132,6 +113,7 @@ function onSortCol(index, icol, sortorder) {
var i = 0;
var colModelGrid = [
+ //隐藏列
{
name: 'position.EncryptId',
label: 'EncryptId',
@@ -153,14 +135,6 @@ var colModelGrid = [
index: 'UnwindDate',
hidden: true,
optionHide: true
- }, {
- name: 'TradeNumber',
- label: '交易编号',
- index: 'TradeNumber',
- sortIndex: i++,
- width: 180,
- align: 'center',
- sortable: false
}, {
name: 'ConfrimNo',
label: '确认书编号',
@@ -170,11 +144,11 @@ var colModelGrid = [
align: 'center',
sortable: false
}, {
- name: 'ClientName',
- label: '交易对手',
- index: 'ClientName',
+ name: 'TradeNumber',
+ label: '交易编号',
+ index: 'TradeNumber',
sortIndex: i++,
- width: 120,
+ width: 180,
align: 'center',
sortable: false
}, {
@@ -186,6 +160,15 @@ var colModelGrid = [
align: 'center',
sortable: false,
formatter:'date',
+ }, {
+ name: 'MaturitySettlementDate',
+ label: '到期结算日',
+ index: 'MaturitySettlementDate',
+ sortIndex: i++,
+ width: 100,
+ align: 'center',
+ sortable: false,
+ formatter: 'date',
}, {
name: 'position.ValueDate',
label: '估值日',
@@ -209,22 +192,7 @@ var colModelGrid = [
width: 120,
align: 'center',
sortable: false,
- formatter: RateFormat
- }, {
- name: 'position.FloatRateUnderlyingCode',
- label: '基准利率',
- index: 'position.FloatRateUnderlyingCode',
- width: 120,
- align: 'center',
- sortable: false
- }, {
- name: 'position.FloatRate',
- label: '当日适用基准利率',
- index: 'position.FloatRate',
- width: 120,
- align: 'center',
- sortable: false,
- formatter: RateFormat
+ formatter: SpreadRateFormat
}, {
name: 'position.PosiNotionalValue',
label: '标的名义金额',
@@ -232,7 +200,7 @@ var colModelGrid = [
width: 150,
align: 'center',
sortable: false,
- formatter: StockEqvNotionalFormat,
+ formatter: AmountFormat,
}, {
name: 'position.PosiQuantity',
label: '标的数量',
@@ -247,6 +215,15 @@ var colModelGrid = [
index: 'PeriodAmount',
width: 100,
align: 'center',
+ formatter: NullableAmountFormat,
+ sortable: false
+ }, {
+ name: 'DividendAmount',
+ label: '期间分红',
+ index: 'DividendAmount',
+ width: 100,
+ align: 'center',
+ formatter: NullableAmountFormat,
sortable: false
}, {
name: 'position.PosiGrossPrice',
@@ -263,12 +240,7 @@ var colModelGrid = [
width: 150,
align: 'center',
sortable: false,
- formatter: function (cellValue, options, rowObject) {
- if (cellValue == null) {
- return "";
- }
- return otcformat.trading.premiumRateP(cellValue);
- }
+ formatter: YieldRateFormat
},
{
name: 'position.UnderlyingPrice',
@@ -299,15 +271,7 @@ var colModelGrid = [
index: 'InterestAmount',
width: 120,
align: 'center',
- formatter: StockEqvNotionalFormat,
- sortable: false,
- }, {
- name: 'position.PosiFeePending',
- label: '开仓交易费用',
- index: 'position.PosiFeePending',
- width: 120,
- align: 'center',
- formatter: StockEqvNotionalFormat,
+ formatter: FixedAmountFormat,
sortable: false,
}, {
name: 'position.PosiProfitSum',
@@ -315,7 +279,47 @@ var colModelGrid = [
index: 'position.PosiProfitSum',
width: 120,
align: 'center',
- formatter: StockEqvNotionalFormat,
+ formatter: FixedAmountFormat,
+ sortable: false,
+ }, {
+ name: 'position.PosiFeePending',
+ label: '开平仓交易费用',
+ index: 'position.PosiFeePending',
+ width: 120,
+ align: 'center',
+ formatter: FixedAmountFormat,
+ sortable: false,
+ }, {
+ name: 'OpenMarginRate',
+ label: '预付金利率',
+ index: 'OpenMarginRate',
+ width: 120,
+ align: 'center',
+ formatter: TrimmedRateFormat,
+ sortable: false,
+ }, {
+ name: 'MarginInterestAmount',
+ label: '预付金利息',
+ index: 'MarginInterestAmount',
+ width: 120,
+ align: 'center',
+ formatter: FixedAmountFormat,
+ sortable: false,
+ }, {
+ name: 'OpenMarginAmount',
+ label: '期初预付金',
+ index: 'OpenMarginAmount',
+ width: 120,
+ align: 'center',
+ formatter: FixedAmountFormat,
+ sortable: false,
+ }, {
+ name: 'AdditionalMarginAmount',
+ label: '追加预付金',
+ index: 'AdditionalMarginAmount',
+ width: 120,
+ align: 'center',
+ formatter: FixedAmountFormat,
sortable: false,
}, {
name: 'NetSettmentAmount',
@@ -323,10 +327,23 @@ var colModelGrid = [
index: 'NetSettmentAmount',
width: 120,
align: 'center',
- formatter: StockEqvNotionalFormat,
+ formatter: FixedAmountFormat,
+ sortable: false,
+ }, {
+ name: 'TrsValue',
+ label: 'TRS估值',
+ index: 'TrsValue',
+ width: 120,
+ align: 'center',
+ formatter: FixedAmountFormat,
sortable: false,
}
];
+// 页面字段顺序以《估值模块V1》第二部分为准;历史个人列配置只能控制显隐,不能打乱业务列顺序。
+var defaultVisibleColumnNames = colModelGrid
+ .filter(function (column) { return column.hidden !== true; })
+ .map(function (column) { return column.name; });
+var documentColumnOrder = colModelGrid.map(function (column) { return column.name; });
function formatter6(cellvalue, options, rowObject) {
return main.formatNumber(cellvalue, 6);
@@ -356,11 +373,37 @@ function gridComplete() {
}
}
//jgrid.sortGrid(g_sort.name, g_sort.order);
- main.setcolumnChooser(jgrid, page.configcolumn);
+ $.when(main.setcolumnChooser(jgrid, page.configcolumn)).always(function () {
+ restoreDocumentColumnOrder(jgrid);
+ ensureBusinessColumnsVisible(jgrid);
+ });
$(".selftooltip").tooltip({ html: true, show: 50000, trigger: "hover" });
$(window).off('resize.jqGrid');
}
+function restoreDocumentColumnOrder(jgrid) {
+ var colModel = jgrid.jqGrid('getGridParam', 'colModel') || [];
+ var currentNames = colModel.map(function (column) { return column.name; });
+ var targetNames = currentNames
+ .filter(function (name) { return documentColumnOrder.indexOf(name) < 0; })
+ .concat(documentColumnOrder);
+ var permutation = targetNames.map(function (name) { return currentNames.indexOf(name); });
+ if (permutation.length === currentNames.length
+ && permutation.every(function (index) { return index >= 0; })
+ && permutation.some(function (index, targetIndex) { return index !== targetIndex; })) {
+ jgrid.jqGrid('remapColumns', permutation, true);
+ }
+}
+
+function ensureBusinessColumnsVisible(jgrid) {
+ var colModel = jgrid.jqGrid('getGridParam', 'colModel') || [];
+ var hasVisibleBusinessColumn = colModel.some(function (column) {
+ return defaultVisibleColumnNames.indexOf(column.name) >= 0 && column.hidden !== true;
+ });
+ if (!hasVisibleBusinessColumn) {
+ jgrid.jqGrid('showCol', defaultVisibleColumnNames);
+ }
+}
function reloadTradeMarketReport() {
//重新加载
@@ -400,10 +443,6 @@ function SendReport() {
main.message("结束日期不能大于当前系统日期!");
return;
}
- if ($("#ValueDate").val() < $("#ValueDateFrom").val()) {
- main.message("起始日期不能大于结束日期!");
- return;
- }
main.open("向{0}发送报告".template(clientName), "/clientbalance/TradeMarketClientSend?clientid=" + param.ClientId + "&ParentFlag=" + param.ParentFlag);
}
function DownLoadReport() {
@@ -424,18 +463,16 @@ function DownLoadReport() {
main.message("结束日期不能大于当前系统日期!");
return;
}
- if ($("#ValueDate").val() < $("#ValueDateFrom").val()) {
- main.message("起始日期不能大于结束日期!");
- return;
- }
-
main.post("/clientbalance/ViewTradeMarketFile", screenData()).done(function (res) {
window.open(res.obj);
});
}
function screenData() {
- var data = { From: $("#ValueDateFrom").val(), To: $("#ValueDate").val() };
+ // 已移除起始日期控件,预览报告按单个估值日生成,From/To 保持同日。
+ var data = { From: $("#ValueDate").val(), To: $("#ValueDate").val() };
data.ClientId = $("#ClientId").val();
+ // 报告下载和发送弹窗均从 screenData 取参数,必须保留当前簿记账户筛选。
+ data.BookId = $("#BookId").val();
if ($("#ParentFlag").prop("checked"))
data.ParentFlag = true;
else
@@ -447,12 +484,35 @@ function showChiCang() {
main.showcolumnChooser(jQuery('#listGrid'), page.configcolumn);
}
function PriceFormat(cellValue, options, rowObject) {
- return otcformat.trading.umprice(cellValue);
+ return main.formatNumber(cellValue, 9, { grouping: true });
}
function StockEqvNotionalFormat(cellValue, options, rowObject) {
return otcformat.trading.StockEqvNotional(cellValue);
}
+function AmountFormat(cellValue, options, rowObject) {
+ return main.formatNumber(cellValue, 2, { trimTailZeros: true });
+}
+function NullableAmountFormat(cellValue, options, rowObject) {
+ if (cellValue === null || cellValue === undefined || cellValue === '') {
+ return '';
+ }
+ return AmountFormat(cellValue, options, rowObject);
+}
+function FixedAmountFormat(cellValue, options, rowObject) {
+ return main.formatNumber(cellValue, 2);
+}
+function YieldRateFormat(cellValue, options, rowObject) {
+ if (cellValue === null || cellValue === undefined || cellValue === '') {
+ return '';
+ }
+ // percent 格式会在数字末尾添加 %,通用 trimTailZeros 无法识别其后的 0。
+ // 先将小数收益率转为百分比数值,再格式化并追加 %,确保最多保留四位小数且去尾零。
+ return main.formatNumber(cellValue * 100, 4, { trimTailZeros: true }) + '%';
+}
+function TrimmedRateFormat(cellValue, options, rowObject) {
+ return main.formatNumber(cellValue, 4, { percent: true, trimTailZeros: true });
+}
function RateFormat(cellValue, options, rowObject) {
if (cellValue) {
var num = new Number(cellValue) * 100;
@@ -461,19 +521,23 @@ function RateFormat(cellValue, options, rowObject) {
return "0.0000%";
}
}
+function SpreadRateFormat(cellValue, options, rowObject) {
+ if (cellValue) {
+ var num = new Number(cellValue) * 100;
+ return num.toFixed(2) + "%";
+ } else {
+ return "0.00%";
+ }
+}
function locationChange(tab) {
if ($("#ValueDate").val() > page.valueDate) {
main.message("结束日期不能大于当前系统日期!");
return;
}
- if ($("#ValueDate").val() < $("#ValueDateFrom").val()) {
- main.message("起始日期不能大于结束日期!");
- return;
- }
if ($("#ParentFlag").prop("checked"))
ParentFlag = true;
else
ParentFlag = false;
- window.location.href = tab + "?clientId=" + $("#ClientId").val() + "&startTime=" + $("#ValueDateFrom").val() + "&endTime=" + $("#ValueDate").val() + "&ParentFlag=" + ParentFlag;
+ window.location.href = tab + "?clientId=" + $("#ClientId").val() + "&startTime=" + $("#ValueDate").val() + "&endTime=" + $("#ValueDate").val() + "&ParentFlag=" + ParentFlag;
return;
}
diff --git a/YLErpWeb/wwwroot/Scripts/app/swaptrade/incomeSwapTrade.js b/YLErpWeb/wwwroot/Scripts/app/swaptrade/incomeSwapTrade.js
index 019e302f..7acad7c4 100644
--- a/YLErpWeb/wwwroot/Scripts/app/swaptrade/incomeSwapTrade.js
+++ b/YLErpWeb/wwwroot/Scripts/app/swaptrade/incomeSwapTrade.js
@@ -9,6 +9,19 @@ const inputFormatDividend = Object.freeze({ precision: 2, append: '', negative:
const inputFormatMarginRate = Object.freeze({ precision: otcformat.trading.marginRateP.precision, append: '%' });
const inputFormatMarginRateNoPercent = Object.freeze({ precision: otcformat.trading.umpriceP.precision, append: '', percent: true });
let ValueDate = model.ValueDate;
+let MaxIncomeValueDate = model.MaxIncomeValueDate ? model.MaxIncomeValueDate.substr(0, 10) : ValueDate;
+
+function parseLocalDate(value) {
+ if (!value) {
+ return null;
+ }
+ var parts = value.substr(0, 10).split('-');
+ if (parts.length !== 3) {
+ return null;
+ }
+ return new Date(Number(parts[0]), Number(parts[1]) - 1, Number(parts[2]));
+}
+
const vue = new Vue({
el: '#vueDiv',
data: {
@@ -22,7 +35,7 @@ const vue = new Vue({
},
computed: {
maxUnwindDate() {
- return ValueDate;
+ return MaxIncomeValueDate;
},
minStartDate() {
return this.deal.StartDate;
@@ -33,9 +46,36 @@ const vue = new Vue({
this.initDeal();
this.setValueDate();
},
+ mounted() {
+ this.$nextTick(() => {
+ var $incomeValueDatePicker = $(this.$refs.incomeValueDatePicker.$el);
+ $incomeValueDatePicker.datepicker("option", "maxDate", parseLocalDate(MaxIncomeValueDate));
+ if (this.isAfterMaxIncomeValueDate(this.deal.ValueDate)) {
+ this.validateIncomeValueDate(this.deal.ValueDate);
+ } else {
+ $incomeValueDatePicker.val(this.deal.ValueDate);
+ }
+ });
+ },
methods: {
+ isAfterMaxIncomeValueDate(valueDate) {
+ return valueDate && MaxIncomeValueDate && valueDate > MaxIncomeValueDate;
+ },
+ validateIncomeValueDate(valueDate) {
+ if (!this.isAfterMaxIncomeValueDate(valueDate)) {
+ return true;
+ }
+ main.message("手动互换结算日期不能晚于当前交易结束日期T-1:" + MaxIncomeValueDate);
+ this.deal.ValueDate = MaxIncomeValueDate;
+ this.deal.UnwindDate = MaxIncomeValueDate;
+ this.floatPosition.UnwindDate = MaxIncomeValueDate;
+ $(this.$refs.incomeValueDatePicker.$el).val(MaxIncomeValueDate);
+ return false;
+ },
+ // 守卫: 价格缩放因子(债券 multiplier=100 时界面为百分比态, 计算用相对价需 ÷100)
+ // 计算已外置到 swapCalc.getPriceScale; 改动需同步 swapCalc.test.js
getPriceScale() {
- return this.multiplier == 100 ? 0.01 : 1;
+ return SwapCalc.getPriceScale(this.multiplier);
},
initDeal() {
var positions = model.FlowEvents.filter((item) => {
@@ -46,7 +86,13 @@ const vue = new Vue({
this.initPosiGrossPrice = this.floatPosition.PosiGrossPrice;
// 互换标的价格固定为期初净价,与平仓不同不需要用户填写
// 期初净价入库为相对价(如1.02),需转换为界面百分比形态(102),与平仓页保持一致
- this.floatPosition.TradingAmountAvg = this.initPosiGrossPrice * this.multiplier;
+ // 普通打开时用期初全价作为默认值;审批打开时必须保留已提交的期末全价,不能再被期初全价覆盖。
+ // 两种来源入库时都是相对价,债券统一 ×100 还原为界面百分比态。
+ this.floatPosition.TradingAmountAvg = SwapCalc.resolveIncomeTradingAmountAvg(
+ this.initPosiGrossPrice,
+ this.floatPosition.TradingAmountAvg,
+ this.multiplier,
+ isUseApproval);
this.interestList = model.FlowEvents.filter((item) => {
return item.InterestMode == 1 || item.InterestMode == 2 || item.InterestMode == 7 || item.InterestMode == 8 || item.InterestMode == 9;
});
@@ -93,6 +139,9 @@ const vue = new Vue({
},
setValueDate(e) {//修改平仓日期
if (e) {
+ if (!this.validateIncomeValueDate(e)) {
+ e = MaxIncomeValueDate;
+ }
this.deal.ValueDate = e;
this.deal.UnwindDate = e;
this.floatPosition.UnwindDate = e;
@@ -132,10 +181,14 @@ const vue = new Vue({
let TradingFeePending = thisObj.floatPosition.TradingFeePending == "" ? 0 : parseFloat(thisObj.floatPosition.TradingFeePending);
let DividendIn = thisObj.floatPosition.DividendIn == "" ? 0 : parseFloat(thisObj.floatPosition.DividendIn ?? 0);
let scale = thisObj.getPriceScale();
- //thisObj.floatPosition.MarkClosePnl = thisObj.deal.CloseNotionalValue * (thisObj.floatPosition.TradingAmountAvg * scale - thisObj.initPosiNetPrice) * floatRatio;
- thisObj.floatPosition.MarkClosePnl = thisObj.deal.CloseNotionalValue * (thisObj.floatPosition.TradingAmountAvg * scale - thisObj.initPosiGrossPrice) * floatRatio;
+ // 债券全价是单位价格,价差盈亏应按持仓数量×合约乘数计算;
+ // CloseNotionalValue 是期初全价折算后的名义本金,直接乘价差会重复包含期初价格。
+ let positionAmount = parseFloat(thisObj.floatPosition.Quantity) * parseFloat(thisObj.floatPosition.ContractSize || 1);
+ thisObj.floatPosition.MarkClosePnl = positionAmount * (thisObj.floatPosition.TradingAmountAvg * scale - thisObj.initPosiGrossPrice) * floatRatio;
thisObj.floatPosition.MarkClosePnl = otcformat.trading.StockEqvNotional(thisObj.floatPosition.MarkClosePnl);//MarkClosePnl 纯盯市不要计算交易费用和分红
- thisObj.floatPosition.FloatPnlSum = (parseFloat(thisObj.floatPosition.MarkClosePnl) + TradingFee + TradingFeePending + DividendIn).toFixed(2);
+ // 守卫: 浮动盈亏合计必须保留 2 位小数 → 对应历史 bug 3c5f25a5(原代码缺精度保留)
+ // 数值由 swapCalc.calcFloatPnlSum 计算, 此处 .toFixed(2) 仅保留字符串类型以兼容下游
+ thisObj.floatPosition.FloatPnlSum = SwapCalc.calcFloatPnlSum(thisObj.floatPosition.MarkClosePnl, TradingFee, TradingFeePending, DividendIn).toFixed(2);
thisObj.calcCloseAmount();
},
//calcClosePnL() {//计算浮动端平仓盈亏
@@ -212,6 +265,9 @@ const vue = new Vue({
main.message("请输入平仓日期");
return;
}
+ if (!thisObj.validateIncomeValueDate(thisObj.deal.ValueDate)) {
+ return;
+ }
let reqObj = _.cloneDeep(thisObj.deal);
let marginCloneList = _.cloneDeep(thisObj.marginList);
reqObj.FlowEvents = _.cloneDeep(thisObj.interestList);
diff --git a/YLErpWeb/wwwroot/Scripts/app/swaptrade/swapCalc.js b/YLErpWeb/wwwroot/Scripts/app/swaptrade/swapCalc.js
new file mode 100644
index 00000000..f18f520c
--- /dev/null
+++ b/YLErpWeb/wwwroot/Scripts/app/swaptrade/swapCalc.js
@@ -0,0 +1,219 @@
+/**
+ * swapCalc.js — 互换结算/平仓纯计算函数(与 C# FrontendCalcReference 对齐)
+ * ============================================================================
+ * 设计要点:
+ * - 无 Vue / otcformat / jQuery / lodash 依赖,全部为纯函数,便于 jest 直接 import。
+ * - 浏览器:挂到 window.SwapCalc(需在 incomeSwapTrade.js / swapTradeEdit.js 之前加载)。
+ * - Node: module.exports(UMD 包装),供 fe-tests/*.test.js 使用。
+ * - 公式与 YLErpDAL/Helpers/FrontendCalcReference.cs 保持一致,是前后端同一份金标准。
+ *
+ * 生产接线状态(tested == used):incomeSwapTrade.js / swapTradeEdit.js 已调用
+ * getPriceScale / deriveTradingAmountAvg / calcFloatPnlSum / calcStockEqvNotional
+ * 这 4 个叶子函数(对应真实出过的 4 个 bug:20ea93d8 / dcf649f2 / 3c5f25a5 / f873239a)。
+ * calcUnwind / calcIncome 仅用于 swapCalc.test.js 的前后端金标准交叉校验,未接入生产代码。
+ *
+ * 守卫的 bug(见 git 历史):
+ * - 20ea93d8 / dcf649f2:deriveTradingAmountAvg 必须用 PosiGrossPrice(全价) 且债券 ×100
+ * - 3c5f25a5:calcFloatPnlSum 必须 .toFixed(2)(保留 2 位小数)
+ * - f873239a:calcStockEqvNotional 必须 round 到 2 位
+ * ============================================================================
+ */
+(function (root, factory) {
+ if (typeof module === 'object' && module.exports) {
+ module.exports = factory();
+ } else {
+ root.SwapCalc = factory();
+ }
+})(typeof self !== 'undefined' ? self : this, function () {
+ 'use strict';
+
+ // 四舍五入(远离零),对齐 C# MidpointRounding.AwayFromZero
+ function roundHalfAwayFromZero(value, digits) {
+ var f = Math.pow(10, digits);
+ var n = Number(value) * f;
+ var sign = n < 0 ? -1 : 1;
+ var r = Math.round(Math.abs(n)) * sign;
+ var result = r / f;
+ return result === 0 ? 0 : result; // 消除 -0
+ }
+
+ // 价格缩放因子:债券(multiplier=100)界面为百分比态,计算用相对价需 ÷100
+ function getPriceScale(multiplier) {
+ return multiplier === 100 ? 0.01 : 1;
+ }
+
+ // 期末全价(界面态) = 期初全价(相对价) × multiplier
+ // 必须用 PosiGrossPrice(全价),非 PosiNetPrice(净价);债券 ×100 转界面百分比态
+ function deriveTradingAmountAvg(posiGrossPrice, multiplier) {
+ return posiGrossPrice * multiplier;
+ }
+
+ // 普通打开时以期初全价作为期末价默认值;审批打开时回显已提交的期末相对价。
+ function resolveIncomeTradingAmountAvg(posiGrossPrice, submittedTradingAmountAvg, multiplier, isUseApproval) {
+ var relativePrice = isUseApproval && submittedTradingAmountAvg !== undefined && submittedTradingAmountAvg !== null
+ ? submittedTradingAmountAvg
+ : posiGrossPrice;
+ return relativePrice * multiplier;
+ }
+
+ // 金额四舍五入到指定小数位(避免 0.1+0.2 类浮点误差)
+ function roundMoney(value, digits) {
+ return roundHalfAwayFromZero(value, digits);
+ }
+
+ // 浮动盈亏合计 = (平仓盈亏 + 交易费用 + 待结算费用 + 分红).toFixed(2)
+ function calcFloatPnlSum(markClosePnl, tradingFee, tradingFeePending, dividendIn) {
+ var sum = (+markClosePnl) + (+tradingFee) + (+tradingFeePending) + (+dividendIn);
+ return roundHalfAwayFromZero(sum, 2);
+ }
+
+ // 名义本金 = 期初全价 × 因子,保留 2 位(EQD-6090)
+ // factor 在前端 = 数量 × 乘数(national)
+ function calcStockEqvNotional(posiGrossPrice, factor) {
+ return roundHalfAwayFromZero(posiGrossPrice * factor, 2);
+ }
+
+ // 平仓名义本金 = 平仓比例 × 剩余持仓名义本金(PosiNotionalValue)
+ // 多次部分平仓后必须用剩余本金 PosiNotionalValue,不能用原始 NotionalValue,否则偏大
+ function calcCloseNotionalByRemaining(closePercent, posiNotionalValue) {
+ return roundHalfAwayFromZero(Number(closePercent) * Number(posiNotionalValue), 2);
+ }
+
+ // 平仓比例 = 平仓名义本金 / 剩余持仓名义本金(PosiNotionalValue)
+ // 多次部分平仓后必须以剩余本金为分母,否则比例偏小,导致后端预付金返还本金计算错误
+ function calcClosePercentByRemaining(closeNotionalValue, posiNotionalValue) {
+ if (Number(posiNotionalValue) === 0) return 0;
+ return roundHalfAwayFromZero(Number(closeNotionalValue) / Number(posiNotionalValue), 6);
+ }
+
+ // 平仓数量(占期初口径 A):CloseQty = PositionQty × (closePercent / oriClosePercent)
+ // closePercent 是"占期初名义本金比例"(A),需先除以 oriClosePercent(=剩余/期初) 转成"占剩余比例"(B),
+ // 再乘以剩余持仓数量 PositionQty。
+ // 多次部分平仓后必须这样转换,否则全部↔部分切换时 ClosePercent 没变但 CloseQty 会变(不自洽)。
+ // 除零保护:oriClosePercent=0(剩余为0,已全部平完)时返回 0。
+ function calcCloseQtyByOriginalPercent(closePercent, oriClosePercent, positionQty) {
+ var ori = Number(oriClosePercent);
+ if (ori === 0) return 0;
+ return roundHalfAwayFromZero(Number(positionQty) * (Number(closePercent) / ori), 2);
+ }
+
+ // 平仓比例(占期初口径 A)= (CloseQty / PositionQty) × oriClosePercent
+ // CloseQty/PositionQty 得到"占剩余比例"(B),乘以 oriClosePercent(=剩余/期初) 转成"占期初比例"(A)。
+ // 除零保护:PositionQty=0 时返回 0。
+ function calcOriginalClosePercentByQty(closeQty, positionQty, oriClosePercent) {
+ var qty = Number(positionQty);
+ if (qty === 0) return 0;
+ return roundHalfAwayFromZero((Number(closeQty) / qty) * Number(oriClosePercent), 6);
+ }
+
+ // 盯市平仓盈亏(unwind):CloseQty × (期末全价×scale − 期初全价) × floatRatio × longRatio
+ // 对齐 FrontendCalcReference.CalcUnwind:先 ×10000 取整再 ÷10000,最后 toFixed(2)
+ // 干净输入下等价于直接 round(.., 2)
+ function calcMarkClosePnl(closeQty, tradingAmountAvg, scale, entryPrice, floatRatio, longRatio) {
+ var product = closeQty * (tradingAmountAvg * scale - entryPrice) * floatRatio * longRatio;
+ var step = Math.round(product * 10000) / 10000; // 对齐 C# Math.Round(.. * 10000) / 10000
+ return roundHalfAwayFromZero(step, 2);
+ }
+
+ // ---- 组合函数:对齐 C# FrontendCalcReference.CalcUnwind / CalcIncome ----
+ // 用途:作为「前端 JS 完整盈亏聚合公式」与「后端 C# 金标准」的交叉校验
+ // (见 swapCalc.test.js 的 FC_001~FC_008 八个冻结场景)。
+ // 注意:以下 calcUnwind / calcIncome **未接入生产代码**——生产 Vue 组件只调用上方
+ // 4 个叶子函数。它们是冻结完整聚合逻辑的参考规格;若要让生产聚合逻辑也被自动守卫,
+ // 需把 incomeSwapTrade.js / swapTradeEdit.js / unwindSwapTrade.js 的聚合计算也改调它们。
+
+ function parseOrZero(s) {
+ return (s === undefined || s === null || s === '') ? 0 : Number(s);
+ }
+
+ function sumLegs(legs) {
+ return (legs || []).reduce(function (acc, l) { return acc + parseOrZero(l.interestClosePnL); }, 0);
+ }
+
+ // 平仓页(unwind)盈亏汇总 — 对齐 FrontendCalcReference.CalcUnwind
+ function calcUnwind(input) {
+ var entryPrice = input.posiGrossPrice;
+ var scale = input.multiplier === 100 ? 0.01 : 1;
+ var floatRatio = input.payDirection === 1 ? 1 : -1;
+ var longRatio = input.positionType === 1 ? 1 : -1;
+
+ var tradingFee = parseOrZero(input.tradingFee);
+ var tradingFeePending = parseOrZero(input.tradingFeePending);
+ var dividendIn = parseOrZero(input.dividendIn);
+
+ var markClosePnl = calcMarkClosePnl(
+ input.closeQty, input.tradingAmountAvg, scale, entryPrice, floatRatio, longRatio);
+ markClosePnl = roundHalfAwayFromZero(markClosePnl, 2);
+
+ var floatPnlSum = roundHalfAwayFromZero(markClosePnl + tradingFee + tradingFeePending + dividendIn, 2);
+
+ var swapRealizedPnL = floatPnlSum + sumLegs(input.interestLegs) + sumLegs(input.marginLegs);
+ var swapCloseAmount = floatPnlSum + sumLegs(input.interestLegs) + sumLegs(input.marginLegs);
+ var swapMarginRebatePnl = sumLegs(input.marginLegs);
+
+ var ratio = input.positionType === 1 ? 1 : -1;
+ var tradingAmountFeeAvg = input.closeQty === 0 ? 0
+ : input.tradingAmountAvg * scale + (tradingFee / input.closeQty) * ratio;
+
+ return {
+ MarkClosePnl: roundHalfAwayFromZero(markClosePnl, 2),
+ FloatPnlSum: floatPnlSum,
+ SwapRealizedPnL: roundHalfAwayFromZero(swapRealizedPnL, 2),
+ SwapCloseAmount: roundHalfAwayFromZero(swapCloseAmount, 2),
+ SwapMarginRebatePnl: roundHalfAwayFromZero(swapMarginRebatePnl, 2),
+ TradingAmountFeeAvg: tradingAmountFeeAvg
+ };
+ }
+
+ // 结息页(income)盈亏汇总 — 对齐 FrontendCalcReference.CalcIncome
+ function calcIncome(input) {
+ var entryPrice = input.posiGrossPrice;
+ var scale = input.multiplier === 100 ? 0.01 : 1;
+ var floatRatio = input.payDirection === 1 ? 1 : -1;
+
+ var tradingFee = parseOrZero(input.tradingFee);
+ var tradingFeePending = parseOrZero(input.tradingFeePending);
+ var dividendIn = parseOrZero(input.dividendIn);
+
+ var contractSize = input.contractSize === undefined || input.contractSize === null
+ ? 1 : Number(input.contractSize);
+ var markClosePnl = roundHalfAwayFromZero(
+ input.positionQty * contractSize * (input.tradingAmountAvg * scale - entryPrice) * floatRatio, 2);
+
+ var floatPnlSum = roundHalfAwayFromZero(markClosePnl + tradingFee + tradingFeePending + dividendIn, 2);
+
+ var swapRealizedPnL = floatPnlSum + sumLegs(input.interestLegs) + sumLegs(input.marginLegs);
+ var swapCloseAmount = floatPnlSum + sumLegs(input.interestLegs) + sumLegs(input.marginLegs);
+ var swapMarginRebatePnl = sumLegs(input.marginLegs);
+
+ var tradingAmountFeeAvg = input.closeQty > 0
+ ? input.tradingAmountAvg * scale + (tradingFee / input.closeQty) * floatRatio
+ : input.tradingAmountAvg * scale;
+
+ return {
+ MarkClosePnl: markClosePnl,
+ FloatPnlSum: floatPnlSum,
+ SwapRealizedPnL: roundHalfAwayFromZero(swapRealizedPnL, 2),
+ SwapCloseAmount: roundHalfAwayFromZero(swapCloseAmount, 2),
+ SwapMarginRebatePnl: roundHalfAwayFromZero(swapMarginRebatePnl, 2),
+ TradingAmountFeeAvg: tradingAmountFeeAvg
+ };
+ }
+
+ return {
+ roundHalfAwayFromZero: roundHalfAwayFromZero,
+ getPriceScale: getPriceScale,
+ deriveTradingAmountAvg: deriveTradingAmountAvg,
+ resolveIncomeTradingAmountAvg: resolveIncomeTradingAmountAvg,
+ roundMoney: roundMoney,
+ calcFloatPnlSum: calcFloatPnlSum,
+ calcStockEqvNotional: calcStockEqvNotional,
+ calcCloseNotionalByRemaining: calcCloseNotionalByRemaining,
+ calcClosePercentByRemaining: calcClosePercentByRemaining,
+ calcCloseQtyByOriginalPercent: calcCloseQtyByOriginalPercent,
+ calcOriginalClosePercentByQty: calcOriginalClosePercentByQty,
+ calcMarkClosePnl: calcMarkClosePnl,
+ calcUnwind: calcUnwind,
+ calcIncome: calcIncome
+ };
+});
diff --git a/YLErpWeb/wwwroot/Scripts/app/swaptrade/swapTradeEdit.js b/YLErpWeb/wwwroot/Scripts/app/swaptrade/swapTradeEdit.js
index 0b3f630b..dc726ce2 100644
--- a/YLErpWeb/wwwroot/Scripts/app/swaptrade/swapTradeEdit.js
+++ b/YLErpWeb/wwwroot/Scripts/app/swaptrade/swapTradeEdit.js
@@ -357,7 +357,8 @@ const vue = new Vue({
this.getSpotPrice(payItem.UnderlyingCode, this.trade.StartDate, payItem);
}
var national = payItem.PosiQuantity * payItem.ContractSize;
- var stockEqvNotional = _.round(payItem.PosiGrossPrice * national, 2);//名义本金=期初价格*数量*乘数
+ // 守卫: 名义本金必须 round 到 2 位 → 对应历史 bug f873239a(缺 _.round); 外置到 swapCalc.calcStockEqvNotional
+ var stockEqvNotional = SwapCalc.calcStockEqvNotional(payItem.PosiGrossPrice, national);//名义本金=期初价格*数量*乘数
this.trade.StockEqvNotional = otcformat.trading.stockEqvNotional(stockEqvNotional);
payItem.PosiNotionalValue = this.trade.StockEqvNotional;
}
diff --git a/YLErpWeb/wwwroot/Scripts/app/swaptrade/unwindSwapTrade.js b/YLErpWeb/wwwroot/Scripts/app/swaptrade/unwindSwapTrade.js
index b97414cf..c7fd23ff 100644
--- a/YLErpWeb/wwwroot/Scripts/app/swaptrade/unwindSwapTrade.js
+++ b/YLErpWeb/wwwroot/Scripts/app/swaptrade/unwindSwapTrade.js
@@ -17,7 +17,9 @@ const vue = new Vue({
marginList: [],
initPosiNetPrice: 0,
multiplier: 1,
- oriClosePercent: model.ClosePercent,
+ // 平仓比例展示/输入均为"占期初(original)"语义(A):默认与每次重开都基于原始名义本金。
+ // oriClosePercent = 剩余名义本金/期初名义本金 = 最多可平比例(不能平超过剩余持仓)。
+ oriClosePercent: 1,
ratio: 1,
shortRatio: 1,
},
@@ -53,6 +55,9 @@ const vue = new Vue({
this.ratio = this.floatPosition.PayDirection == 1 ? -1 : 1;
this.shortRatio = this.floatPosition.PositionType == 1 ? 1 : -1;
this.TradeStartDate = model.TradeStartDate;
+ // 最多可平比例(占期初口径) = 剩余名义本金 / 期初名义本金;分母为 0 时兜底为 1
+ this.oriClosePercent = (this.deal.NotionalValue && this.deal.PosiNotionalValue)
+ ? this.deal.PosiNotionalValue / this.deal.NotionalValue : 1;
// 转换期末标的价格为百分比形式
if (this.floatPosition.TradingAmountAvg) {
this.floatPosition.TradingAmountAvg = this.floatPosition.TradingAmountAvg * this.multiplier;
@@ -126,12 +131,20 @@ const vue = new Vue({
this.deal.CloseNotionalValue = otcformat.trading.StockEqvNotional(parseFloat(this.deal.PosiNotionalValue));
this.deal.CloseQty = this.deal.PositionQty;
} else {
- this.deal.CloseQty = otcformat.trading.notional(parseFloat(this.deal.PositionQty) * parseFloat(this.deal.ClosePercent));
+ // ClosePercent 是占期初口径(A),需除以 oriClosePercent 转占剩余(B) 再乘剩余数量
+ this.deal.CloseQty = this.calcCloseQtyByPercent(this.deal.ClosePercent);
}
this.calcTradingFeePending();
this.getInterestList();
this.calcFloatClosePnl();
},
+ // 按"占期初口径(A)"的 ClosePercent 反算平仓数量:CloseQty = PositionQty × (ClosePercent / oriClosePercent)
+ // 多次部分平仓后必须这样转换,否则全部↔部分切换时 ClosePercent 没变但 CloseQty 会变(不自洽)
+ // 使用 swapCalc.calcCloseQtyByOriginalPercent 的 roundHalfAwayFromZero 避免 JS 浮点精度偏差
+ // (如 32500000*(0.5/0.65)=24999999.999999996 而非 25000000)
+ calcCloseQtyByPercent(closePercent) {
+ return SwapCalc.calcCloseQtyByOriginalPercent(closePercent, this.oriClosePercent, this.deal.PositionQty);
+ },
calcTradingFeePending() {
this.floatPosition.TradingFeePending = this.floatPosition.BeforeCloseFee * parseFloat(this.deal.ClosePercent);
},
@@ -140,12 +153,15 @@ const vue = new Vue({
main.message("平仓数量不能超过持仓数量");
return;
}
- this.deal.ClosePercent = otcformat.fixed6(parseFloat(this.deal.CloseQty) / parseFloat(this.deal.PositionQty));
+ // CloseQty/PositionQty 得占剩余(B),× oriClosePercent 转回占期初(A)
+ var ori = parseFloat(this.oriClosePercent) || 0;
+ this.deal.ClosePercent = otcformat.fixed6((parseFloat(this.deal.CloseQty) / parseFloat(this.deal.PositionQty)) * ori);
if (parseFloat(this.deal.CloseQty) == parseFloat(this.deal.PositionQty)) {
this.deal.CloseMethod = 1;
} else {
this.deal.CloseMethod = 2;
}
+ // 占期初口径:平仓名义本金 = 平仓比例 × 期初名义本金(NotionalValue)
this.deal.CloseNotionalValue = otcformat.trading.StockEqvNotional(parseFloat(this.deal.ClosePercent) * parseFloat(this.deal.NotionalValue));
this.calcTradingFeePending();
this.getInterestList();
@@ -157,12 +173,13 @@ const vue = new Vue({
this.deal.ClosePercent = this.oriClosePercent;
return;
}
- this.deal.CloseQty = otcformat.trading.notional(parseFloat(this.deal.PositionQty) * parseFloat(this.deal.ClosePercent));
+ this.deal.CloseQty = this.calcCloseQtyByPercent(this.deal.ClosePercent);
+ // 占期初口径:平仓名义本金 = 平仓比例 × 期初名义本金(NotionalValue)
this.deal.CloseNotionalValue = otcformat.trading.StockEqvNotional(parseFloat(this.deal.ClosePercent) * parseFloat(this.deal.NotionalValue));
- if (parseFloat(this.deal.CloseNotionalValue) == parseFloat(this.deal.PosiNotionalValue)) {
- this.floatPosition.CloseMethod = 1;
+ if (parseFloat(this.deal.ClosePercent) == parseFloat(this.oriClosePercent)) {
+ this.deal.CloseMethod = 1;
} else {
- this.floatPosition.CloseMethod = 2;
+ this.deal.CloseMethod = 2;
}
this.calcTradingFeePending();
this.getInterestList();
@@ -174,8 +191,14 @@ const vue = new Vue({
this.deal.CloseNotionalValue = this.deal.PosiNotionalValue;
return;
}
+ // 占期初口径:平仓比例 = 平仓名义本金 / 期初名义本金(NotionalValue)
this.deal.ClosePercent = otcformat.fixed6(parseFloat(this.deal.CloseNotionalValue) / parseFloat(this.deal.NotionalValue));
- this.deal.CloseQty = otcformat.trading.notional(parseFloat(this.deal.PositionQty) * parseFloat(this.deal.ClosePercent));
+ this.deal.CloseQty = this.calcCloseQtyByPercent(this.deal.ClosePercent);
+ if (parseFloat(this.deal.ClosePercent) == parseFloat(this.oriClosePercent)) {
+ this.deal.CloseMethod = 1;
+ } else {
+ this.deal.CloseMethod = 2;
+ }
this.calcTradingFeePending();
this.getInterestList();
this.calcFloatClosePnl();
@@ -261,7 +284,8 @@ const vue = new Vue({
},
getInterestList() {//根据平仓日期获取利息腿信息
var thisObj = this;
- var postData = { valueDate: thisObj.deal.ValueDate, unwindDate: thisObj.deal.UnwindDate, tradeId: thisObj.deal.SwapTradeId, closePercent: thisObj.deal.ClosePercent, eventType: 2 }
+ // closePercent 按"占期初(original)"语义(A)传给后端,由 GetUnwindInterestList 转为"占剩余(B)"计算
+ var postData = { valueDate: thisObj.deal.ValueDate, unwindDate: thisObj.deal.UnwindDate, tradeId: thisObj.deal.SwapTradeId, closePercent: thisObj.deal.ClosePercent, eventType: 2, notionalValue: thisObj.deal.NotionalValue, posiNotionalValue: thisObj.deal.PosiNotionalValue }
main.post("/swaptrade2/GetUnwindInterestList", postData, { async: true }).done(function (resp) {
thisObj.interestList = resp.obj.filter((item) => {
return item.InterestMode == 1 || item.InterestMode == 2 || item.InterestMode == 7 || item.InterestMode == 8 || item.InterestMode == 9;
diff --git a/YLErpWeb/wwwroot/Scripts/app/system/Approvalprocess.js b/YLErpWeb/wwwroot/Scripts/app/system/Approvalprocess.js
index 3b34f24d..cff6d111 100644
--- a/YLErpWeb/wwwroot/Scripts/app/system/Approvalprocess.js
+++ b/YLErpWeb/wwwroot/Scripts/app/system/Approvalprocess.js
@@ -10,15 +10,17 @@ function initSelectize(selector, options) {
});
}
};
- if (options) {
- _.assign(options, defaultOptions);
- } else {
- options = defaultOptions;
- }
+ options = _.assign({}, defaultOptions, options || {});
$(selector).selectize(options);
}
function setRuleDiv() {
+ // 先销毁已有的 selectize 实例,避免在隐藏容器(v-show)里初始化后尺寸错位
+ $("[name='selectRule']").each(function () {
+ if (this.selectize) {
+ this.selectize.destroy();
+ }
+ });
initSelectize("[name='selectRule']", {
options: getRules(),
valueField: 'Value',
@@ -30,6 +32,8 @@ function setRuleDiv() {
function getRules() {
var items = [];
for (var i = 0; i < selectItems.length; i++) {
+ // 隐藏"投资规模"选项(仅保留"字段复核")
+ if (selectItems[i].Text === '投资规模') continue;
items.push({
Value: selectItems[i].Value,
Text: selectItems[i].Text
@@ -46,19 +50,22 @@ var app = new Vue({
{ text: '--请选择--', value: '0' },
{ text: '客户开户', value: '1' },
{ text: '客户信息修改', value: '5' },
- { text: '交易', value: '2' },
+ { text: '交易新增与修改', value: '2' },
+ { text: '交易了结', value: '6' },
/* { text: '资信与授信', value: '3' },*/
{ text: '出金', value: '4' }
-
+
],
isOpen: false,
isTrade: false,
+ isClose: false,
isCredit: false,
isOutCash: false,
isClient: false,
openItems: [],
clientItems: [],
tradeItems: [],
+ closeItems: [],
creditItems: [],
outCashItems: [],
openCounter: 0,
@@ -67,23 +74,32 @@ var app = new Vue({
clientCounter: 0,
tradeIndex: 0,
grouplist: [],
- node: 0
+ node: 0,
+ // 需求①:节点触发条件字段(期初名义本金 / 本次交易名义本金)
+ // 开仓流程只能选期初名义本金;了结流程两个都可选
+ conditionFields: [
+ { value: 'initialNotional', text: '期初名义本金' },
+ { value: 'currentNotional', text: '本次交易名义本金' }
+ ],
+ // 开仓流程可选字段(仅期初)
+ conditionFieldsOpen: [
+ { value: 'initialNotional', text: '期初名义本金' }
+ ],
+ conditionOps: [
+ { value: 'gt', text: '>' },
+ //{ value: 'lt', text: '<' },
+ { value: 'gte', text: '>=' },
+ //{ value: 'lte', text: '<=' },
+ //{ value: 'eq', text: '=' },
+ //{ value: 'neq', text: '≠' }
+ ],
+ conditionLogics: [
+ { value: 'AND', text: '满足全部条件时触发' },
+ { value: 'OR', text: '满足任一条件时触发' }
+ ],
+ roleOptions: []
},
computed: {
- roleOptions: function () {
- var items = [];
- main.post("/AccountOpeningProcess/GetRolesOption", {}, { async: false }).done(
- function (res) {
- for (var i = 0; i < res.length; i++) {
- items.push({
- Value: res[i].Value,
- Text: res[i].Text
- });
- }
- }
- );
- return items;
- },
filterBranch() {
return this.tradeItems.filter(x => x.approvalCondition != 0);
},
@@ -92,27 +108,56 @@ var app = new Vue({
},
clientFilterBranch() {
return this.clientItems.filter(x => x.approvalCondition != 0);
+ },
+ // 需求①:开仓流程只能选期初名义本金;了结流程两个都可选
+ availableConditionFields() {
+ return this.isClose ? this.conditionFields : this.conditionFieldsOpen;
}
},
methods: {
+ loadRoleOptions: function () {
+ var thisObj = this;
+ main.post("/AccountOpeningProcess/GetRolesOption", {}, { async: false }).done(
+ function (res) {
+ var items = [];
+ for (var i = 0; i < res.length; i++) {
+ items.push({
+ Value: res[i].Value,
+ Text: res[i].Text
+ });
+ }
+ thisObj.roleOptions = items;
+ }
+ );
+ },
changeType: function () {
var thisObj = this;
$("#addtooltip-warpper").hide();
if (thisObj.selected === '1') {
thisObj.isOpen = true;
thisObj.isTrade = false;
+ thisObj.isClose = false;
thisObj.isCredit = false;
thisObj.isOutCash = false;
thisObj.isClient = false;
} else if (thisObj.selected === '2') {
thisObj.isOpen = false;
thisObj.isTrade = true;
+ thisObj.isClose = false;
+ thisObj.isCredit = false;
+ thisObj.isOutCash = false;
+ thisObj.isClient = false;
+ } else if (thisObj.selected === '6') { // 需求②:交易了结流程
+ thisObj.isOpen = false;
+ thisObj.isTrade = false;
+ thisObj.isClose = true;
thisObj.isCredit = false;
thisObj.isOutCash = false;
thisObj.isClient = false;
} else if (thisObj.selected === '3') {
thisObj.isOpen = false;
thisObj.isTrade = false;
+ thisObj.isClose = false;
thisObj.isCredit = true;
thisObj.isOutCash = false;
thisObj.isClient = false;
@@ -120,6 +165,7 @@ var app = new Vue({
else if (thisObj.selected === '4') {
thisObj.isOpen = false;
thisObj.isTrade = false;
+ thisObj.isClose = false;
thisObj.isCredit = false;
thisObj.isOutCash = true;
thisObj.isClient = false;
@@ -127,6 +173,7 @@ var app = new Vue({
else if (thisObj.selected === '5') {
thisObj.isOpen = false;
thisObj.isTrade = false;
+ thisObj.isClose = false;
thisObj.isCredit = false;
thisObj.isOutCash = false;
thisObj.isClient = true;
@@ -134,6 +181,7 @@ var app = new Vue({
else {
thisObj.isOpen = false;
thisObj.isTrade = false;
+ thisObj.isClose = false;
thisObj.isCredit = false;
thisObj.isOutCash = false;
thisObj.isClient = false;
@@ -227,6 +275,9 @@ var app = new Vue({
if (selectType == "5") {
typeName = 'ClientProcess'
}
+ if (selectType == "6") {
+ typeName = 'CloseProcess'
+ }
var item = {
id: 0,
Type: typeName,
@@ -235,7 +286,10 @@ var app = new Vue({
approvalCondition: 1,
node: 1,
parentNode: thisObj.node,
- approvalGroupId: 0
+ approvalGroupId: 0,
+ conditionConfig: '',
+ triggerCondition: '',
+ _trigger: { tokens: [] }
}
var item2 = {
id: 0,
@@ -245,7 +299,10 @@ var app = new Vue({
approvalCondition: 1,
node: 2,
parentNode: thisObj.node,
- approvalGroupId: 0
+ approvalGroupId: 0,
+ conditionConfig: '',
+ triggerCondition: '',
+ _trigger: { tokens: [] }
}
if (selectType == "2") { //交易
thisObj.tradeItems.splice(thisObj.node, 0, item, item2);
@@ -258,7 +315,10 @@ var app = new Vue({
thisObj.clientItems.splice(thisObj.node, 0, item, item2);
thisObj.initClientItemIndex();
}
-
+ else if (selectType == "6") { //交易了结
+ thisObj.closeItems.splice(thisObj.node, 0, item, item2);
+ thisObj.initCloseItemIndex();
+ }
}
$("#addtooltip-warpper").hide(100);
@@ -321,6 +381,10 @@ var app = new Vue({
thisObj.addClientProcess(index, child, node);
return;
}
+ else if (selectType === "6") { //交易了结
+ thisObj.addCloseNode(index, child, node);
+ return;
+ }
},
delProcess: function (openItem) {
@@ -331,12 +395,9 @@ var app = new Vue({
return;
}
- if (selectType === "1") { //客户开户
- thisObj.delOpenProcess(openItem);
- return;
- }
- else if (selectType === "2") { //交易
- thisObj.delTradeProcess(openItem);
+ if (selectType === "1" || selectType === "2" || selectType === "5" || selectType === "6") {
+ // 客户开户/交易/客户信息/交易了结:统一走通用删除(支持多分支)
+ thisObj.commonDeleteProcess(openItem);
return;
}
@@ -356,89 +417,6 @@ var app = new Vue({
});
return;
}
- else if (selectType === "5") { //客户信息
- thisObj.delClientProcess(openItem);
- return;
- }
- },
- delOpenProcess(openItem) {
- var thisObj = this;
- if (openItem.approvalCondition != 0) {//删除分支下,所有东西
- var childNodes = thisObj.openItems.filter(x => x.node != 0);
- thisObj.openItems = thisObj.openItems.concat(childNodes).filter(function (v) {
- return thisObj.openItems.indexOf(v) === -1 || childNodes.indexOf(v) === -1
- });
- thisObj.initOpenItemIndex();
- } else if (openItem.node != 0) {//删除分支下某节点
- var index = thisObj.openItems.indexOf(openItem);
- thisObj.openItems.splice(index, 1);
- var childNodes = thisObj.openItems.filter(x => x.node == openItem.node && x.Index >= openItem.Index);
- childNodes.forEach(item => {
- item.parentNode = item.parentNode - 1;
- item.Index = item.Index - 1;
- });
- } else {//删除非分支下某节点
- var index = thisObj.openItems.indexOf(openItem);
- thisObj.openItems.splice(index, 1);
- var nodes = thisObj.openItems.filter(x => x.Index >= openItem.Index);
- nodes.forEach(item => {
- item.Index = item.Index - 1;
- });
- thisObj.initOpenItemIndex();
- }
- },
- delTradeProcess(tradeItem) {
- var thisObj = this;
- thisObj.getRuleType();
- if (tradeItem.approvalCondition != 0) {//删除分支下,所有东西
- var childNodes = thisObj.tradeItems.filter(x => x.node != 0);
- thisObj.tradeItems = thisObj.tradeItems.concat(childNodes).filter(function (v) {
- return thisObj.tradeItems.indexOf(v) === -1 || childNodes.indexOf(v) === -1
- });
- thisObj.initTradeItemIndex();
- } else if (tradeItem.node != 0) {//删除分支下某节点
- var index = thisObj.tradeItems.indexOf(tradeItem);
- thisObj.tradeItems.splice(index, 1);
- var childNodes = thisObj.tradeItems.filter(x => x.node == tradeItem.node && x.Index >= tradeItem.Index);
- childNodes.forEach(item => {
- item.parentNode = item.parentNode - 1;
- item.Index = item.Index - 1;
- });
- } else {//删除非分支下某节点
- var index = thisObj.tradeItems.indexOf(tradeItem);
- thisObj.tradeItems.splice(index, 1);
- var nodes = thisObj.tradeItems.filter(x => x.Index >= tradeItem.Index);
- nodes.forEach(item => {
- item.Index = item.Index - 1;
- });
- thisObj.initTradeItemIndex();
- }
- },
- delClientProcess(clientItem) {
- var thisObj = this;
- if (clientItem.approvalCondition != 0) {//删除分支下,所有东西
- var childNodes = thisObj.clientItems.filter(x => x.node != 0);
- thisObj.clientItems = thisObj.clientItems.concat(childNodes).filter(function (v) {
- return thisObj.clientItems.indexOf(v) === -1 || childNodes.indexOf(v) === -1
- });
- thisObj.initClientItemIndex();
- } else if (clientItem.node != 0) {//删除分支下某节点
- var index = thisObj.clientItems.indexOf(clientItem);
- thisObj.clientItems.splice(index, 1);
- var childNodes = thisObj.clientItems.filter(x => x.node == clientItem.node && x.Index >= clientItem.Index);
- childNodes.forEach(item => {
- item.parentNode = item.parentNode - 1;
- item.Index = item.Index - 1;
- });
- } else {//删除非分支下某节点
- var index = thisObj.clientItems.indexOf(clientItem);
- thisObj.clientItems.splice(index, 1);
- var nodes = thisObj.clientItems.filter(x => x.Index >= clientItem.Index);
- nodes.forEach(item => {
- item.Index = item.Index - 1;
- });
- thisObj.initClientItemIndex();
- }
},
addOpenProcess(index, child, node) {
var thisObj = this;
@@ -449,7 +427,10 @@ var app = new Vue({
approvalCondition: 0,
node: node,
parentNode: child ? index : 0,
- approvalGroupId: 0
+ approvalGroupId: 0,
+ conditionConfig: '',
+ triggerCondition: '',
+ _trigger: { tokens: [] }
}
var childNodes = thisObj.openItems.filter(x => x.Index > index);
childNodes.forEach(item => {
@@ -471,7 +452,10 @@ var app = new Vue({
approvalCondition: 0,
node: node,
parentNode: child ? index : 0,
- approvalGroupId: 0
+ approvalGroupId: 0,
+ conditionConfig: '',
+ triggerCondition: '',
+ _trigger: { tokens: [] }
}
thisObj.getRuleType();
var childNodes = thisObj.tradeItems.filter(x => x.Index > index);
@@ -494,7 +478,10 @@ var app = new Vue({
approvalCondition: 0,
node: node,
parentNode: child ? index : 0,
- approvalGroupId: 0
+ approvalGroupId: 0,
+ conditionConfig: '',
+ triggerCondition: '',
+ _trigger: { tokens: [] }
}
var childNodes = thisObj.clientItems.filter(x => x.Index > index);
childNodes.forEach(item => {
@@ -537,6 +524,10 @@ var app = new Vue({
thisObj.clientOk();
return;
}
+ else if (selectType === "6") { // 需求②:交易了结
+ thisObj.saveCloseProcess();
+ return;
+ }
},
openOk() {
var thisObj = this;
@@ -665,6 +656,12 @@ var app = new Vue({
thisObj.getRuleType();
thisObj.initTradeItemIndex();
+ var triggerValid = thisObj.validateAllTriggers(thisObj.tradeItems);
+ if (!triggerValid.valid) {
+ main.message(triggerValid.message);
+ return;
+ }
+ thisObj.stringifyAllTrigger(thisObj.tradeItems); // 需求①:序列化触发条件
var firstChildTradeItem = thisObj.tradeItems.filter(x => x.node == 1);
var secondchildTradeItem = thisObj.tradeItems.filter(x => x.node == 2);
if (firstChildTradeItem.length == 1 && secondchildTradeItem.length == 1) {
@@ -672,7 +669,7 @@ var app = new Vue({
return;
}
if (thisObj.tradeItems != null && thisObj.tradeItems.length > 0) {
- main.confirm("确认修改交易审批流程?", function () {
+ main.confirm("审批页面存在未审批完的交易,修改审批流程后这些交易需要重新审批,确认修改?", function () {
main.post("/AccountOpeningProcess/AddProcess",
{ type: thisObj.tradeItems[0].Type, data: thisObj.tradeItems },
{ async: false }).done(
@@ -864,6 +861,7 @@ var app = new Vue({
var thisObj = this;
thisObj.openItems = [];
thisObj.tradeItems = [];
+ thisObj.closeItems = [];
thisObj.creditItems = [];
thisObj.outCashItems = [];
thisObj.clientItems = [];
@@ -880,7 +878,9 @@ var app = new Vue({
node: value.node,
parentNode: value.parentNode,
approvalGroupId: value.approvalGroupId,
- approvalCondition: value.approvalCondition
+ approvalCondition: value.approvalCondition,
+ conditionConfig: value.conditionConfig,
+ triggerCondition: value.triggerCondition
});
});
@@ -894,9 +894,29 @@ var app = new Vue({
node: value.node,
parentNode: value.parentNode,
approvalGroupId: value.approvalGroupId,
- approvalCondition: value.approvalCondition
+ approvalCondition: value.approvalCondition,
+ conditionConfig: value.conditionConfig,
+ triggerCondition: value.triggerCondition
});
});
+ // 需求②:了结/平仓/行权审批流程
+ if (res.CloseProcess) {
+ res.CloseProcess.forEach(function (value, index, array) {
+ thisObj.closeItems.push({
+ id: value.id,
+ Type: value.processType,
+ Index: value.order,
+ SelectValue: value.roleId,
+ ApprovalRules: value.ruleType,
+ node: value.node,
+ parentNode: value.parentNode,
+ approvalGroupId: value.approvalGroupId,
+ approvalCondition: value.approvalCondition,
+ conditionConfig: value.conditionConfig,
+ triggerCondition: value.triggerCondition
+ });
+ });
+ }
res.CreditProcess.forEach(function (value, index, array) {
thisObj.creditItems.push({
Type: value.processType,
@@ -920,7 +940,15 @@ var app = new Vue({
node: value.node,
parentNode: value.parentNode,
approvalGroupId: value.approvalGroupId,
- approvalCondition: value.approvalCondition
+ approvalCondition: value.approvalCondition,
+ conditionConfig: value.conditionConfig,
+ triggerCondition: value.triggerCondition
+ });
+ });
+ // 需求①:加载后把 triggerCondition(JSON)解析为结构化对象供 UI 编辑
+ ['openItems', 'tradeItems', 'closeItems', 'clientItems'].forEach(function (arr) {
+ thisObj[arr].forEach(function (item) {
+ thisObj.parseTriggerCondition(item);
});
});
}
@@ -943,153 +971,492 @@ var app = new Vue({
clientFilterChild(node) {
return this.clientItems.filter(x => x.node == node && x.approvalCondition == 0);
},
- initTradeItemIndex() {
- var thisObj = this;
- var newSortTradeItems = [];
- var mainTradeItems = thisObj.tradeItems.filter(x => x.node == 0).sort((a, b) => a.Index - b.Index);
- var childTradeItem = thisObj.tradeItems.filter(x => x.node != 0);
- var childTradeItemSort = childTradeItem.sort((a, b) => a.Index - b.Index);
- var firstChildIndex = childTradeItemSort.length > 0 ? childTradeItemSort[0].Index : -1;
- var j = 1;
- for (var i = 0; i < mainTradeItems.length; i++) {
- if (mainTradeItems[i].Index >= firstChildIndex) {
- if (childTradeItemSort.length > 0) {
- mainTradeItems[i].Index = childTradeItemSort[childTradeItemSort.length - 1].Index + j;
+ // ===== 需求③:多分支支持(参考中粮版)通用方法 =====
+ // 通用分支重编号:动态把分支节点编号为 1,2,3...N(不再写死 1/2)
+ commonInitIndex(targetProp) {
+ const that = this;
+ const newSortedItems = [];
+ const mainItems = that[targetProp].filter(x => x.node == 0).sort((a, b) => a.Index - b.Index);
+ const childItems = that[targetProp].filter(x => x.node != 0);
+ const sortedChildItems = childItems.sort((a, b) => a.Index - b.Index);
+ const firstChildIndex = sortedChildItems.length > 0 ? sortedChildItems[0].Index : -1;
+ let j = 1;
+ for (let i = 0; i < mainItems.length; i++) {
+ if (mainItems[i].Index >= firstChildIndex) {
+ if (sortedChildItems.length > 0) {
+ mainItems[i].Index = sortedChildItems[sortedChildItems.length - 1].Index + j;
j++;
} else {
- mainTradeItems[i].Index = i + 1;
+ mainItems[i].Index = i + 1;
}
-
}
- newSortTradeItems.push(mainTradeItems[i]);
+ newSortedItems.push(mainItems[i]);
}
- var firstChildTradeItems = childTradeItem.filter(x => x.node == 1);
- var secondChildTradeItems = childTradeItem.filter(x => x.node == 2);
- firstChildTradeItems.forEach((x, index) => { //分支index不用再排序
- if (x.approvalCondition == 0) {
- x.Index = firstChildIndex + index;
- x.parentNode = firstChildIndex + index - 1;
+
+ // 为分支条件的 node 重新排序(1,2,3...N)——多分支的核心
+ let tempNode = 1;
+ childItems.forEach((i) => {
+ if (i.approvalCondition != 0) {
+ i.node = tempNode++;
}
- newSortTradeItems.push(x);
});
- secondChildTradeItems.forEach((x, index) => {
- if (x.approvalCondition == 0) {
- x.Index = firstChildIndex + index;
- x.parentNode = firstChildIndex + index - 1;
+
+ // 按分支 node 分组,重建每个分支下的子节点 Index/parentNode
+ for (let i = 0; i < childItems.length; i++) {
+ var filteredChildItems = childItems.filter(x => x.node == i + 1);
+ filteredChildItems.forEach((i, index) => {
+ if (i.approvalCondition == 0) {
+ i.Index = firstChildIndex + index;
+ i.parentNode = firstChildIndex + index - 1;
+ }
+ newSortedItems.push(i);
+ });
+ }
+ that[targetProp] = newSortedItems.sort((a, b) => a.Index - b.Index);
+ },
+ // 通用添加分支条件:push 一个 node:999 占位的分支节点,再重编号
+ commonAddCondition(item) {
+ const that = this;
+ const typeToPropMap = {
+ 'OpenProcess': 'openItems',
+ 'ClientProcess': 'clientItems',
+ 'TradeProcess': 'tradeItems',
+ 'CloseProcess': 'closeItems'
+ };
+ const typeToInitFnMap = {
+ 'OpenProcess': that.initOpenItemIndex,
+ 'ClientProcess': that.initClientItemIndex,
+ 'TradeProcess': that.initTradeItemIndex,
+ 'CloseProcess': that.initCloseItemIndex
+ };
+ const prop = typeToPropMap[item.Type];
+ const initFn = typeToInitFnMap[item.Type];
+ that[prop].push({
+ id: 0,
+ Type: item.Type,
+ Index: item.Index,
+ SelectValue: 0,
+ approvalCondition: 1,
+ node: 999,
+ parentNode: item.Index,
+ ApprovalRules: '',
+ approvalGroupId: 0,
+ conditionConfig: '',
+ triggerCondition: '',
+ _trigger: { tokens: [] }
+ });
+ initFn();
+ },
+ // 添加条件入口("添加条件"按钮调用)
+ addCondition(item) {
+ this.commonAddCondition(item);
+ },
+ // 通用删除分支/节点
+ commonDeleteProcess(item) {
+ const that = this;
+ const typeToPropMap = {
+ 'OpenProcess': 'openItems',
+ 'ClientProcess': 'clientItems',
+ 'TradeProcess': 'tradeItems',
+ 'CloseProcess': 'closeItems'
+ };
+ const typeToInitFnMap = {
+ 'OpenProcess': that.initOpenItemIndex,
+ 'ClientProcess': that.initClientItemIndex,
+ 'TradeProcess': that.initTradeItemIndex,
+ 'CloseProcess': that.initCloseItemIndex
+ };
+ const prop = typeToPropMap[item.Type];
+ const initFn = typeToInitFnMap[item.Type];
+
+ // 删除的不是分支条件节点(普通审批节点)
+ if (item.approvalCondition == 0) {
+ const index = that[prop].indexOf(item);
+ that[prop].splice(index, 1);
+ const nodes = that[prop].filter(x => x.Index >= item.Index);
+ nodes.forEach(item => {
+ item.Index = item.Index - 1;
+ });
+ initFn();
+ return;
+ }
+
+ // 分支条件数量<=2 时,删除整个分支组
+ var conditionBranchesLen = that[prop].filter(i => i.approvalCondition != 0 && i.node != 0).length;
+ if (item.approvalCondition != 0 && conditionBranchesLen <= 2) {
+ var childNodes = that[prop].filter(x => x.node != 0);
+ that[prop] = that[prop].filter(x => childNodes.indexOf(x) === -1);
+ initFn();
+ return;
+ }
+
+ // 分支条件数量>2 时,只删除该分支(同 node 的全部节点)
+ if (item.node != 0 && item.approvalCondition != 0) {
+ that[prop] = that[prop].filter(x => x.node != item.node);
+ initFn();
+ }
+ },
+ initTradeItemIndex() {
+ this.commonInitIndex('tradeItems');
+ this.initRuleType();
+ },
+ // ===== 需求①:节点触发条件 结构化编辑器(token 数组,支持每行独立且/或 + 括号)=====
+ // _trigger = { tokens: [ {type:'condition',condition:{field,op,value}}, {type:'operator',connector:'and'|'or'}, {type:'lparen'|'rparen'} ] }
+ // op 用字母标识符(gt/lt/gte/lte/eq/neq),规避 > < 在传输中被 HTML 编码导致加载不出来的问题
+ // 把历史符号 op 归一化为字母标识符
+ normalizeOp(op) {
+ var map = { '>': 'gt', '<': 'lt', '>=': 'gte', '<=': 'lte', '==': 'eq', '!=': 'neq', '=': 'eq', '<>': 'neq' };
+ if (!op) return 'gt';
+ var lower = ('' + op).toLowerCase();
+ if (['gt','lt','gte','lte','eq','neq'].indexOf(lower) >= 0) return lower;
+ return map[op] || lower;
+ },
+ // 字段归一化:历史 notional → initialNotional;空默认 initialNotional
+ normalizeField(field) {
+ if (!field) return 'initialNotional';
+ var f = ('' + field);
+ // 历史兼容
+ if (f.toLowerCase() == 'notional') return 'initialNotional';
+ return f;
+ },
+ // 把 item.triggerCondition(JSON 字符串)解析为 item._trigger 结构化对象供 UI 编辑
+ parseTriggerCondition(item) {
+ if (!item) return;
+ if (item._trigger) return; // 已解析则不重复处理
+ var thisObj = this;
+ var parsed = { tokens: [] };
+ if (item.triggerCondition) {
+ try {
+ var obj = JSON.parse(item.triggerCondition);
+ if (obj.tokens && obj.tokens.length) {
+ // 新结构:直接复用 token,规范化字段
+ parsed.tokens = obj.tokens.map(function (t) {
+ if (t.type == 'condition') {
+ var c = t.condition || {};
+ return { type: 'condition', condition: { field: thisObj.normalizeField(c.field), op: thisObj.normalizeOp(c.op), value: c.value != null ? c.value : '' } };
+ }
+ if (t.type == 'operator') return { type: 'operator', connector: (t.connector || 'and').toLowerCase() };
+ if (t.type == 'lparen') return { type: 'lparen' };
+ if (t.type == 'rparen') return { type: 'rparen' };
+ return null;
+ }).filter(function (t) { return t != null; });
+ }
+ } catch (e) {
+ // 非法 JSON,按空处理
}
- newSortTradeItems.push(x);
+ }
+ this.$set(item, '_trigger', parsed);
+ },
+ // 新增一条触发条件(自动在前方补连接符,首个不补)
+ addTriggerCondition(item) {
+ this.parseTriggerCondition(item);
+ var toks = item._trigger.tokens;
+ if (toks.length > 0) {
+ var last = toks[toks.length - 1];
+ // 若上一 token 是条件或右括号,则需要连接符
+ if (last.type == 'condition' || last.type == 'rparen') {
+ toks.push({ type: 'operator', connector: 'and' });
+ }
+ }
+ toks.push({ type: 'condition', condition: { field: 'initialNotional', op: 'gt', value: '' } });
+ },
+ // 切换某连接符 and/or
+ toggleTriggerConnector(item, idx) {
+ var t = item._trigger.tokens[idx];
+ if (t && t.type == 'operator') {
+ t.connector = (t.connector == 'and') ? 'or' : 'and';
+ }
+ },
+ // 插入左/右括号
+ addTriggerParen(item, side) {
+ this.parseTriggerCondition(item);
+ var toks = item._trigger.tokens;
+ var type = side == 'left' ? 'lparen' : 'rparen';
+ if (type == 'lparen') {
+ // 左括号前若接条件/右括号,需补连接符
+ if (toks.length > 0) {
+ var last = toks[toks.length - 1];
+ if (last.type == 'condition' || last.type == 'rparen') {
+ toks.push({ type: 'operator', connector: 'and' });
+ }
+ }
+ toks.push({ type: 'lparen' });
+ } else {
+ toks.push({ type: 'rparen' });
+ }
+ },
+ // 删除一个 token,并清理其旁孤立连接符
+ removeTriggerToken(item, idx) {
+ var toks = item._trigger.tokens;
+ if (idx < 0 || idx >= toks.length) return;
+ toks.splice(idx, 1);
+ // 清理首部连接符 / 尾部连接符 / 连续连接符
+ var i = 0;
+ while (i < toks.length) {
+ var t = toks[i];
+ if (t.type == 'operator' && (i == 0 || i == toks.length - 1
+ || toks[i - 1].type == 'operator')) {
+ toks.splice(i, 1);
+ } else {
+ i++;
+ }
+ }
+ },
+ // 保存前:把 item._trigger 序列化回 item.triggerCondition JSON
+ stringifyTriggerCondition(item) {
+ if (!item || !item._trigger) return;
+ var toks = item._trigger.tokens || [];
+ if (toks.length == 0) {
+ item.triggerCondition = '';
+ return;
+ }
+ // 过滤掉无效条件(字段/值缺失)
+ var valid = toks.filter(function (t) {
+ if (t.type == 'condition') {
+ var c = t.condition || {};
+ return c.field && c.op && c.value !== '';
+ }
+ return true;
});
- thisObj.tradeItems = newSortTradeItems.sort((a, b) => a.Index - b.Index);
- thisObj.initRuleType();
+ // 移除首尾连接符
+ while (valid.length > 0 && valid[0].type == 'operator') valid.shift();
+ while (valid.length > 0 && valid[valid.length - 1].type == 'operator') valid.pop();
+ item.triggerCondition = valid.length > 0 ? JSON.stringify({ tokens: valid }) : '';
+ },
+ // 批量把一组 items 的 _trigger 序列化(保存前调用)
+ stringifyAllTrigger(items) {
+ var thisObj = this;
+ if (!items) return;
+ items.forEach(function (item) {
+ if (item.node == 0 || item.approvalCondition == 0) {
+ thisObj.stringifyTriggerCondition(item);
+ }
+ });
+ },
+ // 校验触发条件 token 列表是否合法:括号平衡、无空括号、无首尾连接符等
+ validateTriggerTokens(tokens) {
+ if (!tokens || tokens.length == 0) return { valid: true, message: '' };
+ var paren = 0;
+ for (var i = 0; i < tokens.length; i++) {
+ var t = tokens[i];
+ if (t.type == 'lparen') paren++;
+ if (t.type == 'rparen') paren--;
+ if (paren < 0) return { valid: false, message: '触发条件中右括号过多,请检查括号匹配' };
+ if (t.type == 'operator') {
+ if (i == 0 || i == tokens.length - 1) return { valid: false, message: '触发条件首尾不能为连接符(且/或)' };
+ var prev = tokens[i - 1];
+ if (prev.type == 'operator' || prev.type == 'lparen') return { valid: false, message: '触发条件中连接符(且/或)位置不正确' };
+ }
+ if (t.type == 'condition') {
+ var c = t.condition || {};
+ if (!c.field || !c.op || c.value === '') return { valid: false, message: '触发条件中存在未填写完整的条件' };
+ }
+ }
+ if (paren != 0) return { valid: false, message: '触发条件中括号不匹配,请检查' };
+ return { valid: true, message: '' };
+ },
+ // 校验一组 items 的触发条件,返回第一个错误信息
+ validateAllTriggers(items) {
+ var thisObj = this;
+ if (!items) return { valid: true, message: '' };
+ for (var i = 0; i < items.length; i++) {
+ var item = items[i];
+ if ((item.node == 0 || item.approvalCondition == 0) && item._trigger && item._trigger.tokens) {
+ var res = thisObj.validateTriggerTokens(item._trigger.tokens);
+ if (!res.valid) return res;
+ }
+ }
+ return { valid: true, message: '' };
+ },
+ // ===== 需求②:交易了结流程(closeItems)方法集,算法同交易流程 =====
+ closeFilterBranch() {
+ return this.closeItems.filter(x => x.approvalCondition != 0);
+ },
+ closeFilterChild(node) {
+ return this.closeItems.filter(x => x.node == node && x.approvalCondition == 0);
+ },
+ initCloseItemIndex() {
+ this.commonInitIndex('closeItems');
+ this.initRuleType();
+ },
+ closeShowProcess(index, child, obj) {
+ var thisObj = this;
+ var closeBranch = thisObj.closeItems.find(x => x.approvalCondition != 0);
+ if (!closeBranch) {
+ let offsetTop = $(obj.target).offset().top;
+ let offsetLeft = $(obj.target).offset().left;
+ $("#addtooltip-warpper").css({ "left": offsetLeft - 180, "top": offsetTop - 110, "margin-left": "30px" });
+ $("#addtooltip-warpper").hide();
+ $("#addtooltip-warpper").show(150);
+ this.tradeIndex = index;
+ thisObj.node = index;
+ } else {
+ thisObj.closeAddProcess(index, child, 0);
+ $("#addtooltip-warpper").hide(100);
+ }
+ },
+ closeAddProcess(index, child, node) {
+ var thisObj = this;
+ thisObj.addCloseNode(index, child, node);
+ $("#addtooltip-warpper").hide(100);
+ },
+ addCloseNode(index, child, node) {
+ var thisObj = this;
+ var item = {
+ id: 0,
+ Type: 'CloseProcess',
+ Index: index + 1,
+ SelectValue: 0,
+ ApprovalRules: '',
+ node: node,
+ parentNode: child ? index : 0,
+ approvalGroupId: 0,
+ approvalCondition: 0,
+ conditionConfig: '',
+ triggerCondition: '',
+ _trigger: { tokens: [] }
+ };
+ thisObj.closeItems.forEach(x => {
+ if (x.Index >= index) {
+ x.Index = x.Index + 1;
+ }
+ });
+ thisObj.closeItems.splice(index, 0, item);
+ thisObj.initCloseItemIndex();
+ },
+ closeSelectChangeType(index, value) {
+ var thisObj = this;
+ for (var j = 0; j < thisObj.closeItems.length; j++) {
+ if (j === index) continue;
+ if (thisObj.closeItems[j].SelectValue === parseInt(value) && thisObj.closeItems[j].node == 0) {
+ main.message("不得选择重复角色");
+ return;
+ }
+ }
+ },
+ saveCloseProcess() {
+ var thisObj = this;
+ // 角色非空校验
+ for (var i = 0; i < thisObj.closeItems.length; i++) {
+ if (thisObj.closeItems[i].SelectValue === "" || thisObj.closeItems[i].SelectValue === 0) {
+ if (thisObj.closeItems[i].approvalCondition == 0) {
+ main.message('流程中断,请重新选择');
+ return;
+ }
+ }
+ }
+
+ var temp1 = 0;
+ var closeLength = thisObj.closeItems.length;
+ for (var w1 = 0; w1 < closeLength - 1; w1++) {
+ for (var n1 = 1; n1 < closeLength; n1++) {
+ if (w1 !== n1) {
+ if (parseInt(thisObj.closeItems[w1].SelectValue) === parseInt(thisObj.closeItems[n1].SelectValue) && parseInt(thisObj.closeItems[n1].SelectValue) != 0) {
+ if (parseInt(thisObj.closeItems[w1].node) == parseInt(thisObj.closeItems[n1].node)) {
+ temp1 = temp1 + 1;
+ }
+ }
+ }
+ }
+ }
+ var approvalGroupItems = thisObj.closeItems.filter(x => x.approvalGroupId != 0);
+ var approvalCloseLength = approvalGroupItems.length;
+ var temp2 = 0;
+ for (var w1 = 0; w1 < approvalCloseLength - 1; w1++) {
+ for (var n1 = 1; n1 < approvalCloseLength; n1++) {
+ if (w1 !== n1) {
+ if (parseInt(approvalGroupItems[w1].approvalCondition) === parseInt(approvalGroupItems[n1].approvalCondition) && parseInt(approvalGroupItems[w1].approvalGroupId) === parseInt(approvalGroupItems[n1].approvalGroupId)) {
+ temp2 = temp2 + 1;
+ }
+ }
+ }
+ }
+ if (temp1 > 0 || temp2 > 0) {
+ main.message('流程包含重复项,请重新选择');
+ return;
+ }
+
+ thisObj.getCloseRuleType();
+ thisObj.initCloseItemIndex();
+ var firstChildCloseItem = thisObj.closeItems.filter(x => x.node == 1);
+ var secondchildCloseItem = thisObj.closeItems.filter(x => x.node == 2);
+ if (firstChildCloseItem.length == 1 && secondchildCloseItem.length == 1) {
+ main.message('分支节点流程未设置完毕');
+ return;
+ }
+ var triggerValid = thisObj.validateAllTriggers(thisObj.closeItems);
+ if (!triggerValid.valid) {
+ main.message(triggerValid.message);
+ return;
+ }
+ thisObj.stringifyAllTrigger(thisObj.closeItems); // 需求①:序列化触发条件
+ if (thisObj.closeItems != null && thisObj.closeItems.length > 0) {
+ main.confirm("审批页面存在未审批完的交易,修改审批流程后这些交易需要重新审批,确认修改?", function () {
+ main.post("/AccountOpeningProcess/AddProcess",
+ { type: "CloseProcess", data: thisObj.closeItems },
+ { async: false }).done(
+ function (res) {
+ thisObj.getProcess();
+ });
+ });
+ } else {
+ main.confirm("删除审批流程后,交易了结审批就会直接审批通过,确认删除?", function () {
+ main.post("/AccountOpeningProcess/AddProcess",
+ { type: "CloseProcess" },
+ { async: false }).done(
+ function (res) {
+ });
+ });
+ }
},
initOpenItemIndex() {
- var thisObj = this;
- var newSortOpenItems = [];
- var mainOpenItems = thisObj.openItems.filter(x => x.node == 0).sort((a, b) => a.Index - b.Index);
- var childOpenItem = thisObj.openItems.filter(x => x.node != 0);
- var childOpenItemSort = childOpenItem.sort((a, b) => a.Index - b.Index);
- var firstChildIndex = childOpenItemSort.length > 0 ? childOpenItemSort[0].Index : -1;
- var j = 1;
- for (var i = 0; i < mainOpenItems.length; i++) {
- if (mainOpenItems[i].Index >= firstChildIndex) {
- if (childOpenItemSort.length > 0) {
- mainOpenItems[i].Index = childOpenItemSort[childOpenItemSort.length - 1].Index + j;
- j++;
- } else {
- mainOpenItems[i].Index = i + 1;
- }
-
- }
- newSortOpenItems.push(mainOpenItems[i]);
- }
- var firstChildOpenItems = childOpenItem.filter(x => x.node == 1);
- var secondChildOpenItems = childOpenItem.filter(x => x.node == 2);
- firstChildOpenItems.forEach((x, index) => { //分支index不用再排序
- if (x.approvalCondition == 0) {
- x.Index = firstChildIndex + index;
- x.parentNode = firstChildIndex + index - 1;
- }
- newSortOpenItems.push(x);
- });
- secondChildOpenItems.forEach((x, index) => {
- if (x.approvalCondition == 0) {
- x.Index = firstChildIndex + index;
- x.parentNode = firstChildIndex + index - 1;
- }
- newSortOpenItems.push(x);
- });
- thisObj.openItems = newSortOpenItems.sort((a, b) => a.Index - b.Index);
+ this.commonInitIndex('openItems');
},
initClientItemIndex() {
+ this.commonInitIndex('clientItems');
+ },
+ initRuleTypeFor(items, prefix) {
var thisObj = this;
- var newSortClientItems = [];
- var mainClientItems = thisObj.clientItems.filter(x => x.node == 0).sort((a, b) => a.Index - b.Index);
- var childClientItem = thisObj.clientItems.filter(x => x.node != 0);
- var childClientItemSort = childClientItem.sort((a, b) => a.Index - b.Index);
- var firstChildIndex = childClientItemSort.length > 0 ? childClientItemSort[0].Index : -1;
- var j = 1;
- for (var i = 0; i < mainClientItems.length; i++) {
- if (mainClientItems[i].Index >= firstChildIndex) {
- if (childClientItemSort.length > 0) {
- mainClientItems[i].Index = childClientItemSort[childClientItemSort.length - 1].Index + j;
- j++;
- } else {
- mainClientItems[i].Index = i + 1;
- }
-
+ var length = items.length;
+ for (var i = 0; i < length; i++) {
+ var ruleId = "#" + prefix + items[i].Index + items[i].node;
+ var el = $(ruleId).get(0);
+ if (!el || !el.selectize) continue; // DOM 尚未渲染或未初始化 selectize,跳过
+ if (items[i].ApprovalRules != null && items[i].ApprovalRules.length > 0) {
+ var ruleArr = items[i].ApprovalRules.split(',');
+ el.selectize.setValue(ruleArr);
+ } else {
+ el.selectize.setValue([]);
}
- newSortClientItems.push(mainClientItems[i]);
}
- var firstChildClientItems = childClientItem.filter(x => x.node == 1);
- var secondChildClientItems = childClientItem.filter(x => x.node == 2);
- firstChildClientItems.forEach((x, index) => { //分支index不用再排序
- if (x.approvalCondition == 0) {
- x.Index = firstChildIndex + index;
- x.parentNode = firstChildIndex + index - 1;
- }
- newSortClientItems.push(x);
- });
- secondChildClientItems.forEach((x, index) => {
- if (x.approvalCondition == 0) {
- x.Index = firstChildIndex + index;
- x.parentNode = firstChildIndex + index - 1;
- }
- newSortClientItems.push(x);
- });
- thisObj.clientItems = newSortClientItems.sort((a, b) => a.Index - b.Index);
},
initRuleType() {
- var thisObj = this;
- var tradeLength = thisObj.tradeItems.length;
- for (var i = 0; i < tradeLength; i++) {
- var ruleId = "#ruleType" + thisObj.tradeItems[i].Index + thisObj.tradeItems[i].node;
- var $selectize = $(ruleId).get(0);
- if (thisObj.tradeItems[i].ApprovalRules != null && thisObj.tradeItems[i].ApprovalRules.length > 0) {
- var ruleArr = thisObj.tradeItems[i].ApprovalRules.split(',');
- $selectize.selectize.setValue(ruleArr);
- } else if ($selectize) {
- $selectize.selectize.setValue([]);
- }
-
- }
+ this.initRuleTypeFor(this.tradeItems, 'ruleType');
+ this.initRuleTypeFor(this.closeItems, 'closeRuleType');
},
- getRuleType() {
+ getRuleTypeFor(items, prefix) {
var thisObj = this;
- var tradeLength = thisObj.tradeItems.length;
- for (var i = 0; i < tradeLength; i++) {
- var ruleId = "#ruleType" + thisObj.tradeItems[i].Index + thisObj.tradeItems[i].node;
+ var length = items.length;
+ for (var i = 0; i < length; i++) {
+ var ruleId = "#" + prefix + items[i].Index + items[i].node;
var $selectize = $(ruleId).get(0);
if ($selectize) {
var ruleArr = $selectize.selectize.items;
- thisObj.tradeItems[i].ApprovalRules = ruleArr.join(',');
+ items[i].ApprovalRules = ruleArr.join(',');
}
-
}
+ },
+ getRuleType() {
+ this.getRuleTypeFor(this.tradeItems, 'ruleType');
+ },
+ getCloseRuleType() {
+ this.getRuleTypeFor(this.closeItems, 'closeRuleType');
}
},
mounted: function () {
this.getProcess();
this.getApprovalGroup();
+ this.loadRoleOptions();
},
watch: {
tradeItems:
@@ -1097,6 +1464,16 @@ var app = new Vue({
handler(val, oldVal) {
this.$nextTick(function () {
setRuleDiv();
+ this.initRuleType();
+ })
+ },
+ },
+ closeItems:
+ {
+ handler(val, oldVal) {
+ this.$nextTick(function () {
+ setRuleDiv();
+ this.initRuleType();
})
},
}
diff --git a/YLErpWeb/wwwroot/Scripts/fast/fastVue.base.js b/YLErpWeb/wwwroot/Scripts/fast/fastVue.base.js
index c3d1802c..f57f9c4a 100644
--- a/YLErpWeb/wwwroot/Scripts/fast/fastVue.base.js
+++ b/YLErpWeb/wwwroot/Scripts/fast/fastVue.base.js
@@ -432,7 +432,15 @@
function __onInput() {
if (_ctrlV) {
_ctrlV = false;
- return setValue(this.value);
+ // 粘贴进来的是显示值(可能带 %/‱ 后缀),先按 __change 同款口径解析为模型值再回显,
+ // 避免 setValue 把显示值再乘以 100/10000(#EQD-5914 债券价格粘贴 ×100)
+ let f = '';
+ if (this.value && this.value !== _options.append) {
+ f = parseFloat(this.value.replaceAll(",", "")) || 0;
+ if (_options.append === '%' || _options.percent == true) f /= 100;
+ else if (_options.append === '‱') f /= 10000;
+ }
+ return setValue(f);
}
if (_chnInput >= 0) {
__onChineseInput.call(this, _chnInput);
diff --git a/YLErpWeb/wwwroot/Scripts/utils.js b/YLErpWeb/wwwroot/Scripts/utils.js
index 3a1e661b..a615eda2 100644
--- a/YLErpWeb/wwwroot/Scripts/utils.js
+++ b/YLErpWeb/wwwroot/Scripts/utils.js
@@ -1091,4 +1091,216 @@ main.checkEmail = function (email) {
const regex = /^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$/;
return regex.test(email);
}
-
\ No newline at end of file
+
+/**
+ * 可折叠分组表头工具(适用于 jqGrid 4.5.4,不依赖 free-jqGrid / Guriddo 商业版)
+ *
+ * 背景:jqGrid 4.5.4 的 setGroupHeaders 只能生成静态合并表头,不支持点击折叠。
+ * 本方法在 setGroupHeaders 基础上补齐"点击分组表头折叠/展开"交互,
+ * 并复用本文件 setcolumnChooser2 已验证的 destroyGroupHeader → 显隐列 → setGroupHeaders 重建模式。
+ *
+ * 用法:
+ * main.initCollapsibleGroupHeaders($('#listGrid'), [
+ * { title: '基本信息', columns: ['交易日', '簿记账户'] },
+ * { title: '名义本金', columns: ['合约名义本金', '多头', '空头'] }
+ * ]);
+ *
+ * @param {jQuery} jgrid jqGrid 容器(如 $('#listGrid'))
+ * @param {Array} groupConfig 分组配置,每项 { title: string, columns: string[] }
+ * - title 分组表头显示名
+ * - columns 该组包含的列(使用 colModel.name)
+ * 注意:columns 里若包含已被 setcolumnChooser 隐藏的列,会被自动跳过,不影响重建。
+ */
+main.initCollapsibleGroupHeaders = function (jgrid, groupConfig) {
+ if (!groupConfig || !groupConfig.length) return;
+
+ // 存储各分组的折叠状态,key=title,value=true 表示已折叠
+ var collapseState = {};
+
+ // 根据 groupConfig + 当前 colModel 可见性,构造 setGroupHeaders 所需的 groupHeaders 参数。
+ // 关键:折叠的分组仍需保留一个表头单元格作为"展开锚点",否则用户无法再次展开。
+ function buildGroupHeaders() {
+ var colModel = jgrid.jqGrid('getGridParam', 'colModel');
+ var visibleNames = colModel.filter(function (c) { return !c.hidden; }).map(function (c) { return c.name; });
+ var groupHeaders = [];
+ for (var g = 0; g < groupConfig.length; g++) {
+ var group = groupConfig[g];
+ var visibleColsInGroup = group.columns.filter(function (n) { return visibleNames.indexOf(n) > -1; });
+ //整组都不可见:若是被折叠的分组,仍需保留锚点(下方 applyGroupHeaders 已保留首列);
+ //若是被 setcolumnChooser 主动隐藏的分组,则跳过不渲染表头
+ if (!visibleColsInGroup.length && !collapseState[group.title]) continue;
+ //锚点列:折叠态下 numberOfColumns=1(首列被保留);展开态为该组可见列数
+ var count = visibleColsInGroup.length || 1;
+ var icon = collapseState[group.title] ? '▶' : '▼';
+ var titleClass = collapseState[group.title] ? 'group-header-title group-collapsed' : 'group-header-title';
+ groupHeaders.push({
+ startColumnName: group.columns[0], //锚点列始终是首列(折叠时首列被保留)
+ numberOfColumns: count,
+ titleText: '
' + icon + ' ' + group.title + ''
+ });
+ }
+ return groupHeaders;
+ }
+
+ // 应用一次分组表头(含折叠态显隐),复用 destroyGroupHeader → setGroupHeaders 模式
+ function applyGroupHeaders() {
+ jgrid.jqGrid('destroyGroupHeader', true); // true: 不恢复为单行表头
+ // 按折叠状态显隐列:折叠的分组保留首列作为锚点(避免整组表头消失无法展开)
+ for (var g = 0; g < groupConfig.length; g++) {
+ var group = groupConfig[g];
+ if (collapseState[group.title]) {
+ //折叠:隐藏除首列外的所有列,保留首列作为锚点
+ if (group.columns.length > 1) {
+ jgrid.setGridParam().hideCol(group.columns.slice(1));
+ }
+ jgrid.setGridParam().showCol([group.columns[0]]);
+ } else {
+ //展开:恢复该组所有列
+ jgrid.setGridParam().showCol(group.columns);
+ }
+ }
+ var groupHeaders = buildGroupHeaders();
+ if (groupHeaders.length) {
+ jgrid.jqGrid('setGroupHeaders', { useColSpanStyle: true, groupHeaders: groupHeaders });
+ }
+ //保存到 jqGrid 参数,便于与 setcolumnChooser 协调
+ jgrid.jqGrid('setGridParam', { collapsibleGroupConfig: groupConfig, collapseState: collapseState });
+ bindHeaderClick();
+ }
+
+ // 给分组表头单元格绑定 click(事件委托,重建表头后仍生效)
+ function bindHeaderClick() {
+ var hbox = jgrid.closest('.ui-jqgrid').find('.ui-jqgrid-hdiv');
+ hbox.off('click.collapsibleGroup').on('click.collapsibleGroup', '.group-header-title', function (e) {
+ e.stopPropagation();
+ var idx = $(this).attr('data-group');
+ var group = groupConfig[idx];
+ if (!group) return;
+ collapseState[group.title] = !collapseState[group.title];
+ applyGroupHeaders();
+ });
+ }
+
+ applyGroupHeaders();
+};
+
+/**
+ * 重建已初始化的可折叠分组表头。
+ * 供 setcolumnChooser / 列重排后调用,确保分组边界与最新的列顺序/可见性同步。
+ * @param {jQuery} jgrid
+ */
+main.refreshCollapsibleGroupHeaders = function (jgrid) {
+ var cfg = jgrid.jqGrid('getGridParam', 'collapsibleGroupConfig');
+ if (!cfg) return;
+ // 复用已有的 collapseState
+ var state = jgrid.jqGrid('getGridParam', 'collapseState') || {};
+ // 重新初始化(groupConfig 同引用,collapseState 重建以剔除已失效的分组)
+ main.initCollapsibleGroupHeaders(jgrid, cfg);
+ // 回填状态
+ var freshState = jgrid.jqGrid('getGridParam', 'collapseState') || {};
+ Object.keys(state).forEach(function (k) { if (k in freshState) freshState[k] = state[k]; });
+};
+
+/**
+ * 导出 jqGrid 可见列为 Excel(零依赖,基于 HTML table + ms-excel MIME)。
+ *
+ * 设计目标:导出内容与前端表格"当前可见列"完全一致(需求《估值模块V1》4.2)。
+ * 不依赖第三方库,不调用后端导出接口,避免与 C# 模板导出口径混淆。
+ *
+ * @param {jQuery} jgrid jqGrid 容器
+ * @param {string} fileName 导出文件名(不含扩展名)
+ * @param {Array} groupConfig 可选,分组表头配置,每项 { title: string, columns: string[] }
+ * @param {Array} exportRows 可选,后端返回的全部筛选结果;未传时导出当前页
+ * @param {Array} exportColumnNames 可选,指定导出的列名及顺序;未传时导出当前可见列
+ */
+main.exportVisibleColumnsToExcel = function (jgrid, fileName, groupConfig, exportRows, exportColumnNames) {
+ var colModel = jgrid.jqGrid('getGridParam', 'colModel');
+ var exportCols;
+ if (Array.isArray(exportColumnNames)) {
+ exportCols = exportColumnNames.map(function (name) {
+ for (var i = 0; i < colModel.length; i++) {
+ if (colModel[i].name === name) return colModel[i];
+ }
+ }).filter(function (col) { return col && col.name !== 'cb' && col.name !== 'rn'; });
+ } else {
+ // 只导出可见列(hidden !== true),与折叠状态联动:收起的列自动不可见
+ exportCols = colModel.filter(function (c) { return c.hidden !== true && c.name !== 'cb' && c.name !== 'rn'; });
+ }
+ if (!exportCols.length) { main.message && main.message("没有可导出的列"); return; }
+
+ var rows = exportRows || jgrid.jqGrid('getRowData');
+ if (exportRows) {
+ var gridElement = jgrid[0];
+ rows = exportRows.map(function (row, rowIndex) {
+ var formattedRow = {};
+ exportCols.forEach(function (col) {
+ var colIndex = colModel.indexOf(col);
+ var rawValue = $.jgrid.getAccessor(row, col.name);
+ var formattedValue = gridElement && gridElement.formatter
+ ? gridElement.formatter(rowIndex + 1, rawValue, colIndex, row, 'add')
+ : rawValue;
+ formattedRow[col.name] = $('
').html(formattedValue == null ? '' : String(formattedValue)).text().replace(/\u00a0/g, '');
+ });
+ return formattedRow;
+ });
+ }
+ var headerLabels = exportCols.map(function (c) { return c.label || c.name; });
+
+ // 构建 HTML table,用 style 保持 mso-number-format 让金额不被科学计数法破坏
+ var html = '';
+ html += '
';
+ html += '
';
+ //表头:有分组配置时导出两级表头(分类 + 字段),否则保持原单级表头。
+ if (groupConfig && groupConfig.length) {
+ html += buildGroupHeaderHtml(exportCols, groupConfig);
+ }
+ html += '' + headerLabels.map(function (l) {
+ return '| ' + escapeXml(l) + ' | ';
+ }).join('') + '
';
+ //数据行
+ for (var i = 0; i < rows.length; i++) {
+ html += '';
+ for (var c = 0; c < exportCols.length; c++) {
+ var val = rows[i][exportCols[c].name];
+ if (val === undefined || val === null) val = '';
+ html += '| ' + escapeXml(String(val)) + ' | ';
+ }
+ html += '
';
+ }
+ html += '
';
+
+ var blob = new Blob(['\ufeff' + html], { type: 'application/vnd.ms-excel;charset=utf-8' });
+ var url = URL.createObjectURL(blob);
+ var a = document.createElement('a');
+ a.href = url;
+ a.download = (fileName || 'export') + '.xls';
+ document.body.appendChild(a);
+ a.click();
+ document.body.removeChild(a);
+ setTimeout(function () { URL.revokeObjectURL(url); }, 1000);
+
+ function escapeXml(s) {
+ return s.replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"');
+ }
+
+ function buildGroupHeaderHtml(cols, config) {
+ var titleByColumn = {};
+ config.forEach(function (group) {
+ (group.columns || []).forEach(function (name) {
+ titleByColumn[name] = group.title || '';
+ });
+ });
+
+ var cells = [];
+ for (var i = 0; i < cols.length; i++) {
+ var title = titleByColumn[cols[i].name] || '';
+ var colspan = 1;
+ while (i + colspan < cols.length && (titleByColumn[cols[i + colspan].name] || '') === title) {
+ colspan++;
+ }
+ cells.push('
' + escapeXml(title) + ' | ');
+ i += colspan - 1;
+ }
+ return '
' + cells.join('') + '
';
+ }
+};
diff --git a/YLErpWeb/wwwroot/Statics/bundles/bundle.js b/YLErpWeb/wwwroot/Statics/bundles/bundle.js
index 0c9acc5c..06ac26d4 100644
--- a/YLErpWeb/wwwroot/Statics/bundles/bundle.js
+++ b/YLErpWeb/wwwroot/Statics/bundles/bundle.js
@@ -14489,7 +14489,15 @@ $.fn.selectpicker.Constructor.DEFAULTS = Object.assign($.fn.selectpicker.Constru
function __onInput() {
if (_ctrlV) {
_ctrlV = false;
- return setValue(this.value);
+ // 粘贴进来的是显示值(可能带 %/‱ 后缀),先按 __change 同款口径解析为模型值再回显,
+ // 避免 setValue 把显示值再乘以 100/10000(#EQD-5914 债券价格粘贴 ×100)
+ let f = '';
+ if (this.value && this.value !== _options.append) {
+ f = parseFloat(this.value.replaceAll(",", "")) || 0;
+ if (_options.append === '%' || _options.percent == true) f /= 100;
+ else if (_options.append === '‱') f /= 10000;
+ }
+ return setValue(f);
}
if (_chnInput >= 0) {
__onChineseInput.call(this, _chnInput);
@@ -14666,9 +14674,9 @@ $.fn.selectpicker.Constructor.DEFAULTS = Object.assign($.fn.selectpicker.Constru
}
}).datepicker({
- minDate: self.mindate,
+ minDate: self.mindate ? new Date(self.mindate) : null,
beforeShowDay(date) {
- return [(!self.maxdate || date <= new Date(self.maxdate)) && (self.noholiday || !ylotc.isHoliday(date))];
+ return [(self.noholiday || !ylotc.isHoliday(date))];
},
changeMonth: true,
changeYear: true,
diff --git a/YLErpWeb/wwwroot/Statics/libs/selectize/css/accountOpeningProcess.css b/YLErpWeb/wwwroot/Statics/libs/selectize/css/accountOpeningProcess.css
index 17140a3b..f7bd261e 100644
--- a/YLErpWeb/wwwroot/Statics/libs/selectize/css/accountOpeningProcess.css
+++ b/YLErpWeb/wwwroot/Statics/libs/selectize/css/accountOpeningProcess.css
@@ -50,7 +50,7 @@ html {
flex-direction: column;
align-items: center;
width: 100%;
- padding: 0 50px;
+ /*padding: 0 50px;*/
position: relative;
font-size: 12px;
}
@@ -430,6 +430,163 @@ html {
.glyphicon {
color: #FFFFFF !important;
}
-button:focus {
- outline: none;
-}
\ No newline at end of file
+.trigger-condition-box {
+ background-color: #FFFFFF;
+ border-radius: 5px;
+ box-shadow: 0 2px 5px 0 rgba(0, 0, 0, .1);
+ border: 1px solid #F5F5F5;
+ margin: 8px 10px 10px 10px;
+ overflow: hidden;
+}
+
+.trigger-condition-title {
+ background: rgb(255, 148, 62);
+ color: #FFFFFF;
+ font-size: 12px;
+ padding: 5px 10px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.trigger-condition-title .trigger-actions {
+ display: flex;
+ gap: 6px;
+}
+
+.trigger-action-btn {
+ display: inline-block;
+ border-radius: 15px;
+ color: rgb(50, 150, 250);
+ border: none;
+ box-shadow: 0 2px 5px 0 rgba(0, 0, 0, .1);
+ background: #FFFFFF;
+ padding: 3px 10px;
+ font-size: 12px;
+ cursor: pointer;
+ line-height: 18px;
+}
+
+.trigger-action-btn:hover {
+ background: #f5f7fa;
+ transform: scale(1.05);
+ transition: all .3s;
+}
+
+.trigger-token-list {
+ padding: 8px 10px;
+}
+
+.trigger-token-row {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ min-height: 26px;
+ margin-bottom: 4px;
+ width: 100%;
+}
+
+.trigger-token-row:last-child {
+ margin-bottom: 0;
+}
+
+.trigger-connector {
+ display: inline-block;
+ width: 60px;
+ text-align: center;
+ color: #409eff;
+ cursor: pointer;
+ font-size: 12px;
+}
+
+.trigger-paren {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 100%;
+ font-size: 12px;
+ padding: 4px 0;
+ position: relative;
+}
+
+.trigger-paren .trigger-remove,
+.trigger-condition-row .trigger-remove {
+ opacity: 0.85;
+}
+
+.trigger-paren:hover .trigger-remove,
+.trigger-condition-row:hover .trigger-remove {
+ opacity: 1;
+}
+
+.trigger-paren .trigger-remove {
+ position: absolute;
+ right: 0;
+ top: 50%;
+ transform: translateY(-50%);
+}
+
+.trigger-condition-row {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ width: 100%;
+}
+
+.trigger-condition-row .trigger-remove {
+ margin-left: auto;
+}
+
+.trigger-condition-row select,
+.trigger-condition-row input {
+ height: 20px;
+ font-size: 12px;
+ padding: 0 2px;
+ box-sizing: border-box;
+}
+
+.trigger-condition-row select {
+ width: auto;
+ min-width: 70px;
+}
+
+.trigger-condition-row input {
+ width: 80px;
+ padding-left: 4px;
+}
+
+.trigger-remove {
+ color: #ff4d4f !important;
+ cursor: pointer;
+ margin-left: 4px;
+ font-size: 11px;
+ opacity: 0.7;
+ transition: opacity 0.2s;
+}
+
+.trigger-remove:hover {
+ color: #ff7875 !important;
+ opacity: 1;
+}
+
+/* 修复审批规则 selectize 标签初始加载时下沉、不居中问题 */
+/* 关键:bundle.min.css 里设置了 .selectize-input.items.not-full.has-options { height:28px },
+ 固定高度导致标签在 baseline 对齐下下沉。这里把高度改回 auto,并强制标签垂直居中。 */
+.selectize-control.multi .selectize-input.items.not-full.has-options,
+.selectize-control.multi .selectize-input.items.not-full.has-options.has-items {
+ height: auto;
+ min-height: 20px;
+}
+
+.selectize-control.multi .selectize-input > div[data-value],
+.selectize-control.multi .selectize-input > div.item {
+ vertical-align: middle !important;
+}
+
+/* 需求③:多分支连线。多个 .col-box 时,中间列(非首非尾)的右覆盖线宽度置 0,避免连线断裂 */
+.col-box:not(:first-child):not(:last-child) .top-right-cover-line {
+ width: 0;
+}
+.col-box:not(:first-child):not(:last-child) .bottom-right-cover-line {
+ width: 0;
+}
diff --git a/项目文档/估值模块重构-前端改造说明.md b/项目文档/估值模块重构-前端改造说明.md
new file mode 100644
index 00000000..ab1f2205
--- /dev/null
+++ b/项目文档/估值模块重构-前端改造说明.md
@@ -0,0 +1,181 @@
+# 估值模块重构 - 前端改造说明
+
+> 对应需求:《估值模块V1》(`估值模块V1.pdf`)
+> 分支:`glms/feature/1.4.2`
+> 改造时间:2026-07
+
+## 一、改造范围与决策
+
+### 背景
+需求要求重构两个页面的互换相关 Tab:
+1. **日终持仓风险_互换** 的「框架合约」Tab —— 适配内部盯市场景
+2. **每日估值报告** 的「互换估值」Tab —— 适配对客发送场景
+
+### 决策:路径 A(改现有 jqGrid 前端)
+经对比分析(详见下方"方案对比"),选择**直接改现有 jqGrid 前端**,理由:
+- 计算逻辑全在后端 `SwapEodPositionService.cs`,前端只做格式化展示 —— 改动可控
+- 数据接口零改动,新旧同源,便于对比验证
+- 不换库(不升级到 free-jqGrid),零全站回归风险
+- 工作量最小
+
+### 方案对比(已否决)
+| 方案 | 否决理由 |
+|------|----------|
+| otcdms-ui 新建 Vue 页面 | 需加 Java 中转层,工作量大;数据仍来自 C#,未实现解耦 |
+| 升级 free-jqGrid | 原生支持折叠,但需回归全站 40+ 处 grouping,风险过大 |
+
+## 二、改造内容
+
+### 提交 1:通用工具(`utils.js`)
+新增两个通用函数,所有 jqGrid 页面可复用:
+- `main.initCollapsibleGroupHeaders(jgrid, groupConfig)`:生成合并表头 + 点击折叠/展开
+- `main.refreshCollapsibleGroupHeaders(jgrid)`:列重排后重建分组边界
+- `main.exportVisibleColumnsToExcel(jgrid, fileName)`:零依赖导出可见列为 Excel
+
+### 提交 2:框架合约 Tab(`EodPositionRisks.js`)
+- colModel 按需求 2.2 分组重排(组内列连续)
+- 字段命名对齐(预付金→保证金、利率端→利息端)
+- 接入可折叠分组表头(7 组)
+- **缺失字段已标注 TODO**(见第四节)
+
+### 提交 3:框架合约 Tab 导出
+- 恢复导出按钮(原被注释)
+- 接入 `exportVisibleColumnsToExcel`,与折叠状态联动
+
+### 提交 4:互换估值 Tab(`TradeMarketReport_EodPosition.js`)
+- 新增分组配置(4 组),现有列顺序天然满足连续性,无需重排
+- 接入可折叠分组表头,保留异常行标红逻辑
+- 新增簿记账户筛选(需求 3.1)
+- 新增「导出互换估值」按钮,与现有 DownLoadReport 独立
+
+## 三、分组配置映射表
+
+### 模块一:框架合约 Tab(`eodSwapGroupConfig`)
+
+| 分组 | 需求字段 | colModel.name | 后端字段 |
+|------|----------|---------------|----------|
+| 基本信息 | 交易日 | `position.ValueDate` | `eod_swap.ValueDate` |
+| | 簿记账户 | `AssetBookName` | 关联 asset_unit |
+| | 交易对手方 | `ClientName` | 关联 client |
+| | 互换交易编码 | `SwapTradeNo` | `eod_swap.SwapTradeNo` |
+| | 产品类型 | `StructureType` | trade.StructureType |
+| | 互换类型 | `SwapTradeTypeStr` | 枚举翻译 |
+| 名义本金 | 合约名义本金 | `position.NotionalValue` | `eod_swap.NotionalValue` |
+| | 合约多头名义本金 | `position.NotionalValueLong` | 同上 |
+| | 合约空头名义本金 | `position.NotionalValueShort` | 同上 |
+| 标的市值 | 合约多头标的市值 | `position.MarketValueLong` | 计算字段 |
+| | 合约空头标的市值 | `position.MarketValueShort` | 计算字段 |
+| 浮动端 | 合约浮动端待实现收益 | `position.FloatingPnL` | `eod_swap.FloatingPnL` |
+| 利息端 | 合约利息端待实现收益 | `position.InterestPnL` | `eod_swap.InterestPnL` |
+| 保证金 | 收取对手方初始保证金 | `position.InitMarginGain` | 计算字段 |
+| | 收取对手方维持保证金 | `position.PostionMarginGain` | 计算字段 |
+| | 支付初始保证金 | `position.InitMarginLoss` | 计算字段 |
+| | 支付维持保证金 | `position.PostionMarginLoss` | 计算字段 |
+| 估值与实现收益 | 合约持仓价值 | `position.PostionValue` | `eod_swap.PostionValue` |
+| | 合约当日实现收益 | `position.TdRealizedPnL` | `eod_swap.TdRealizedPnL` |
+| | 合约已实现收益 | `position.RealizedPnL` | `eod_swap.RealizedPnL` |
+| | DV | `position.dv01` | `eod_swap.dv01` |
+
+### 模块二:互换估值 Tab(`eodSwapValuationGroupConfig`)
+
+| 分组 | 需求字段 | colModel.name | 后端字段 |
+|------|----------|---------------|----------|
+| 基本信息 | 交易编号 | `TradeNumber` | trade.TradeNumber |
+| | 确认书编号 | `ConfrimNo` | trade.ConfrimNo |
+| | 交易对手 | `ClientName` | 关联 client |
+| | 起始日 | `position.PosiStartDate` | swap_position.PosiStartDate |
+| | 估值日 | `position.ValueDate` | swap_position.ValueDate |
+| | 参考标的 | `position.UnderlyingCode` | swap_position.UnderlyingCode |
+| 利率与规模 | 利差 | `InterestRate` | 计算字段 |
+| | 基准利率 | `position.FloatRateUnderlyingCode` | swap_position |
+| | 当日适用基准利率 | `position.FloatRate` | 计算字段 |
+| | 标的名义金额 | `position.PosiNotionalValue` | swap_position |
+| | 标的数量 | `position.PosiQuantity` | swap_position |
+| | 期间付息 | `PeriodAmount` | 查询时现算 |
+| 价格 | 期初标的交割全价 | `position.PosiGrossPrice` | swap_position |
+| | 期初标的成交收益率 | `InitYtm` | trade_swap |
+| | 期末标的交割全价 | `position.UnderlyingPrice` | swap_position |
+| | 实际期限 | `DayCount` | 查询时现算 |
+| 收益 | 浮动利率(绝对) | `FloatRateAbs` | 查询时现算 |
+| | 利率收益金额 | `InterestAmount` | 查询时现算 |
+| | 开仓交易费用 | `position.PosiFeePending` | swap_position |
+| | 浮动收益金额 | `position.PosiProfitSum` | swap_position |
+| | 净额结算金额 | `NetSettmentAmount` | 查询时现算 |
+
+## 四、缺失字段清单(TODO,待后端确认)
+
+以下需求字段本轮**未实现**,需后端确认数据来源后单独提交补充。
+
+### 模块一(框架合约 Tab)
+
+| 需求字段 | 需求分组 | 后端状态 | 待办 |
+|----------|----------|----------|------|
+| 标的类型 | 基本信息 | 待确认 | 加 colModel,值"现券/ETF/指数" |
+| 名义本金(概念性) | 基本信息 | 待确认 | 可能与合约名义本金重复 |
+| 期间付息/分红 | 浮动端 | 待确认 | `eod_swap` 是否有此字段 |
+| 付息方式 | 估值与实现收益 | 待确认 | 到期轧差/派息日支付,来源 trade 要素 |
+| 合约估值(到期轧差口径) | 估值与实现收益 | 待确认 | `FloatingPnL + InterestPnL + 期间付息` |
+| 合约估值(期间支付派息口径) | 估值与实现收益 | 待确认 | `FloatingPnL + InterestPnL` |
+| 保证金利息(收取/支付) | 保证金 | 待确认 | 现状 colModel 无此字段 |
+
+### 模块二(互换估值 Tab)
+
+| 需求字段 | 需求分组 | 后端状态 | 待办 |
+|----------|----------|----------|------|
+| 期间分红 | 利率与规模 | 待确认 | ETF 适用 |
+| 预付金利率 | 预付金(新分组) | 待确认 | |
+| 预付金利息 | 预付金 | 待确认 | |
+| 期初预付金 | 预付金 | 待确认 | 我方收取为正,支付为负 |
+| 追加预付金 | 预付金 | 待确认 | 我方收取为正,支付为负 |
+| TRS估值 | 汇总(新分组) | 待确认 | `净额结算金额 + 期初预付金 + 追加预付金` |
+
+## 五、已知约束
+
+### 1. 冻结列与 groupHeader 冲突
+jqGrid 4.5.4 的 `setFrozenColumns` 与 `setGroupHeaders` 合用有限制。
+参考 `clientRiskMonitor.js:284-285` 的绕法:先 `destroyFrozenColumns` 再 `setFrozenColumns`。
+本改造的目标页面未使用冻结列,暂无影响。
+
+### 2. setcolumnChooser 兼容
+`main.setcolumnChooser` 会 `remapColumns` 重排列,且不重建 groupHeader。
+解决方案:在 `gridComplete` 中用 `$.when(defer).done(...)` 确保 `setcolumnChooser` 完成后再初始化分组表头。
+若用户自定义列顺序打散了分组,`buildGroupHeaders` 会按实际可见列动态计算最接近的分组边界。
+
+### 3. 导出口径区分
+| 导出方式 | 触发 | 数据源 | 口径 |
+|----------|------|--------|------|
+| 前端可见列导出(新增) | 「导出」按钮 | jqGrid 当前页数据 | 与页面显示一致 |
+| 后端模板导出(现有) | `DownLoadReport` | C# Service | 报告格式,口径不同 |
+
+两者独立,需在 UI 和文档上区分,避免用户混淆。
+
+### 4. 导出格式
+当前前端导出为 `.xls`(HTML table + ms-excel MIME),非严格 `.xlsx`。
+若需严格 xlsx,后续可引入 SheetJS(项目已有 `Statics/libs/export/excellentexport.js`,但无实际使用范例)。
+
+## 六、测试要点
+
+### 框架合约 Tab
+1. 打开「风险控制-日终持仓风险_互换-框架合约」
+2. 表头按 7 组分组合并显示
+3. 点击各分组表头能收起(▶)/展开(▼)
+4. 展开后列对齐不错位
+5. footer 汇总行(DV)不受折叠影响
+6. 「列设置」(configure.png)功能正常
+7. 点击「导出」生成 Excel,列与页面可见列一致
+
+### 互换估值 Tab
+1. 打开「结算管理-每日估值报告-互换估值」
+2. 表头按 4 组分组合并显示
+3. 折叠交互正常
+4. 异常行标红(dataError)不受影响
+5. 簿记账户筛选生效(需后端支持 BookId 参数)
+6. 「导出互换估值」按钮可用
+7. 现有「发送报告/下载报告」功能不受影响
+
+## 七、后续工作
+
+1. **缺失字段补齐**(见第四节 TODO)—— 需后端确认字段来源
+2. **命名对齐回归** —— 预付金→保证金 改动需确认不影响现有用户习惯
+3. **导出格式升级** —— 若需严格 xlsx,引入 SheetJS
+4. **预付金/TRS估值 分组** —— 缺失字段补齐后,互换估值 Tab 新增「预付金」「汇总」两个分组