jest
This commit is contained in:
1 parent
3260b8c879
commit
556141af56
7 files changed
+210
-437
No files matched your search
@@ -0,0 +1,74 @@
|
||||
# 技能冷却与法力消耗平衡调整计划
|
||||
|
||||
## Objective (目标)
|
||||
调整主动技能(Active Skill)的 `mpCost`(法力消耗)与 `cooldown`(冷却时间)计算规则,使其随着造物材料品质(Quality)的提升而指数级上升(蓝耗)并在 2~8 回合内波动(冷却)。以适应游戏中角色境界(Realm)和基础属性的指数级增长。
|
||||
|
||||
## Key Files & Context (受影响的文件)
|
||||
1. **`engine/creation-v2/config/CreationBalance.ts`**:
|
||||
- `CREATION_PROJECTION_BALANCE`:新增 `qualityCooldownBonus: [0, 0, 1, 2, 3, 4, 5, 6] as const` 用于控制随品质带来的额外冷却。
|
||||
|
||||
2. **`engine/creation-v2/rules/composition/EnergyConversionRules.ts`**:
|
||||
- 增加指数级法力消耗计算逻辑:提取 `qualityOrder`,使用 `Math.pow(2, qualityOrder)` 作为 `mpCost` 的乘数。
|
||||
|
||||
3. **`engine/creation-v2/rules/composition/ProjectionRules.ts`**:
|
||||
- 修改 `buildSkillPolicy` 中的 `cooldown` 计算逻辑,附加对应 `qualityOrder` 的冷却补偿,并通过 `Math.min(8, baseCooldown + bonus)` 封顶为 8 回合。
|
||||
|
||||
## Implementation Steps (实施步骤)
|
||||
|
||||
### 1. 更新 `CreationBalance.ts`
|
||||
在 `CREATION_PROJECTION_BALANCE` 常量中添加 `qualityCooldownBonus` 数组:
|
||||
```typescript
|
||||
export const CREATION_PROJECTION_BALANCE = {
|
||||
// ...
|
||||
gongfaSpiritBuffBase: 3,
|
||||
|
||||
/**
|
||||
* 主动技能冷却时间品质加成(基于品质 order 0-7)。
|
||||
* 将在基础冷却上增加该值,且总冷却限制在 2~8 回合。
|
||||
*/
|
||||
qualityCooldownBonus: [0, 0, 1, 2, 3, 4, 5, 6] as const,
|
||||
} as const;
|
||||
```
|
||||
|
||||
### 2. 更新 `EnergyConversionRules.ts`
|
||||
在 `EnergyConversionRules.apply` 方法中引入 `materialQualityProfile` 并应用指数级增长:
|
||||
```typescript
|
||||
const { energySummary, affixes, materialQualityProfile } = facts;
|
||||
|
||||
const qualityOrder = materialQualityProfile.weightedAverageOrder;
|
||||
const qualityMultiplier = Math.pow(2, qualityOrder);
|
||||
|
||||
const baseMpCost = Math.round(
|
||||
energySummary.effectiveTotal / CREATION_PROJECTION_BALANCE.mpCostDivisor,
|
||||
);
|
||||
|
||||
const mpCost = Math.max(
|
||||
CREATION_SKILL_DEFAULTS.minMpCost * qualityMultiplier,
|
||||
baseMpCost * qualityMultiplier,
|
||||
);
|
||||
```
|
||||
|
||||
### 3. 更新 `ProjectionRules.ts`
|
||||
在 `ProjectionRules.buildSkillPolicy` 方法中,修改冷却时间的计算逻辑:
|
||||
```typescript
|
||||
const coreType = coreDef.effectTemplate.type;
|
||||
const baseCooldown =
|
||||
coreType === 'heal'
|
||||
? CREATION_SKILL_DEFAULTS.healCooldown
|
||||
: coreType === 'apply_buff'
|
||||
? CREATION_SKILL_DEFAULTS.buffCooldown
|
||||
: CREATION_SKILL_DEFAULTS.damageCooldown;
|
||||
|
||||
const qualityOrder = materialQualityProfile.weightedAverageOrder;
|
||||
const cooldownBonus = CREATION_PROJECTION_BALANCE.qualityCooldownBonus[qualityOrder] ?? 0;
|
||||
const cooldown = Math.min(8, baseCooldown + cooldownBonus);
|
||||
|
||||
diagnostics.addTrace({
|
||||
ruleId: this.id,
|
||||
outcome: 'applied',
|
||||
message: `cooldown=${cooldown} (coreType=${coreType}, base=${baseCooldown}, bonus=${cooldownBonus})`,
|
||||
});
|
||||
```
|
||||
|
||||
## Verification & Testing (验证与测试)
|
||||
- [ ] 运行 `npm test` 确保受影响的现有测试在更新预期的 `mpCost` 和 `cooldown` 断言后仍然通过。
|
||||
@@ -14,7 +14,6 @@ import {
|
||||
ListenerGuardConfig,
|
||||
ListenerScope,
|
||||
ModifierType,
|
||||
StackRule,
|
||||
} from '../contracts/battle';
|
||||
import type { CreationTagSignalSource } from '../types';
|
||||
import { AffixCategory, CreationProductType } from '../types';
|
||||
|
||||
@@ -1,429 +0,0 @@
|
||||
/**
|
||||
* AffixBoundaryValidation.test.ts
|
||||
*
|
||||
* 词缀边界规则校验测试(平衡三角论)。
|
||||
*
|
||||
* Part 1: 遍历 DEFAULT_AFFIX_REGISTRY 中的所有词缀,验证现有词缀全部合规。
|
||||
* Part 2: 注册违规 mock 词缀,验证 validateBoundary() 能正确拦截。
|
||||
*/
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { ModifierType } from '../../contracts/battle';
|
||||
import { GameplayTags } from '@/engine/shared/tag-domain';
|
||||
import { DEFAULT_AFFIX_REGISTRY, AffixRegistry } from '../../affixes';
|
||||
import type { AffixDefinition } from '../../affixes';
|
||||
import { matchAll } from '../../affixes';
|
||||
|
||||
/** 构造最小可注册词缀的辅助工厂 */
|
||||
function makeAffix(overrides: Partial<AffixDefinition>): AffixDefinition {
|
||||
return {
|
||||
id: 'test-affix',
|
||||
displayName: 'Test',
|
||||
displayDescription: 'Test affix',
|
||||
category: 'skill_core',
|
||||
rarity: 'common',
|
||||
match: matchAll([]),
|
||||
weight: 1,
|
||||
energyCost: 1,
|
||||
effectTemplate: { type: 'damage', params: { value: 10 } },
|
||||
applicableTo: ['skill'],
|
||||
...overrides,
|
||||
} as AffixDefinition;
|
||||
}
|
||||
|
||||
describe('AffixBoundaryValidation', () => {
|
||||
const allDefs = DEFAULT_AFFIX_REGISTRY.getAll();
|
||||
|
||||
// ===== Part 1: 现有词缀合规性审计 =====
|
||||
|
||||
it('gongfa 词缀禁止使用 OWNER_AS_TARGET scope', () => {
|
||||
const violations = allDefs.filter(
|
||||
(def) =>
|
||||
def.applicableTo.includes('gongfa') &&
|
||||
def.listenerSpec?.scope === GameplayTags.SCOPE.OWNER_AS_TARGET,
|
||||
);
|
||||
|
||||
expect(violations.map((d) => d.id)).toEqual([]);
|
||||
});
|
||||
|
||||
it('skill 词缀禁止使用 attribute_modifier effectType', () => {
|
||||
const violations = allDefs.filter(
|
||||
(def) =>
|
||||
def.applicableTo.includes('skill') &&
|
||||
def.effectTemplate.type === 'attribute_modifier',
|
||||
);
|
||||
|
||||
expect(violations.map((d) => d.id)).toEqual([]);
|
||||
});
|
||||
|
||||
it('artifact 词缀禁止使用 ADD 百分比 attribute_modifier', () => {
|
||||
const violations = allDefs.filter((def) => {
|
||||
if (!def.applicableTo.includes('artifact')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (def.effectTemplate.type !== 'attribute_modifier') {
|
||||
return false;
|
||||
}
|
||||
|
||||
const params = def.effectTemplate.params;
|
||||
if ('modifiers' in params) {
|
||||
return params.modifiers.some((modifier) => modifier.modType === ModifierType.ADD);
|
||||
}
|
||||
|
||||
return params.modType === ModifierType.ADD;
|
||||
});
|
||||
|
||||
expect(violations.map((d) => d.id)).toEqual([]);
|
||||
});
|
||||
|
||||
|
||||
it('artifact 词缀禁止使用 OWNER_AS_CASTER scope', () => {
|
||||
const violations = allDefs.filter(
|
||||
(def) =>
|
||||
def.applicableTo.includes('artifact') &&
|
||||
def.listenerSpec?.scope === GameplayTags.SCOPE.OWNER_AS_CASTER,
|
||||
);
|
||||
|
||||
expect(violations.map((d) => d.id)).toEqual([]);
|
||||
});
|
||||
|
||||
it('DEFAULT_AFFIX_REGISTRY 应包含所有三种产物类型的词缀', () => {
|
||||
const hasArtifact = allDefs.some((d) => d.applicableTo.includes('artifact'));
|
||||
const hasGongfa = allDefs.some((d) => d.applicableTo.includes('gongfa'));
|
||||
const hasSkill = allDefs.some((d) => d.applicableTo.includes('skill'));
|
||||
expect(hasArtifact).toBe(true);
|
||||
expect(hasGongfa).toBe(true);
|
||||
expect(hasSkill).toBe(true);
|
||||
});
|
||||
|
||||
it('no commonAffixes remain (applicableTo 中不再有跨产物类型的词缀)', () => {
|
||||
const crossProductAffixes = allDefs.filter(
|
||||
(def) =>
|
||||
def.applicableTo.includes('artifact') && def.applicableTo.includes('gongfa'),
|
||||
);
|
||||
expect(crossProductAffixes.map((d) => d.id)).toEqual([]);
|
||||
});
|
||||
|
||||
it('池与产物类型强绑定: skill_* 池词缀仅适用于 skill', () => {
|
||||
const violations = allDefs.filter(
|
||||
(def) =>
|
||||
def.category.startsWith('skill_') &&
|
||||
def.applicableTo.some((t) => t !== 'skill'),
|
||||
);
|
||||
expect(violations.map((d) => d.id)).toEqual([]);
|
||||
});
|
||||
|
||||
it('池与产物类型强绑定: gongfa_* 池词缀仅适用于 gongfa', () => {
|
||||
const violations = allDefs.filter(
|
||||
(def) =>
|
||||
def.category.startsWith('gongfa_') &&
|
||||
def.applicableTo.some((t) => t !== 'gongfa'),
|
||||
);
|
||||
expect(violations.map((d) => d.id)).toEqual([]);
|
||||
});
|
||||
|
||||
it('池与产物类型强绑定: artifact_* 池词缀仅适用于 artifact', () => {
|
||||
const violations = allDefs.filter(
|
||||
(def) =>
|
||||
def.category.startsWith('artifact_') &&
|
||||
def.applicableTo.some((t) => t !== 'artifact'),
|
||||
);
|
||||
expect(violations.map((d) => d.id)).toEqual([]);
|
||||
});
|
||||
|
||||
it('稀有池词缀的 rarity 必须为 rare 或 legendary', () => {
|
||||
const rarePools = ['skill_rare', 'gongfa_secret', 'artifact_treasure'];
|
||||
const violations = allDefs.filter(
|
||||
(def) =>
|
||||
rarePools.includes(def.category) &&
|
||||
def.rarity !== 'rare' &&
|
||||
def.rarity !== 'legendary',
|
||||
);
|
||||
expect(violations.map((d) => d.id)).toEqual([]);
|
||||
});
|
||||
|
||||
// ===== Part 2: validateBoundary() 拦截测试 =====
|
||||
|
||||
describe('validateBoundary() 拦截违规词缀', () => {
|
||||
it('拦截 pool-product binding 违规: skill_core 词缀不能 applicableTo gongfa', () => {
|
||||
const registry = new AffixRegistry();
|
||||
expect(() =>
|
||||
registry.register([
|
||||
makeAffix({
|
||||
id: 'bad-pool-binding',
|
||||
category: 'skill_core',
|
||||
applicableTo: ['gongfa'],
|
||||
}),
|
||||
]),
|
||||
).toThrow('pool-product binding violation');
|
||||
});
|
||||
|
||||
it('拦截 pool-product binding 违规: artifact_panel 词缀不能 applicableTo skill', () => {
|
||||
const registry = new AffixRegistry();
|
||||
expect(() =>
|
||||
registry.register([
|
||||
makeAffix({
|
||||
id: 'bad-pool-binding-2',
|
||||
category: 'artifact_panel',
|
||||
applicableTo: ['skill'],
|
||||
effectTemplate: {
|
||||
type: 'attribute_modifier',
|
||||
params: { attrType: 'ATK' as any, modType: ModifierType.FIXED, value: 10 },
|
||||
},
|
||||
}),
|
||||
]),
|
||||
).toThrow('pool-product binding violation');
|
||||
});
|
||||
|
||||
it('拦截稀有池 rarity 违规: skill_rare 不接受 common', () => {
|
||||
const registry = new AffixRegistry();
|
||||
expect(() =>
|
||||
registry.register([
|
||||
makeAffix({
|
||||
id: 'bad-rarity',
|
||||
category: 'skill_rare',
|
||||
rarity: 'common',
|
||||
applicableTo: ['skill'],
|
||||
}),
|
||||
]),
|
||||
).toThrow('rare pool rarity violation');
|
||||
});
|
||||
|
||||
it('拦截稀有池 rarity 违规: gongfa_secret 不接受 uncommon', () => {
|
||||
const registry = new AffixRegistry();
|
||||
expect(() =>
|
||||
registry.register([
|
||||
makeAffix({
|
||||
id: 'bad-rarity-gongfa',
|
||||
category: 'gongfa_secret',
|
||||
rarity: 'uncommon',
|
||||
applicableTo: ['gongfa'],
|
||||
}),
|
||||
]),
|
||||
).toThrow('rare pool rarity violation');
|
||||
});
|
||||
|
||||
it('拦截稀有池 rarity 违规: artifact_treasure 不接受 common', () => {
|
||||
const registry = new AffixRegistry();
|
||||
expect(() =>
|
||||
registry.register([
|
||||
makeAffix({
|
||||
id: 'bad-rarity-artifact',
|
||||
category: 'artifact_treasure',
|
||||
rarity: 'common',
|
||||
applicableTo: ['artifact'],
|
||||
}),
|
||||
]),
|
||||
).toThrow('rare pool rarity violation');
|
||||
});
|
||||
|
||||
it('稀有池允许 rare rarity', () => {
|
||||
const registry = new AffixRegistry();
|
||||
expect(() =>
|
||||
registry.register([
|
||||
makeAffix({
|
||||
id: 'ok-rare',
|
||||
category: 'skill_rare',
|
||||
rarity: 'rare',
|
||||
applicableTo: ['skill'],
|
||||
}),
|
||||
]),
|
||||
).not.toThrow();
|
||||
});
|
||||
|
||||
it('稀有池允许 legendary rarity', () => {
|
||||
const registry = new AffixRegistry();
|
||||
expect(() =>
|
||||
registry.register([
|
||||
makeAffix({
|
||||
id: 'ok-legendary',
|
||||
category: 'gongfa_secret',
|
||||
rarity: 'legendary',
|
||||
applicableTo: ['gongfa'],
|
||||
}),
|
||||
]),
|
||||
).not.toThrow();
|
||||
});
|
||||
|
||||
it('拦截 artifact OWNER_AS_CASTER scope', () => {
|
||||
const registry = new AffixRegistry();
|
||||
expect(() =>
|
||||
registry.register([
|
||||
makeAffix({
|
||||
id: 'bad-artifact-scope',
|
||||
category: 'artifact_defense',
|
||||
rarity: 'common',
|
||||
applicableTo: ['artifact'],
|
||||
listenerSpec: {
|
||||
scope: GameplayTags.SCOPE.OWNER_AS_CASTER as any,
|
||||
trigger: 'ON_TURN_START' as any,
|
||||
priority: 50,
|
||||
},
|
||||
}),
|
||||
]),
|
||||
).toThrow('artifact affix must not use OWNER_AS_CASTER scope');
|
||||
});
|
||||
|
||||
it('拦截 gongfa OWNER_AS_TARGET scope', () => {
|
||||
const registry = new AffixRegistry();
|
||||
expect(() =>
|
||||
registry.register([
|
||||
makeAffix({
|
||||
id: 'bad-gongfa-scope',
|
||||
category: 'gongfa_school',
|
||||
rarity: 'common',
|
||||
applicableTo: ['gongfa'],
|
||||
listenerSpec: {
|
||||
scope: GameplayTags.SCOPE.OWNER_AS_TARGET as any,
|
||||
trigger: 'ON_BEING_HIT' as any,
|
||||
priority: 50,
|
||||
},
|
||||
}),
|
||||
]),
|
||||
).toThrow('gongfa affix must not use OWNER_AS_TARGET scope');
|
||||
});
|
||||
|
||||
it('拦截 skill attribute_modifier effectType', () => {
|
||||
const registry = new AffixRegistry();
|
||||
expect(() =>
|
||||
registry.register([
|
||||
makeAffix({
|
||||
id: 'bad-skill-attr-mod',
|
||||
category: 'skill_core',
|
||||
applicableTo: ['skill'],
|
||||
effectTemplate: {
|
||||
type: 'attribute_modifier',
|
||||
params: { attrType: 'ATK' as any, modType: ModifierType.ADD, value: 10 },
|
||||
},
|
||||
}),
|
||||
]),
|
||||
).toThrow('skill affix must not use attribute_modifier effect type');
|
||||
});
|
||||
|
||||
it('拦截 gongfa attribute_modifier FIXED modType', () => {
|
||||
const registry = new AffixRegistry();
|
||||
expect(() =>
|
||||
registry.register([
|
||||
makeAffix({
|
||||
id: 'bad-gongfa-fixed',
|
||||
category: 'gongfa_foundation',
|
||||
applicableTo: ['gongfa'],
|
||||
effectTemplate: {
|
||||
type: 'attribute_modifier',
|
||||
params: { attrType: 'ATK' as any, modType: ModifierType.FIXED, value: 100 },
|
||||
},
|
||||
}),
|
||||
]),
|
||||
).toThrow('gongfa affix must not use ModifierType.FIXED');
|
||||
});
|
||||
|
||||
it('拦截 gongfa attribute_modifier FIXED modType (modifiers 数组形式)', () => {
|
||||
const registry = new AffixRegistry();
|
||||
expect(() =>
|
||||
registry.register([
|
||||
makeAffix({
|
||||
id: 'bad-gongfa-fixed-array',
|
||||
category: 'gongfa_foundation',
|
||||
applicableTo: ['gongfa'],
|
||||
effectTemplate: {
|
||||
type: 'attribute_modifier',
|
||||
params: {
|
||||
modifiers: [
|
||||
{ attrType: 'ATK' as any, modType: ModifierType.ADD, value: 10 },
|
||||
{ attrType: 'DEF' as any, modType: ModifierType.FIXED, value: 50 },
|
||||
],
|
||||
},
|
||||
},
|
||||
}),
|
||||
]),
|
||||
).toThrow('gongfa affix must not use ModifierType.FIXED');
|
||||
});
|
||||
|
||||
it('拦截 skill apply_buff 内嵌 OWNER_AS_CASTER listener 且 duration > 1', () => {
|
||||
const registry = new AffixRegistry();
|
||||
expect(() =>
|
||||
registry.register([
|
||||
makeAffix({
|
||||
id: 'bad-skill-long-buff',
|
||||
category: 'skill_variant',
|
||||
applicableTo: ['skill'],
|
||||
effectTemplate: {
|
||||
type: 'apply_buff',
|
||||
params: {
|
||||
buffConfig: {
|
||||
name: 'test',
|
||||
duration: 3,
|
||||
listeners: [
|
||||
{
|
||||
scope: GameplayTags.SCOPE.OWNER_AS_CASTER,
|
||||
trigger: 'ON_TURN_START' as any,
|
||||
effects: [],
|
||||
},
|
||||
],
|
||||
} as any,
|
||||
},
|
||||
},
|
||||
}),
|
||||
]),
|
||||
).toThrow('skill affix must not use apply_buff with OWNER_AS_CASTER listener and duration > 1');
|
||||
});
|
||||
|
||||
it('skill apply_buff OWNER_AS_TARGET listener + duration > 1 允许 (DOT/debuff)', () => {
|
||||
const registry = new AffixRegistry();
|
||||
expect(() =>
|
||||
registry.register([
|
||||
makeAffix({
|
||||
id: 'ok-skill-dot-buff',
|
||||
category: 'skill_variant',
|
||||
applicableTo: ['skill'],
|
||||
effectTemplate: {
|
||||
type: 'apply_buff',
|
||||
params: {
|
||||
buffConfig: {
|
||||
name: 'burn',
|
||||
duration: 3,
|
||||
listeners: [
|
||||
{
|
||||
scope: GameplayTags.SCOPE.OWNER_AS_TARGET,
|
||||
trigger: 'ON_TURN_START' as any,
|
||||
effects: [],
|
||||
},
|
||||
],
|
||||
} as any,
|
||||
},
|
||||
},
|
||||
}),
|
||||
]),
|
||||
).not.toThrow();
|
||||
});
|
||||
|
||||
it('skill apply_buff duration=1 内嵌 listener 允许通过', () => {
|
||||
const registry = new AffixRegistry();
|
||||
expect(() =>
|
||||
registry.register([
|
||||
makeAffix({
|
||||
id: 'ok-skill-short-buff',
|
||||
category: 'skill_variant',
|
||||
applicableTo: ['skill'],
|
||||
effectTemplate: {
|
||||
type: 'apply_buff',
|
||||
params: {
|
||||
buffConfig: {
|
||||
name: 'test',
|
||||
duration: 1,
|
||||
listeners: [
|
||||
{
|
||||
scope: GameplayTags.SCOPE.OWNER_AS_CASTER,
|
||||
trigger: 'ON_TURN_START' as any,
|
||||
effects: [],
|
||||
},
|
||||
],
|
||||
} as any,
|
||||
},
|
||||
},
|
||||
}),
|
||||
]),
|
||||
).not.toThrow();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,5 +1,5 @@
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
const nextJest = require('next/jest');
|
||||
import type { Config } from 'jest';
|
||||
import nextJest from 'next/jest.js';
|
||||
|
||||
const createJestConfig = nextJest({
|
||||
// Provide the path to your Next.js app to load next.config.js and .env files in your test environment
|
||||
@@ -7,10 +7,10 @@ const createJestConfig = nextJest({
|
||||
});
|
||||
|
||||
// Add any custom config to be passed to Jest
|
||||
const customJestConfig = {
|
||||
setupFilesAfterEnv: [],
|
||||
testEnvironment: 'node',
|
||||
testTimeout: 10000, // 全局默认 10 秒
|
||||
const config: Config = {
|
||||
coverageProvider: 'v8',
|
||||
// Add more setup options before each test is run
|
||||
// setupFilesAfterEnv: ['<rootDir>/jest.setup.ts'],
|
||||
moduleNameMapper: {
|
||||
'^@/(.*)$': '<rootDir>/$1',
|
||||
'^d3-(.+)$': '<rootDir>/node_modules/d3-$1/dist/d3-$1.js',
|
||||
@@ -18,4 +18,4 @@ const customJestConfig = {
|
||||
};
|
||||
|
||||
// createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async
|
||||
module.exports = createJestConfig(customJestConfig);
|
||||
export default createJestConfig(config);
|
||||
Generated
+127
@@ -54,6 +54,7 @@
|
||||
"supertest": "^7.2.2",
|
||||
"tailwindcss": "^4",
|
||||
"ts-jest": "^29.4.6",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^5",
|
||||
"wrangler": "^4.72.0"
|
||||
}
|
||||
@@ -6294,6 +6295,34 @@
|
||||
"tailwindcss": "4.2.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@tsconfig/node10": {
|
||||
"version": "1.0.12",
|
||||
"resolved": "https://registry.npmmirror.com/@tsconfig/node10/-/node10-1.0.12.tgz",
|
||||
"integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@tsconfig/node12": {
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmmirror.com/@tsconfig/node12/-/node12-1.0.11.tgz",
|
||||
"integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@tsconfig/node14": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmmirror.com/@tsconfig/node14/-/node14-1.0.3.tgz",
|
||||
"integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@tsconfig/node16": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmmirror.com/@tsconfig/node16/-/node16-1.0.4.tgz",
|
||||
"integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@tsconfig/node18": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmmirror.com/@tsconfig/node18/-/node18-1.0.3.tgz",
|
||||
@@ -7163,6 +7192,19 @@
|
||||
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/acorn-walk": {
|
||||
"version": "8.3.5",
|
||||
"resolved": "https://registry.npmmirror.com/acorn-walk/-/acorn-walk-8.3.5.tgz",
|
||||
"integrity": "sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"acorn": "^8.11.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/agentkeepalive": {
|
||||
"version": "4.6.0",
|
||||
"resolved": "https://registry.npmmirror.com/agentkeepalive/-/agentkeepalive-4.6.0.tgz",
|
||||
@@ -7284,6 +7326,13 @@
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/arg": {
|
||||
"version": "4.1.3",
|
||||
"resolved": "https://registry.npmmirror.com/arg/-/arg-4.1.3.tgz",
|
||||
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/argparse": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz",
|
||||
@@ -8209,6 +8258,13 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/create-require": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmmirror.com/create-require/-/create-require-1.1.1.tgz",
|
||||
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/cross-spawn": {
|
||||
"version": "7.0.6",
|
||||
"resolved": "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
||||
@@ -8467,6 +8523,16 @@
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/diff": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmmirror.com/diff/-/diff-4.0.4.tgz",
|
||||
"integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"engines": {
|
||||
"node": ">=0.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/doctrine": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/doctrine/-/doctrine-2.1.0.tgz",
|
||||
@@ -15873,6 +15939,50 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/ts-node": {
|
||||
"version": "10.9.2",
|
||||
"resolved": "https://registry.npmmirror.com/ts-node/-/ts-node-10.9.2.tgz",
|
||||
"integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@cspotcode/source-map-support": "^0.8.0",
|
||||
"@tsconfig/node10": "^1.0.7",
|
||||
"@tsconfig/node12": "^1.0.7",
|
||||
"@tsconfig/node14": "^1.0.0",
|
||||
"@tsconfig/node16": "^1.0.2",
|
||||
"acorn": "^8.4.1",
|
||||
"acorn-walk": "^8.1.1",
|
||||
"arg": "^4.1.0",
|
||||
"create-require": "^1.1.0",
|
||||
"diff": "^4.0.1",
|
||||
"make-error": "^1.1.1",
|
||||
"v8-compile-cache-lib": "^3.0.1",
|
||||
"yn": "3.1.1"
|
||||
},
|
||||
"bin": {
|
||||
"ts-node": "dist/bin.js",
|
||||
"ts-node-cwd": "dist/bin-cwd.js",
|
||||
"ts-node-esm": "dist/bin-esm.js",
|
||||
"ts-node-script": "dist/bin-script.js",
|
||||
"ts-node-transpile-only": "dist/bin-transpile.js",
|
||||
"ts-script": "dist/bin-script-deprecated.js"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@swc/core": ">=1.2.50",
|
||||
"@swc/wasm": ">=1.2.50",
|
||||
"@types/node": "*",
|
||||
"typescript": ">=2.7"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@swc/core": {
|
||||
"optional": true
|
||||
},
|
||||
"@swc/wasm": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/ts-tqdm": {
|
||||
"version": "0.8.6",
|
||||
"resolved": "https://registry.npmmirror.com/ts-tqdm/-/ts-tqdm-0.8.6.tgz",
|
||||
@@ -16254,6 +16364,13 @@
|
||||
"uuid": "dist-node/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/v8-compile-cache-lib": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
|
||||
"integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/v8-to-istanbul": {
|
||||
"version": "9.3.0",
|
||||
"resolved": "https://registry.npmmirror.com/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz",
|
||||
@@ -17163,6 +17280,16 @@
|
||||
"node": "^20.19.0 || ^22.12.0 || >=23"
|
||||
}
|
||||
},
|
||||
"node_modules/yn": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmmirror.com/yn/-/yn-3.1.1.tgz",
|
||||
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/yocto-queue": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/yocto-queue/-/yocto-queue-0.1.0.tgz",
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
"supertest": "^7.2.2",
|
||||
"tailwindcss": "^4",
|
||||
"ts-jest": "^29.4.6",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^5",
|
||||
"wrangler": "^4.72.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
"target": "ES2024",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"types": ["jest", "node"],
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"noEmit": true,
|
||||
|
||||
Reference in new issue
Block a user