volleyballsimtypes 0.0.473 → 0.0.475
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/src/api/index.d.ts +8 -0
- package/dist/cjs/src/data/models/tactics.d.ts +10 -1
- package/dist/cjs/src/data/models/tactics.js +4 -0
- package/dist/cjs/src/data/transformers/tactics.js +66 -2
- package/dist/cjs/src/data/transformers/tactics.test.js +44 -0
- package/dist/cjs/src/service/team/index.d.ts +1 -0
- package/dist/cjs/src/service/team/index.js +1 -0
- package/dist/cjs/src/service/team/libero-injury.d.ts +6 -0
- package/dist/cjs/src/service/team/libero-injury.js +2 -0
- package/dist/cjs/src/service/team/libero-sub.d.ts +4 -1
- package/dist/cjs/src/service/team/pinch-condition.d.ts +12 -2
- package/dist/cjs/src/service/team/pinch-condition.js +10 -2
- package/dist/cjs/src/service/team/schemas/designated-sub.z.d.ts +13 -1
- package/dist/cjs/src/service/team/schemas/designated-sub.z.js +3 -1
- package/dist/cjs/src/service/team/schemas/libero-injury.z.test.d.ts +1 -0
- package/dist/cjs/src/service/team/schemas/libero-injury.z.test.js +71 -0
- package/dist/cjs/src/service/team/schemas/libero-sub.z.d.ts +94 -0
- package/dist/cjs/src/service/team/schemas/libero-sub.z.js +23 -6
- package/dist/cjs/src/service/team/schemas/libero-sub.z.test.js +33 -2
- package/dist/cjs/src/service/team/schemas/tactics.z.d.ts +73 -0
- package/dist/cjs/src/service/team/schemas/tactics.z.js +41 -1
- package/dist/cjs/src/service/team/schemas/team.z.d.ts +73 -0
- package/dist/cjs/src/service/team/tactics.d.ts +3 -0
- package/dist/cjs/src/service/team/tactics.js +2 -1
- package/dist/esm/src/api/index.d.ts +8 -0
- package/dist/esm/src/data/models/tactics.d.ts +10 -1
- package/dist/esm/src/data/models/tactics.js +4 -0
- package/dist/esm/src/data/transformers/tactics.js +66 -2
- package/dist/esm/src/data/transformers/tactics.test.js +44 -0
- package/dist/esm/src/service/team/index.d.ts +1 -0
- package/dist/esm/src/service/team/index.js +1 -0
- package/dist/esm/src/service/team/libero-injury.d.ts +6 -0
- package/dist/esm/src/service/team/libero-injury.js +1 -0
- package/dist/esm/src/service/team/libero-sub.d.ts +4 -1
- package/dist/esm/src/service/team/pinch-condition.d.ts +12 -2
- package/dist/esm/src/service/team/pinch-condition.js +9 -1
- package/dist/esm/src/service/team/schemas/designated-sub.z.d.ts +13 -1
- package/dist/esm/src/service/team/schemas/designated-sub.z.js +4 -2
- package/dist/esm/src/service/team/schemas/libero-injury.z.test.d.ts +1 -0
- package/dist/esm/src/service/team/schemas/libero-injury.z.test.js +69 -0
- package/dist/esm/src/service/team/schemas/libero-sub.z.d.ts +94 -0
- package/dist/esm/src/service/team/schemas/libero-sub.z.js +23 -6
- package/dist/esm/src/service/team/schemas/libero-sub.z.test.js +33 -2
- package/dist/esm/src/service/team/schemas/tactics.z.d.ts +73 -0
- package/dist/esm/src/service/team/schemas/tactics.z.js +41 -1
- package/dist/esm/src/service/team/schemas/team.z.d.ts +73 -0
- package/dist/esm/src/service/team/tactics.d.ts +3 -0
- package/dist/esm/src/service/team/tactics.js +2 -1
- package/package.json +1 -1
|
@@ -111,9 +111,16 @@ export interface ApiInjuryReplacement {
|
|
|
111
111
|
replacementId: string;
|
|
112
112
|
benchBackfillId?: string;
|
|
113
113
|
}
|
|
114
|
+
export interface ApiLiberoInjury {
|
|
115
|
+
preMatchReplacementId?: string;
|
|
116
|
+
secondLiberoBackfillId?: string;
|
|
117
|
+
inMatchDesignateId?: string;
|
|
118
|
+
}
|
|
114
119
|
export interface ApiLiberoSetSubConfig {
|
|
115
120
|
mode: LiberoSubMode;
|
|
116
121
|
fatigueBand?: EnergyBand;
|
|
122
|
+
conditions?: PinchCondition[];
|
|
123
|
+
conditionLogic?: ConditionLogic;
|
|
117
124
|
}
|
|
118
125
|
export interface ApiLiberoSubConfig extends ApiLiberoSetSubConfig {
|
|
119
126
|
sets?: ApiLiberoSetSubConfig[];
|
|
@@ -134,6 +141,7 @@ export interface Tactics {
|
|
|
134
141
|
offensivePreferenceSets?: ApiOffensivePreference[][];
|
|
135
142
|
replaceKnockedImmediately?: Record<string, boolean>;
|
|
136
143
|
injuryReplacements?: ApiInjuryReplacement[];
|
|
144
|
+
liberoInjury?: ApiLiberoInjury;
|
|
137
145
|
}
|
|
138
146
|
export interface ApiLineupPreset {
|
|
139
147
|
presetId: string;
|
|
@@ -44,9 +44,16 @@ export interface InjuryReplacementAttributes {
|
|
|
44
44
|
replacementId: PlayerId;
|
|
45
45
|
benchBackfillId?: PlayerId;
|
|
46
46
|
}
|
|
47
|
+
export interface LiberoInjuryAttributes {
|
|
48
|
+
preMatchReplacementId?: PlayerId;
|
|
49
|
+
secondLiberoBackfillId?: PlayerId;
|
|
50
|
+
inMatchDesignateId?: PlayerId;
|
|
51
|
+
}
|
|
47
52
|
export interface LiberoSetSubConfigAttributes {
|
|
48
53
|
mode: LiberoSubMode;
|
|
49
54
|
fatigueBand?: EnergyBand;
|
|
55
|
+
conditions?: PinchCondition[];
|
|
56
|
+
conditionLogic?: ConditionLogic;
|
|
50
57
|
}
|
|
51
58
|
export interface LiberoSubConfigAttributes extends LiberoSetSubConfigAttributes {
|
|
52
59
|
sets?: LiberoSetSubConfigAttributes[];
|
|
@@ -68,10 +75,11 @@ export interface TacticsAttributes {
|
|
|
68
75
|
offensive_preference_sets?: OffensivePreferenceAttributes[][];
|
|
69
76
|
replace_knocked_immediately?: Record<PlayerId, boolean>;
|
|
70
77
|
injury_replacements?: InjuryReplacementAttributes[];
|
|
78
|
+
libero_injury?: LiberoInjuryAttributes;
|
|
71
79
|
}
|
|
72
80
|
export type TacticsPk = 'team_id';
|
|
73
81
|
export type TacticsId = TacticsModel[TacticsPk];
|
|
74
|
-
export type TacticsOptionalAttributes = 'lineup' | 'libero_replacements' | 'receive_rotation_offset' | 'designated_subs' | 'substitution_band' | 'second_libero' | 'libero_sub' | 'libero_replacement_sets' | 'rotation_system' | 'designated_setters' | 'offensive_preferences' | 'system_sets' | 'offensive_preference_sets' | 'replace_knocked_immediately' | 'injury_replacements';
|
|
82
|
+
export type TacticsOptionalAttributes = 'lineup' | 'libero_replacements' | 'receive_rotation_offset' | 'designated_subs' | 'substitution_band' | 'second_libero' | 'libero_sub' | 'libero_replacement_sets' | 'rotation_system' | 'designated_setters' | 'offensive_preferences' | 'system_sets' | 'offensive_preference_sets' | 'replace_knocked_immediately' | 'injury_replacements' | 'libero_injury';
|
|
75
83
|
export type TacticsCreationAttributes = Optional<TacticsAttributes, TacticsOptionalAttributes>;
|
|
76
84
|
export declare class TacticsModel extends Model<TacticsAttributes, TacticsCreationAttributes> implements TacticsAttributes {
|
|
77
85
|
team_id: string;
|
|
@@ -90,6 +98,7 @@ export declare class TacticsModel extends Model<TacticsAttributes, TacticsCreati
|
|
|
90
98
|
offensive_preference_sets?: OffensivePreferenceAttributes[][];
|
|
91
99
|
replace_knocked_immediately?: Record<PlayerId, boolean>;
|
|
92
100
|
injury_replacements?: InjuryReplacementAttributes[];
|
|
101
|
+
libero_injury?: LiberoInjuryAttributes;
|
|
93
102
|
team: TeamModel;
|
|
94
103
|
getTeam: Sequelize.BelongsToGetAssociationMixin<TeamModel>;
|
|
95
104
|
setTeam: Sequelize.BelongsToSetAssociationMixin<TeamModel, TeamId>;
|
|
@@ -93,7 +93,14 @@ function transformToAttributes(tactics, teamId) {
|
|
|
93
93
|
starterId: ir.starter.id,
|
|
94
94
|
replacementId: ir.replacement.id,
|
|
95
95
|
benchBackfillId: ir.benchBackfill?.id
|
|
96
|
-
}))
|
|
96
|
+
})),
|
|
97
|
+
libero_injury: tactics.liberoInjury != null
|
|
98
|
+
? {
|
|
99
|
+
preMatchReplacementId: tactics.liberoInjury.preMatchReplacement?.id,
|
|
100
|
+
secondLiberoBackfillId: tactics.liberoInjury.secondLiberoBackfill?.id,
|
|
101
|
+
inMatchDesignateId: tactics.liberoInjury.inMatchDesignate?.id
|
|
102
|
+
}
|
|
103
|
+
: undefined
|
|
97
104
|
};
|
|
98
105
|
}
|
|
99
106
|
// Accepts TacticsAttributes (not just TacticsModel) so a per-match preset's config, shaped as column data by
|
|
@@ -221,6 +228,38 @@ function transformToObject(model, roster) {
|
|
|
221
228
|
healed.push({ starter, replacement, benchBackfill });
|
|
222
229
|
}
|
|
223
230
|
return healed;
|
|
231
|
+
})(),
|
|
232
|
+
// LENIENT (roster.find): drop any stale/invalid libero-injury id so a bad row can never crash a team load.
|
|
233
|
+
// Mirrors the schema pool rules: preMatchReplacement is a RESERVE or the L2 (not in the lineup) and needs a
|
|
234
|
+
// starting libero; secondLiberoBackfill is a RESERVE (not the current L2) kept only when the L2 is the
|
|
235
|
+
// replacement; inMatchDesignate is a bench/reserve player (not a court starter, the libero, or the L2).
|
|
236
|
+
liberoInjury: (() => {
|
|
237
|
+
const li = model.libero_injury;
|
|
238
|
+
if (li == null)
|
|
239
|
+
return undefined;
|
|
240
|
+
const liberoZoneId = lineup[service_1.CourtPosition.LIBERO_ZONE]?.id;
|
|
241
|
+
const injuryStarterIds = new Set([lineup[service_1.CourtPosition.LEFT_FRONT], lineup[service_1.CourtPosition.MIDDLE_FRONT], lineup[service_1.CourtPosition.RIGHT_FRONT],
|
|
242
|
+
lineup[service_1.CourtPosition.LEFT_BACK], lineup[service_1.CourtPosition.MIDDLE_BACK], lineup[service_1.CourtPosition.RIGHT_BACK]]
|
|
243
|
+
.map((p) => p.id));
|
|
244
|
+
const reserveOrL2 = (id) => {
|
|
245
|
+
if (id == null)
|
|
246
|
+
return undefined;
|
|
247
|
+
const p = roster.find((x) => x.id === id);
|
|
248
|
+
return p != null && !inLineupIds.has(p.id) ? p : undefined;
|
|
249
|
+
};
|
|
250
|
+
const preMatchReplacement = liberoZoneId != null ? reserveOrL2(li.preMatchReplacementId) : undefined;
|
|
251
|
+
const secondLiberoBackfill = (preMatchReplacement != null && preMatchReplacement.id === secondLibero?.id)
|
|
252
|
+
? (() => { const p = reserveOrL2(li.secondLiberoBackfillId); return p != null && p.id !== secondLibero?.id ? p : undefined; })()
|
|
253
|
+
: undefined;
|
|
254
|
+
const inMatchDesignate = (() => {
|
|
255
|
+
const p = li.inMatchDesignateId != null ? roster.find((x) => x.id === li.inMatchDesignateId) : undefined;
|
|
256
|
+
if (p == null || injuryStarterIds.has(p.id) || p.id === liberoZoneId || p.id === secondLibero?.id)
|
|
257
|
+
return undefined;
|
|
258
|
+
return p;
|
|
259
|
+
})();
|
|
260
|
+
if (preMatchReplacement == null && secondLiberoBackfill == null && inMatchDesignate == null)
|
|
261
|
+
return undefined;
|
|
262
|
+
return { preMatchReplacement, secondLiberoBackfill, inMatchDesignate };
|
|
224
263
|
})()
|
|
225
264
|
});
|
|
226
265
|
}
|
|
@@ -325,6 +364,30 @@ function tacticsColumnsToApiDto(model) {
|
|
|
325
364
|
healed.push({ starterId: ir.starterId, replacementId: ir.replacementId, benchBackfillId });
|
|
326
365
|
}
|
|
327
366
|
return healed.length > 0 ? healed : undefined;
|
|
367
|
+
})(),
|
|
368
|
+
// Same stale-data policy for the libero-injury ids (ids only; roster membership is checked in the service
|
|
369
|
+
// heal). preMatchReplacement = reserve or the L2 (not in the lineup) + needs a starting libero;
|
|
370
|
+
// secondLiberoBackfill = a reserve (not the current L2) kept only when the L2 is the replacement;
|
|
371
|
+
// inMatchDesignate = a bench/reserve player (not a court starter, the libero, or the L2).
|
|
372
|
+
liberoInjury: (() => {
|
|
373
|
+
const li = model.libero_injury;
|
|
374
|
+
if (li == null)
|
|
375
|
+
return undefined;
|
|
376
|
+
const liberoZoneId = model.lineup[service_1.CourtPosition.LIBERO_ZONE];
|
|
377
|
+
const starterSlotIds = new Set([model.lineup[service_1.CourtPosition.LEFT_FRONT], model.lineup[service_1.CourtPosition.MIDDLE_FRONT],
|
|
378
|
+
model.lineup[service_1.CourtPosition.RIGHT_FRONT], model.lineup[service_1.CourtPosition.LEFT_BACK],
|
|
379
|
+
model.lineup[service_1.CourtPosition.MIDDLE_BACK], model.lineup[service_1.CourtPosition.RIGHT_BACK]]);
|
|
380
|
+
const reserveOrL2 = (id) => (id != null && !lineupIds.has(id)) ? id : undefined;
|
|
381
|
+
const preMatchReplacementId = liberoZoneId != null ? reserveOrL2(li.preMatchReplacementId) : undefined;
|
|
382
|
+
const secondLiberoBackfillId = (preMatchReplacementId != null && preMatchReplacementId === validSecondLibero)
|
|
383
|
+
? (() => { const id = reserveOrL2(li.secondLiberoBackfillId); return id != null && id !== validSecondLibero ? id : undefined; })()
|
|
384
|
+
: undefined;
|
|
385
|
+
const designateEligible = li.inMatchDesignateId != null && !starterSlotIds.has(li.inMatchDesignateId) &&
|
|
386
|
+
li.inMatchDesignateId !== liberoZoneId && li.inMatchDesignateId !== validSecondLibero;
|
|
387
|
+
const inMatchDesignateId = designateEligible ? li.inMatchDesignateId : undefined;
|
|
388
|
+
if (preMatchReplacementId == null && secondLiberoBackfillId == null && inMatchDesignateId == null)
|
|
389
|
+
return undefined;
|
|
390
|
+
return { preMatchReplacementId, secondLiberoBackfillId, inMatchDesignateId };
|
|
328
391
|
})()
|
|
329
392
|
};
|
|
330
393
|
}
|
|
@@ -360,6 +423,7 @@ function apiTacticsConfigToAttributes(config, teamId) {
|
|
|
360
423
|
system_sets: config.systemSets,
|
|
361
424
|
offensive_preference_sets: config.offensivePreferenceSets,
|
|
362
425
|
replace_knocked_immediately: config.replaceKnockedImmediately,
|
|
363
|
-
injury_replacements: config.injuryReplacements
|
|
426
|
+
injury_replacements: config.injuryReplacements,
|
|
427
|
+
libero_injury: config.liberoInjury
|
|
364
428
|
};
|
|
365
429
|
}
|
|
@@ -139,3 +139,47 @@ function makeTactics(designatedSubs) {
|
|
|
139
139
|
(0, globals_1.expect)(back.offensivePreferenceSets).toBeUndefined();
|
|
140
140
|
});
|
|
141
141
|
});
|
|
142
|
+
(0, globals_1.describe)('libero injuries — service <-> row round-trip + lenient heal', () => {
|
|
143
|
+
const country = (0, test_helpers_1.makeCountry)();
|
|
144
|
+
const p1 = (0, test_helpers_1.makePlayer)(country);
|
|
145
|
+
const p2 = (0, test_helpers_1.makePlayer)(country);
|
|
146
|
+
const p3 = (0, test_helpers_1.makePlayer)(country);
|
|
147
|
+
const p4 = (0, test_helpers_1.makePlayer)(country);
|
|
148
|
+
const p5 = (0, test_helpers_1.makePlayer)(country);
|
|
149
|
+
const p6 = (0, test_helpers_1.makePlayer)(country);
|
|
150
|
+
const libero = (0, test_helpers_1.makePlayer)(country);
|
|
151
|
+
const l2 = (0, test_helpers_1.makePlayer)(country);
|
|
152
|
+
const reserveA = (0, test_helpers_1.makePlayer)(country);
|
|
153
|
+
const reserveB = (0, test_helpers_1.makePlayer)(country);
|
|
154
|
+
const roster = [p1, p2, p3, p4, p5, p6, libero, l2, reserveA, reserveB];
|
|
155
|
+
const tactics = service_1.Tactics.create({
|
|
156
|
+
lineup: { 4: p4, 3: p3, 2: p2, 5: p5, 6: p6, 1: p1, 0: libero, bench: [] },
|
|
157
|
+
liberoReplacements: [],
|
|
158
|
+
secondLibero: l2,
|
|
159
|
+
liberoInjury: { preMatchReplacement: l2, secondLiberoBackfill: reserveA, inMatchDesignate: reserveB }
|
|
160
|
+
});
|
|
161
|
+
(0, globals_1.it)('writes libero_injury as id-based jsonb', () => {
|
|
162
|
+
const attrs = (0, tactics_1.transformFromTactics)(tactics, 'team-1');
|
|
163
|
+
(0, globals_1.expect)(attrs.libero_injury).toEqual({
|
|
164
|
+
preMatchReplacementId: l2.id,
|
|
165
|
+
secondLiberoBackfillId: reserveA.id,
|
|
166
|
+
inMatchDesignateId: reserveB.id
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
(0, globals_1.it)('resolves the stored libero_injury ids back to roster players', () => {
|
|
170
|
+
const attrs = (0, tactics_1.transformFromTactics)(tactics, 'team-1');
|
|
171
|
+
const back = (0, tactics_1.transformToTactics)(attrs, roster);
|
|
172
|
+
(0, globals_1.expect)(back.liberoInjury?.preMatchReplacement?.id).toBe(l2.id);
|
|
173
|
+
(0, globals_1.expect)(back.liberoInjury?.secondLiberoBackfill?.id).toBe(reserveA.id);
|
|
174
|
+
(0, globals_1.expect)(back.liberoInjury?.inMatchDesignate?.id).toBe(reserveB.id);
|
|
175
|
+
});
|
|
176
|
+
(0, globals_1.it)('drops a stale pre-match replacement that is now a court starter (lenient heal, no crash)', () => {
|
|
177
|
+
const attrs = (0, tactics_1.transformFromTactics)(tactics, 'team-1');
|
|
178
|
+
attrs.libero_injury.preMatchReplacementId = p2.id;
|
|
179
|
+
attrs.libero_injury.secondLiberoBackfillId = undefined;
|
|
180
|
+
const back = (0, tactics_1.transformToTactics)(attrs, roster);
|
|
181
|
+
(0, globals_1.expect)(back.liberoInjury?.preMatchReplacement).toBeUndefined();
|
|
182
|
+
(0, globals_1.expect)(back.liberoInjury?.secondLiberoBackfill).toBeUndefined();
|
|
183
|
+
(0, globals_1.expect)(back.liberoInjury?.inMatchDesignate?.id).toBe(reserveB.id);
|
|
184
|
+
});
|
|
185
|
+
});
|
|
@@ -28,3 +28,4 @@ __exportStar(require("./lineup-function"), exports);
|
|
|
28
28
|
__exportStar(require("./base-position"), exports);
|
|
29
29
|
__exportStar(require("./offensive-preference"), exports);
|
|
30
30
|
__exportStar(require("./injury-replacement"), exports);
|
|
31
|
+
__exportStar(require("./libero-injury"), exports);
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { EnergyBand } from './energy-band';
|
|
2
|
-
|
|
2
|
+
import { ConditionLogic, PinchCondition } from './pinch-condition';
|
|
3
|
+
export type LiberoSubMode = 'NEVER' | 'FATIGUE' | 'ALWAYS' | 'CONDITIONS';
|
|
3
4
|
export interface LiberoSetSubConfig {
|
|
4
5
|
readonly mode: LiberoSubMode;
|
|
5
6
|
readonly fatigueBand?: EnergyBand;
|
|
7
|
+
readonly conditions?: PinchCondition[];
|
|
8
|
+
readonly conditionLogic?: ConditionLogic;
|
|
6
9
|
}
|
|
7
10
|
export interface LiberoSubConfig extends LiberoSetSubConfig {
|
|
8
11
|
readonly sets?: LiberoSetSubConfig[];
|
|
@@ -6,7 +6,12 @@ export declare enum PinchConditionType {
|
|
|
6
6
|
AFTER_ROTATIONS = "AFTER_ROTATIONS",// from the team's Nth serve turn in the set onward
|
|
7
7
|
FROM_SET = "FROM_SET",// only set N or later
|
|
8
8
|
MIN_OWN_SCORE = "MIN_OWN_SCORE",// only once own score >= N
|
|
9
|
-
MIN_OPPONENT_SCORE = "MIN_OPPONENT_SCORE"
|
|
9
|
+
MIN_OPPONENT_SCORE = "MIN_OPPONENT_SCORE",// only once opponent score >= N
|
|
10
|
+
PHASE = "PHASE"
|
|
11
|
+
}
|
|
12
|
+
export declare enum MatchPhase {
|
|
13
|
+
SERVING = "SERVING",
|
|
14
|
+
RECEIVING = "RECEIVING"
|
|
10
15
|
}
|
|
11
16
|
export declare enum OpponentRelation {
|
|
12
17
|
AHEAD = "AHEAD",
|
|
@@ -50,7 +55,11 @@ export interface MinOpponentScoreCondition {
|
|
|
50
55
|
readonly type: PinchConditionType.MIN_OPPONENT_SCORE;
|
|
51
56
|
readonly score: number;
|
|
52
57
|
}
|
|
53
|
-
export
|
|
58
|
+
export interface PhaseCondition {
|
|
59
|
+
readonly type: PinchConditionType.PHASE;
|
|
60
|
+
readonly phase: MatchPhase;
|
|
61
|
+
}
|
|
62
|
+
export type PinchCondition = AsapCondition | TeamSetPointCondition | OpponentSetPointCondition | ScoreDiffCondition | AfterRotationsCondition | FromSetCondition | MinOwnScoreCondition | MinOpponentScoreCondition | PhaseCondition;
|
|
54
63
|
export type ConditionLogic = 'ALL' | 'ANY';
|
|
55
64
|
export interface PinchSetState {
|
|
56
65
|
readonly ownScore: number;
|
|
@@ -58,4 +67,5 @@ export interface PinchSetState {
|
|
|
58
67
|
readonly setTarget: number;
|
|
59
68
|
readonly setNumber: number;
|
|
60
69
|
readonly ownServeTurns: number;
|
|
70
|
+
readonly phase: MatchPhase;
|
|
61
71
|
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// wins back the serve, out the moment the serve is lost). Each condition is evaluated against the live set
|
|
4
4
|
// state; a pinch entry combines them with ALL (every condition must hold) or ANY (one is enough).
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.ScoreDirection = exports.OpponentRelation = exports.PinchConditionType = void 0;
|
|
6
|
+
exports.ScoreDirection = exports.OpponentRelation = exports.MatchPhase = exports.PinchConditionType = void 0;
|
|
7
7
|
var PinchConditionType;
|
|
8
8
|
(function (PinchConditionType) {
|
|
9
9
|
PinchConditionType["ASAP"] = "ASAP";
|
|
@@ -13,8 +13,16 @@ var PinchConditionType;
|
|
|
13
13
|
PinchConditionType["AFTER_ROTATIONS"] = "AFTER_ROTATIONS";
|
|
14
14
|
PinchConditionType["FROM_SET"] = "FROM_SET";
|
|
15
15
|
PinchConditionType["MIN_OWN_SCORE"] = "MIN_OWN_SCORE";
|
|
16
|
-
PinchConditionType["MIN_OPPONENT_SCORE"] = "MIN_OPPONENT_SCORE";
|
|
16
|
+
PinchConditionType["MIN_OPPONENT_SCORE"] = "MIN_OPPONENT_SCORE";
|
|
17
|
+
PinchConditionType["PHASE"] = "PHASE"; // the team is serving or receiving this rally (used by the libero deployment rule)
|
|
17
18
|
})(PinchConditionType || (exports.PinchConditionType = PinchConditionType = {}));
|
|
19
|
+
// Which side of the rally the team is on. Known at each dead ball: the serving team is SERVING, the other
|
|
20
|
+
// RECEIVING. Consumed by the PHASE condition (libero deployment); pinch servers always evaluate while SERVING.
|
|
21
|
+
var MatchPhase;
|
|
22
|
+
(function (MatchPhase) {
|
|
23
|
+
MatchPhase["SERVING"] = "SERVING";
|
|
24
|
+
MatchPhase["RECEIVING"] = "RECEIVING";
|
|
25
|
+
})(MatchPhase || (exports.MatchPhase = MatchPhase = {}));
|
|
18
26
|
var OpponentRelation;
|
|
19
27
|
(function (OpponentRelation) {
|
|
20
28
|
OpponentRelation["AHEAD"] = "AHEAD";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { Player } from '../../player';
|
|
3
3
|
import { EnergyBand } from '../energy-band';
|
|
4
|
-
import { OpponentRelation, PinchConditionType, ScoreDirection } from '../pinch-condition';
|
|
4
|
+
import { MatchPhase, OpponentRelation, PinchConditionType, ScoreDirection } from '../pinch-condition';
|
|
5
5
|
export declare const SubBandSchema: z.ZodUnion<readonly [z.ZodEnum<typeof EnergyBand>, z.ZodLiteral<"NEVER">]>;
|
|
6
6
|
export declare const PinchConditionSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
7
7
|
type: z.ZodLiteral<PinchConditionType.ASAP>;
|
|
@@ -28,6 +28,9 @@ export declare const PinchConditionSchema: z.ZodDiscriminatedUnion<[z.ZodObject<
|
|
|
28
28
|
}, z.core.$strip>, z.ZodObject<{
|
|
29
29
|
type: z.ZodLiteral<PinchConditionType.MIN_OPPONENT_SCORE>;
|
|
30
30
|
score: z.ZodNumber;
|
|
31
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
32
|
+
type: z.ZodLiteral<PinchConditionType.PHASE>;
|
|
33
|
+
phase: z.ZodEnum<typeof MatchPhase>;
|
|
31
34
|
}, z.core.$strip>], "type">;
|
|
32
35
|
export declare const ConditionLogicSchema: z.ZodUnion<readonly [z.ZodLiteral<"ALL">, z.ZodLiteral<"ANY">]>;
|
|
33
36
|
export declare const SubModeSchema: z.ZodEnum<{
|
|
@@ -69,6 +72,9 @@ export declare const SetSubConfigSchema: z.ZodObject<{
|
|
|
69
72
|
}, z.core.$strip>, z.ZodObject<{
|
|
70
73
|
type: z.ZodLiteral<PinchConditionType.MIN_OPPONENT_SCORE>;
|
|
71
74
|
score: z.ZodNumber;
|
|
75
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
76
|
+
type: z.ZodLiteral<PinchConditionType.PHASE>;
|
|
77
|
+
phase: z.ZodEnum<typeof MatchPhase>;
|
|
72
78
|
}, z.core.$strip>], "type">>>;
|
|
73
79
|
conditionLogic: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"ALL">, z.ZodLiteral<"ANY">]>>;
|
|
74
80
|
}, z.core.$strip>;
|
|
@@ -107,6 +113,9 @@ export declare const DesignatedSubSchema: z.ZodObject<{
|
|
|
107
113
|
}, z.core.$strip>, z.ZodObject<{
|
|
108
114
|
type: z.ZodLiteral<PinchConditionType.MIN_OPPONENT_SCORE>;
|
|
109
115
|
score: z.ZodNumber;
|
|
116
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
117
|
+
type: z.ZodLiteral<PinchConditionType.PHASE>;
|
|
118
|
+
phase: z.ZodEnum<typeof MatchPhase>;
|
|
110
119
|
}, z.core.$strip>], "type">>>;
|
|
111
120
|
conditionLogic: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"ALL">, z.ZodLiteral<"ANY">]>>;
|
|
112
121
|
}, z.core.$strip>>>;
|
|
@@ -143,6 +152,9 @@ export declare const DesignatedSubSchema: z.ZodObject<{
|
|
|
143
152
|
}, z.core.$strip>, z.ZodObject<{
|
|
144
153
|
type: z.ZodLiteral<PinchConditionType.MIN_OPPONENT_SCORE>;
|
|
145
154
|
score: z.ZodNumber;
|
|
155
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
156
|
+
type: z.ZodLiteral<PinchConditionType.PHASE>;
|
|
157
|
+
phase: z.ZodEnum<typeof MatchPhase>;
|
|
146
158
|
}, z.core.$strip>], "type">>>;
|
|
147
159
|
conditionLogic: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"ALL">, z.ZodLiteral<"ANY">]>>;
|
|
148
160
|
starter: z.ZodCustom<Player, Player>;
|
|
@@ -17,7 +17,9 @@ exports.PinchConditionSchema = zod_1.z.discriminatedUnion('type', [
|
|
|
17
17
|
zod_1.z.object({ type: zod_1.z.literal(pinch_condition_1.PinchConditionType.AFTER_ROTATIONS), rotations: zod_1.z.number().int().min(1).max(6) }),
|
|
18
18
|
zod_1.z.object({ type: zod_1.z.literal(pinch_condition_1.PinchConditionType.FROM_SET), set: zod_1.z.number().int().min(1).max(5) }),
|
|
19
19
|
zod_1.z.object({ type: zod_1.z.literal(pinch_condition_1.PinchConditionType.MIN_OWN_SCORE), score: zod_1.z.number().int().min(0).max(40) }),
|
|
20
|
-
zod_1.z.object({ type: zod_1.z.literal(pinch_condition_1.PinchConditionType.MIN_OPPONENT_SCORE), score: zod_1.z.number().int().min(0).max(40) })
|
|
20
|
+
zod_1.z.object({ type: zod_1.z.literal(pinch_condition_1.PinchConditionType.MIN_OPPONENT_SCORE), score: zod_1.z.number().int().min(0).max(40) }),
|
|
21
|
+
// PHASE is used by the libero deployment rule (which reuses this schema); pinch servers never offer it.
|
|
22
|
+
zod_1.z.object({ type: zod_1.z.literal(pinch_condition_1.PinchConditionType.PHASE), phase: zod_1.z.nativeEnum(pinch_condition_1.MatchPhase) })
|
|
21
23
|
]);
|
|
22
24
|
exports.ConditionLogicSchema = zod_1.z.union([zod_1.z.literal('ALL'), zod_1.z.literal('ANY')]);
|
|
23
25
|
exports.SubModeSchema = zod_1.z.enum(['FATIGUE', 'PINCH', 'NEVER']);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const globals_1 = require("@jest/globals");
|
|
4
|
+
const tactics_z_1 = require("./tactics.z");
|
|
5
|
+
const test_helpers_1 = require("../../test-helpers");
|
|
6
|
+
(0, globals_1.describe)('TacticsInputSchema — liberoInjury (owner 2026-07-06)', () => {
|
|
7
|
+
const country = (0, test_helpers_1.makeCountry)();
|
|
8
|
+
const p1 = (0, test_helpers_1.makePlayer)(country);
|
|
9
|
+
const p2 = (0, test_helpers_1.makePlayer)(country);
|
|
10
|
+
const p3 = (0, test_helpers_1.makePlayer)(country);
|
|
11
|
+
const p4 = (0, test_helpers_1.makePlayer)(country);
|
|
12
|
+
const p5 = (0, test_helpers_1.makePlayer)(country);
|
|
13
|
+
const p6 = (0, test_helpers_1.makePlayer)(country);
|
|
14
|
+
const benchA = (0, test_helpers_1.makePlayer)(country);
|
|
15
|
+
const benchB = (0, test_helpers_1.makePlayer)(country);
|
|
16
|
+
const libero = (0, test_helpers_1.makePlayer)(country);
|
|
17
|
+
const l2 = (0, test_helpers_1.makePlayer)(country); // second libero (a reserve)
|
|
18
|
+
const reserveA = (0, test_helpers_1.makePlayer)(country);
|
|
19
|
+
const reserveB = (0, test_helpers_1.makePlayer)(country);
|
|
20
|
+
function baseInput(overrides = {}) {
|
|
21
|
+
return {
|
|
22
|
+
lineup: { 4: p4, 3: p3, 2: p2, 5: p5, 6: p6, 1: p1, 0: libero, bench: [benchA, benchB] },
|
|
23
|
+
liberoReplacements: [],
|
|
24
|
+
secondLibero: l2,
|
|
25
|
+
...overrides
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
const hasIssue = (res, message) => !res.success && res.error.issues.some(i => i.message === message);
|
|
29
|
+
(0, globals_1.it)('accepts no liberoInjury', () => {
|
|
30
|
+
(0, globals_1.expect)(tactics_z_1.TacticsInputSchema.safeParse(baseInput()).success).toBe(true);
|
|
31
|
+
});
|
|
32
|
+
(0, globals_1.it)('accepts a reserve as the pre-match libero replacement', () => {
|
|
33
|
+
(0, globals_1.expect)(tactics_z_1.TacticsInputSchema.safeParse(baseInput({ liberoInjury: { preMatchReplacement: reserveA } })).success).toBe(true);
|
|
34
|
+
});
|
|
35
|
+
(0, globals_1.it)('accepts the L2 as the replacement with a reserve backfill (new L2)', () => {
|
|
36
|
+
(0, globals_1.expect)(tactics_z_1.TacticsInputSchema.safeParse(baseInput({ liberoInjury: { preMatchReplacement: l2, secondLiberoBackfill: reserveA } })).success).toBe(true);
|
|
37
|
+
});
|
|
38
|
+
(0, globals_1.it)('rejects a starter / the libero / a bench player as the pre-match replacement', () => {
|
|
39
|
+
for (const bad of [p2, libero, benchA]) {
|
|
40
|
+
const res = tactics_z_1.TacticsInputSchema.safeParse(baseInput({ liberoInjury: { preMatchReplacement: bad } }));
|
|
41
|
+
(0, globals_1.expect)(hasIssue(res, 'LIBERO_INJURY_REPLACEMENT_MUST_BE_RESERVE_OR_L2')).toBe(true);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
(0, globals_1.it)('rejects a pre-match replacement when there is no starting libero', () => {
|
|
45
|
+
const res = tactics_z_1.TacticsInputSchema.safeParse(baseInput({
|
|
46
|
+
lineup: { 4: p4, 3: p3, 2: p2, 5: p5, 6: p6, 1: p1, bench: [benchA, benchB] },
|
|
47
|
+
secondLibero: undefined,
|
|
48
|
+
liberoInjury: { preMatchReplacement: reserveA }
|
|
49
|
+
}));
|
|
50
|
+
(0, globals_1.expect)(hasIssue(res, 'LIBERO_INJURY_REQUIRES_LIBERO')).toBe(true);
|
|
51
|
+
});
|
|
52
|
+
(0, globals_1.it)('rejects a backfill when the replacement is not the L2', () => {
|
|
53
|
+
const res = tactics_z_1.TacticsInputSchema.safeParse(baseInput({ liberoInjury: { preMatchReplacement: reserveA, secondLiberoBackfill: reserveB } }));
|
|
54
|
+
(0, globals_1.expect)(hasIssue(res, 'LIBERO_BACKFILL_REQUIRES_L2_REPLACEMENT')).toBe(true);
|
|
55
|
+
});
|
|
56
|
+
(0, globals_1.it)('rejects a non-reserve backfill (bench player) even when the L2 is the replacement', () => {
|
|
57
|
+
const res = tactics_z_1.TacticsInputSchema.safeParse(baseInput({ liberoInjury: { preMatchReplacement: l2, secondLiberoBackfill: benchA } }));
|
|
58
|
+
(0, globals_1.expect)(hasIssue(res, 'LIBERO_BACKFILL_MUST_BE_RESERVE')).toBe(true);
|
|
59
|
+
});
|
|
60
|
+
(0, globals_1.it)('accepts a bench or reserve player as the in-match designate', () => {
|
|
61
|
+
for (const ok of [benchA, reserveA]) {
|
|
62
|
+
(0, globals_1.expect)(tactics_z_1.TacticsInputSchema.safeParse(baseInput({ liberoInjury: { inMatchDesignate: ok } })).success).toBe(true);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
(0, globals_1.it)('rejects a starter / the libero / the L2 as the in-match designate', () => {
|
|
66
|
+
for (const bad of [p2, libero, l2]) {
|
|
67
|
+
const res = tactics_z_1.TacticsInputSchema.safeParse(baseInput({ liberoInjury: { inMatchDesignate: bad } }));
|
|
68
|
+
(0, globals_1.expect)(hasIssue(res, 'LIBERO_DESIGNATE_MUST_BE_BENCH_OR_RESERVE')).toBe(true);
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
});
|
|
@@ -4,14 +4,46 @@ export declare const LiberoSubModeSchema: z.ZodEnum<{
|
|
|
4
4
|
NEVER: "NEVER";
|
|
5
5
|
FATIGUE: "FATIGUE";
|
|
6
6
|
ALWAYS: "ALWAYS";
|
|
7
|
+
CONDITIONS: "CONDITIONS";
|
|
7
8
|
}>;
|
|
8
9
|
export declare const LiberoSetSubConfigSchema: z.ZodObject<{
|
|
9
10
|
mode: z.ZodEnum<{
|
|
10
11
|
NEVER: "NEVER";
|
|
11
12
|
FATIGUE: "FATIGUE";
|
|
12
13
|
ALWAYS: "ALWAYS";
|
|
14
|
+
CONDITIONS: "CONDITIONS";
|
|
13
15
|
}>;
|
|
14
16
|
fatigueBand: z.ZodOptional<z.ZodEnum<typeof EnergyBand>>;
|
|
17
|
+
conditions: z.ZodOptional<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
18
|
+
type: z.ZodLiteral<import("..").PinchConditionType.ASAP>;
|
|
19
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
20
|
+
type: z.ZodLiteral<import("..").PinchConditionType.TEAM_SET_POINT>;
|
|
21
|
+
margin: z.ZodNumber;
|
|
22
|
+
opponent: z.ZodEnum<typeof import("..").OpponentRelation>;
|
|
23
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
24
|
+
type: z.ZodLiteral<import("..").PinchConditionType.OPPONENT_SET_POINT>;
|
|
25
|
+
margin: z.ZodNumber;
|
|
26
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
27
|
+
type: z.ZodLiteral<import("..").PinchConditionType.SCORE_DIFF>;
|
|
28
|
+
direction: z.ZodEnum<typeof import("..").ScoreDirection>;
|
|
29
|
+
points: z.ZodNumber;
|
|
30
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
31
|
+
type: z.ZodLiteral<import("..").PinchConditionType.AFTER_ROTATIONS>;
|
|
32
|
+
rotations: z.ZodNumber;
|
|
33
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
34
|
+
type: z.ZodLiteral<import("..").PinchConditionType.FROM_SET>;
|
|
35
|
+
set: z.ZodNumber;
|
|
36
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
37
|
+
type: z.ZodLiteral<import("..").PinchConditionType.MIN_OWN_SCORE>;
|
|
38
|
+
score: z.ZodNumber;
|
|
39
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
40
|
+
type: z.ZodLiteral<import("..").PinchConditionType.MIN_OPPONENT_SCORE>;
|
|
41
|
+
score: z.ZodNumber;
|
|
42
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
43
|
+
type: z.ZodLiteral<import("..").PinchConditionType.PHASE>;
|
|
44
|
+
phase: z.ZodEnum<typeof import("..").MatchPhase>;
|
|
45
|
+
}, z.core.$strip>], "type">>>;
|
|
46
|
+
conditionLogic: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"ALL">, z.ZodLiteral<"ANY">]>>;
|
|
15
47
|
}, z.core.$strip>;
|
|
16
48
|
export declare const LiberoSubConfigSchema: z.ZodObject<{
|
|
17
49
|
sets: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
@@ -19,13 +51,75 @@ export declare const LiberoSubConfigSchema: z.ZodObject<{
|
|
|
19
51
|
NEVER: "NEVER";
|
|
20
52
|
FATIGUE: "FATIGUE";
|
|
21
53
|
ALWAYS: "ALWAYS";
|
|
54
|
+
CONDITIONS: "CONDITIONS";
|
|
22
55
|
}>;
|
|
23
56
|
fatigueBand: z.ZodOptional<z.ZodEnum<typeof EnergyBand>>;
|
|
57
|
+
conditions: z.ZodOptional<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
58
|
+
type: z.ZodLiteral<import("..").PinchConditionType.ASAP>;
|
|
59
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
60
|
+
type: z.ZodLiteral<import("..").PinchConditionType.TEAM_SET_POINT>;
|
|
61
|
+
margin: z.ZodNumber;
|
|
62
|
+
opponent: z.ZodEnum<typeof import("..").OpponentRelation>;
|
|
63
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
64
|
+
type: z.ZodLiteral<import("..").PinchConditionType.OPPONENT_SET_POINT>;
|
|
65
|
+
margin: z.ZodNumber;
|
|
66
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
67
|
+
type: z.ZodLiteral<import("..").PinchConditionType.SCORE_DIFF>;
|
|
68
|
+
direction: z.ZodEnum<typeof import("..").ScoreDirection>;
|
|
69
|
+
points: z.ZodNumber;
|
|
70
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
71
|
+
type: z.ZodLiteral<import("..").PinchConditionType.AFTER_ROTATIONS>;
|
|
72
|
+
rotations: z.ZodNumber;
|
|
73
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
74
|
+
type: z.ZodLiteral<import("..").PinchConditionType.FROM_SET>;
|
|
75
|
+
set: z.ZodNumber;
|
|
76
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
77
|
+
type: z.ZodLiteral<import("..").PinchConditionType.MIN_OWN_SCORE>;
|
|
78
|
+
score: z.ZodNumber;
|
|
79
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
80
|
+
type: z.ZodLiteral<import("..").PinchConditionType.MIN_OPPONENT_SCORE>;
|
|
81
|
+
score: z.ZodNumber;
|
|
82
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
83
|
+
type: z.ZodLiteral<import("..").PinchConditionType.PHASE>;
|
|
84
|
+
phase: z.ZodEnum<typeof import("..").MatchPhase>;
|
|
85
|
+
}, z.core.$strip>], "type">>>;
|
|
86
|
+
conditionLogic: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"ALL">, z.ZodLiteral<"ANY">]>>;
|
|
24
87
|
}, z.core.$strip>>>;
|
|
25
88
|
mode: z.ZodEnum<{
|
|
26
89
|
NEVER: "NEVER";
|
|
27
90
|
FATIGUE: "FATIGUE";
|
|
28
91
|
ALWAYS: "ALWAYS";
|
|
92
|
+
CONDITIONS: "CONDITIONS";
|
|
29
93
|
}>;
|
|
30
94
|
fatigueBand: z.ZodOptional<z.ZodEnum<typeof EnergyBand>>;
|
|
95
|
+
conditions: z.ZodOptional<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
96
|
+
type: z.ZodLiteral<import("..").PinchConditionType.ASAP>;
|
|
97
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
98
|
+
type: z.ZodLiteral<import("..").PinchConditionType.TEAM_SET_POINT>;
|
|
99
|
+
margin: z.ZodNumber;
|
|
100
|
+
opponent: z.ZodEnum<typeof import("..").OpponentRelation>;
|
|
101
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
102
|
+
type: z.ZodLiteral<import("..").PinchConditionType.OPPONENT_SET_POINT>;
|
|
103
|
+
margin: z.ZodNumber;
|
|
104
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
105
|
+
type: z.ZodLiteral<import("..").PinchConditionType.SCORE_DIFF>;
|
|
106
|
+
direction: z.ZodEnum<typeof import("..").ScoreDirection>;
|
|
107
|
+
points: z.ZodNumber;
|
|
108
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
109
|
+
type: z.ZodLiteral<import("..").PinchConditionType.AFTER_ROTATIONS>;
|
|
110
|
+
rotations: z.ZodNumber;
|
|
111
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
112
|
+
type: z.ZodLiteral<import("..").PinchConditionType.FROM_SET>;
|
|
113
|
+
set: z.ZodNumber;
|
|
114
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
115
|
+
type: z.ZodLiteral<import("..").PinchConditionType.MIN_OWN_SCORE>;
|
|
116
|
+
score: z.ZodNumber;
|
|
117
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
118
|
+
type: z.ZodLiteral<import("..").PinchConditionType.MIN_OPPONENT_SCORE>;
|
|
119
|
+
score: z.ZodNumber;
|
|
120
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
121
|
+
type: z.ZodLiteral<import("..").PinchConditionType.PHASE>;
|
|
122
|
+
phase: z.ZodEnum<typeof import("..").MatchPhase>;
|
|
123
|
+
}, z.core.$strip>], "type">>>;
|
|
124
|
+
conditionLogic: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"ALL">, z.ZodLiteral<"ANY">]>>;
|
|
31
125
|
}, z.core.$strip>;
|
|
@@ -3,18 +3,35 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.LiberoSubConfigSchema = exports.LiberoSetSubConfigSchema = exports.LiberoSubModeSchema = void 0;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
5
|
const energy_band_1 = require("../energy-band");
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
//
|
|
9
|
-
//
|
|
6
|
+
const designated_sub_z_1 = require("./designated-sub.z");
|
|
7
|
+
exports.LiberoSubModeSchema = zod_1.z.enum(['NEVER', 'FATIGUE', 'ALWAYS', 'CONDITIONS']);
|
|
8
|
+
// Fields shared by the all-sets config and each per-set config. The swapped-in player is always the dedicated
|
|
9
|
+
// `secondLibero`, so there is no bench to validate; the CONDITIONS mode reuses the pinch-server condition
|
|
10
|
+
// catalog (PinchConditionSchema, which includes the libero-only PHASE condition) + ALL/ANY logic.
|
|
10
11
|
const liberoSetSubConfigShape = {
|
|
11
12
|
mode: exports.LiberoSubModeSchema,
|
|
12
13
|
// fatigue mode only (absent => the team default `substitutionBand`):
|
|
13
|
-
fatigueBand: zod_1.z.nativeEnum(energy_band_1.EnergyBand).optional()
|
|
14
|
+
fatigueBand: zod_1.z.nativeEnum(energy_band_1.EnergyBand).optional(),
|
|
15
|
+
// conditions mode only:
|
|
16
|
+
conditions: zod_1.z.array(designated_sub_z_1.PinchConditionSchema).optional(),
|
|
17
|
+
conditionLogic: designated_sub_z_1.ConditionLogicSchema.optional()
|
|
14
18
|
};
|
|
15
|
-
|
|
19
|
+
// CONDITIONS mode needs at least one condition (mirrors the designated-sub pinch refine).
|
|
20
|
+
function refineConditions(data, ctx) {
|
|
21
|
+
if (data.mode !== 'CONDITIONS')
|
|
22
|
+
return;
|
|
23
|
+
if (data.conditions == null || data.conditions.length === 0) {
|
|
24
|
+
ctx.addIssue({ code: 'custom', message: 'LIBERO_CONDITIONS_REQUIRE_A_CONDITION', path: ['conditions'] });
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
exports.LiberoSetSubConfigSchema = zod_1.z.object(liberoSetSubConfigShape).superRefine(refineConditions);
|
|
16
28
|
exports.LiberoSubConfigSchema = zod_1.z.object({
|
|
17
29
|
...liberoSetSubConfigShape,
|
|
18
30
|
// Optional per-set overrides (index 0 = set 1 ... index 4 = set 5); absent => the flat config for all sets.
|
|
19
31
|
sets: zod_1.z.array(exports.LiberoSetSubConfigSchema).max(5).optional()
|
|
32
|
+
}).superRefine((data, ctx) => {
|
|
33
|
+
// The flat config is the fallback for any set a partial `sets` array doesn't cover, so validate it whenever
|
|
34
|
+
// `sets` is absent or covers fewer than 5 sets (each present per-set config is validated by its own schema).
|
|
35
|
+
if (data.sets == null || data.sets.length < 5)
|
|
36
|
+
refineConditions(data, ctx);
|
|
20
37
|
});
|