volleyballsimtypes 0.0.476 → 0.0.478
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 +9 -1
- package/dist/cjs/src/data/models/auth-session.d.ts +5 -1
- package/dist/cjs/src/data/models/auth-session.js +8 -0
- package/dist/cjs/src/data/models/tactics.d.ts +9 -1
- package/dist/cjs/src/data/transformers/tactics.js +33 -3
- package/dist/cjs/src/data/transformers/tactics.test.js +31 -0
- package/dist/cjs/src/service/team/designated-sub.d.ts +5 -0
- package/dist/cjs/src/service/team/pinch-condition.d.ts +7 -0
- package/dist/cjs/src/service/team/pinch-condition.js +10 -1
- package/dist/cjs/src/service/team/schemas/designated-sub.z.d.ts +131 -1
- package/dist/cjs/src/service/team/schemas/designated-sub.z.js +20 -6
- package/dist/cjs/src/service/team/schemas/designated-sub.z.test.js +83 -0
- package/dist/cjs/src/service/team/schemas/libero-sub.z.d.ts +13 -4
- package/dist/cjs/src/service/team/schemas/tactics.z.d.ts +90 -2
- package/dist/cjs/src/service/team/schemas/team.z.d.ts +90 -2
- package/dist/esm/src/api/index.d.ts +9 -1
- package/dist/esm/src/data/models/auth-session.d.ts +5 -1
- package/dist/esm/src/data/models/auth-session.js +8 -0
- package/dist/esm/src/data/models/tactics.d.ts +9 -1
- package/dist/esm/src/data/transformers/tactics.js +33 -3
- package/dist/esm/src/data/transformers/tactics.test.js +31 -0
- package/dist/esm/src/service/team/designated-sub.d.ts +5 -0
- package/dist/esm/src/service/team/pinch-condition.d.ts +7 -0
- package/dist/esm/src/service/team/pinch-condition.js +9 -0
- package/dist/esm/src/service/team/schemas/designated-sub.z.d.ts +131 -1
- package/dist/esm/src/service/team/schemas/designated-sub.z.js +20 -6
- package/dist/esm/src/service/team/schemas/designated-sub.z.test.js +84 -1
- package/dist/esm/src/service/team/schemas/libero-sub.z.d.ts +13 -4
- package/dist/esm/src/service/team/schemas/tactics.z.d.ts +90 -2
- package/dist/esm/src/service/team/schemas/team.z.d.ts +90 -2
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as Sequelize from 'sequelize';
|
|
2
2
|
import { Model, Optional } from 'sequelize';
|
|
3
3
|
import { PlayerId, TeamId, TeamModel } from '.';
|
|
4
|
-
import { ConditionLogic, CourtPosition, EnergyBand, LiberoSubMode, PinchCondition, RotationSystemEnum, SubBand, SubMode } from '../../service';
|
|
4
|
+
import { ConditionLogic, CourtPosition, EnergyBand, LiberoSubMode, PinchCondition, RotationSystemEnum, SubBackMode, SubBand, SubMode } from '../../service';
|
|
5
5
|
export interface TacticsLineupAttributes {
|
|
6
6
|
[CourtPosition.LIBERO_ZONE]?: PlayerId;
|
|
7
7
|
[CourtPosition.LEFT_BACK]: PlayerId;
|
|
@@ -19,6 +19,10 @@ export interface SetSubConfigAttributes {
|
|
|
19
19
|
benchFatigueBand?: EnergyBand;
|
|
20
20
|
conditions?: PinchCondition[];
|
|
21
21
|
conditionLogic?: ConditionLogic;
|
|
22
|
+
pinchServer?: boolean;
|
|
23
|
+
subBackMode?: SubBackMode;
|
|
24
|
+
subBackConditions?: PinchCondition[];
|
|
25
|
+
subBackConditionLogic?: ConditionLogic;
|
|
22
26
|
}
|
|
23
27
|
export interface DesignatedSubAttributes {
|
|
24
28
|
starterId: PlayerId;
|
|
@@ -29,6 +33,10 @@ export interface DesignatedSubAttributes {
|
|
|
29
33
|
benchFatigueBand?: EnergyBand;
|
|
30
34
|
conditions?: PinchCondition[];
|
|
31
35
|
conditionLogic?: ConditionLogic;
|
|
36
|
+
pinchServer?: boolean;
|
|
37
|
+
subBackMode?: SubBackMode;
|
|
38
|
+
subBackConditions?: PinchCondition[];
|
|
39
|
+
subBackConditionLogic?: ConditionLogic;
|
|
32
40
|
sets?: SetSubConfigAttributes[];
|
|
33
41
|
}
|
|
34
42
|
export interface OffensivePreferenceAttributes {
|
|
@@ -11,6 +11,12 @@ function subModeFromAttributes(d) {
|
|
|
11
11
|
return 'NEVER';
|
|
12
12
|
return 'FATIGUE';
|
|
13
13
|
}
|
|
14
|
+
// pinchServer only applies to PINCH ("Conditions") mode. A LEGACY PINCH row (no flag) defaults to true so
|
|
15
|
+
// existing pinch servers keep serve-and-return behavior; a new conditional sub persists an explicit false. This
|
|
16
|
+
// default must resolve identically on every READ path (both transformToObject and tacticsColumnsToApiDto).
|
|
17
|
+
function effectivePinchServer(mode, pinchServer) {
|
|
18
|
+
return mode === 'PINCH' ? (pinchServer ?? true) : undefined;
|
|
19
|
+
}
|
|
14
20
|
function findPlayer(id, roster) {
|
|
15
21
|
const player = roster.find((p) => p.id === id);
|
|
16
22
|
if (player == null)
|
|
@@ -59,13 +65,21 @@ function transformToAttributes(tactics, teamId) {
|
|
|
59
65
|
benchFatigueBand: ds.benchFatigueBand,
|
|
60
66
|
conditions: ds.conditions,
|
|
61
67
|
conditionLogic: ds.conditionLogic,
|
|
68
|
+
pinchServer: ds.pinchServer,
|
|
69
|
+
subBackMode: ds.subBackMode,
|
|
70
|
+
subBackConditions: ds.subBackConditions,
|
|
71
|
+
subBackConditionLogic: ds.subBackConditionLogic,
|
|
62
72
|
sets: ds.sets?.map(s => ({
|
|
63
73
|
mode: s.mode,
|
|
64
74
|
benchId: s.bench?.id,
|
|
65
75
|
fatigueBand: s.fatigueBand,
|
|
66
76
|
benchFatigueBand: s.benchFatigueBand,
|
|
67
77
|
conditions: s.conditions,
|
|
68
|
-
conditionLogic: s.conditionLogic
|
|
78
|
+
conditionLogic: s.conditionLogic,
|
|
79
|
+
pinchServer: s.pinchServer,
|
|
80
|
+
subBackMode: s.subBackMode,
|
|
81
|
+
subBackConditions: s.subBackConditions,
|
|
82
|
+
subBackConditionLogic: s.subBackConditionLogic
|
|
69
83
|
}))
|
|
70
84
|
})),
|
|
71
85
|
rotation_system: tactics.rotationSystem,
|
|
@@ -149,13 +163,21 @@ function transformToObject(model, roster) {
|
|
|
149
163
|
benchFatigueBand: d.benchFatigueBand,
|
|
150
164
|
conditions: d.conditions,
|
|
151
165
|
conditionLogic: d.conditionLogic,
|
|
166
|
+
pinchServer: effectivePinchServer(subModeFromAttributes(d), d.pinchServer),
|
|
167
|
+
subBackMode: d.subBackMode,
|
|
168
|
+
subBackConditions: d.subBackConditions,
|
|
169
|
+
subBackConditionLogic: d.subBackConditionLogic,
|
|
152
170
|
sets: d.sets?.map(s => ({
|
|
153
171
|
mode: s.mode,
|
|
154
172
|
bench: s.benchId != null ? findPlayer(s.benchId, roster) : undefined,
|
|
155
173
|
fatigueBand: s.fatigueBand,
|
|
156
174
|
benchFatigueBand: s.benchFatigueBand,
|
|
157
175
|
conditions: s.conditions,
|
|
158
|
-
conditionLogic: s.conditionLogic
|
|
176
|
+
conditionLogic: s.conditionLogic,
|
|
177
|
+
pinchServer: effectivePinchServer(s.mode, s.pinchServer),
|
|
178
|
+
subBackMode: s.subBackMode,
|
|
179
|
+
subBackConditions: s.subBackConditions,
|
|
180
|
+
subBackConditionLogic: s.subBackConditionLogic
|
|
159
181
|
}))
|
|
160
182
|
})),
|
|
161
183
|
rotationSystem: model.rotation_system,
|
|
@@ -306,13 +328,21 @@ function tacticsColumnsToApiDto(model) {
|
|
|
306
328
|
benchFatigueBand: d.benchFatigueBand,
|
|
307
329
|
conditions: d.conditions,
|
|
308
330
|
conditionLogic: d.conditionLogic,
|
|
331
|
+
pinchServer: effectivePinchServer(subModeFromAttributes(d), d.pinchServer),
|
|
332
|
+
subBackMode: d.subBackMode,
|
|
333
|
+
subBackConditions: d.subBackConditions,
|
|
334
|
+
subBackConditionLogic: d.subBackConditionLogic,
|
|
309
335
|
sets: d.sets?.map(s => ({
|
|
310
336
|
mode: s.mode,
|
|
311
337
|
benchId: s.benchId,
|
|
312
338
|
fatigueBand: s.fatigueBand,
|
|
313
339
|
benchFatigueBand: s.benchFatigueBand,
|
|
314
340
|
conditions: s.conditions,
|
|
315
|
-
conditionLogic: s.conditionLogic
|
|
341
|
+
conditionLogic: s.conditionLogic,
|
|
342
|
+
pinchServer: effectivePinchServer(s.mode, s.pinchServer),
|
|
343
|
+
subBackMode: s.subBackMode,
|
|
344
|
+
subBackConditions: s.subBackConditions,
|
|
345
|
+
subBackConditionLogic: s.subBackConditionLogic
|
|
316
346
|
}))
|
|
317
347
|
})),
|
|
318
348
|
rotationSystem: model.rotation_system,
|
|
@@ -58,6 +58,37 @@ describe('tacticsColumnsToApiDto()', () => {
|
|
|
58
58
|
expect(dto.designatedSubs[0].fatigueBand).toBe(EnergyBand.WORN);
|
|
59
59
|
expect(dto.designatedSubs[0].benchFatigueBand).toBe(EnergyBand.TIRED);
|
|
60
60
|
});
|
|
61
|
+
it('defaults a legacy PINCH row (no pinchServer flag) to pinchServer true', () => {
|
|
62
|
+
const dto = tacticsColumnsToApiDto(makeTactics([
|
|
63
|
+
{ starterId: 's1', benchId: 'b1', mode: 'PINCH', conditions: [{ type: 'ASAP' }] }
|
|
64
|
+
]));
|
|
65
|
+
expect(dto.designatedSubs[0].pinchServer).toBe(true);
|
|
66
|
+
});
|
|
67
|
+
it('leaves pinchServer undefined for a non-PINCH row', () => {
|
|
68
|
+
const dto = tacticsColumnsToApiDto(makeTactics([
|
|
69
|
+
{ starterId: 's1', benchId: 'b1', mode: 'FATIGUE', fatigueBand: EnergyBand.TIRED }
|
|
70
|
+
]));
|
|
71
|
+
expect(dto.designatedSubs[0].pinchServer).toBeUndefined();
|
|
72
|
+
});
|
|
73
|
+
it('passes a conditional regular sub (pinchServer false + condition sub-back) through unchanged', () => {
|
|
74
|
+
const dto = tacticsColumnsToApiDto(makeTactics([
|
|
75
|
+
{
|
|
76
|
+
starterId: 's1',
|
|
77
|
+
benchId: 'b1',
|
|
78
|
+
mode: 'PINCH',
|
|
79
|
+
conditions: [{ type: 'SCORE_DIFF', direction: 'TRAILING', points: 3 }],
|
|
80
|
+
pinchServer: false,
|
|
81
|
+
subBackMode: 'CONDITIONS',
|
|
82
|
+
subBackConditions: [{ type: 'TEAM_SET_POINT', margin: 2, opponent: 'EITHER' }],
|
|
83
|
+
subBackConditionLogic: 'ANY'
|
|
84
|
+
}
|
|
85
|
+
]));
|
|
86
|
+
const ds = dto.designatedSubs[0];
|
|
87
|
+
expect(ds.pinchServer).toBe(false);
|
|
88
|
+
expect(ds.subBackMode).toBe('CONDITIONS');
|
|
89
|
+
expect(ds.subBackConditions).toEqual([{ type: 'TEAM_SET_POINT', margin: 2, opponent: 'EITHER' }]);
|
|
90
|
+
expect(ds.subBackConditionLogic).toBe('ANY');
|
|
91
|
+
});
|
|
61
92
|
it('drops a second libero that collides with the starting libero (not a reserve)', () => {
|
|
62
93
|
const model = makeTactics([]);
|
|
63
94
|
model.lineup[CourtPosition.LIBERO_ZONE] = 'libero1';
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Player } from '../player';
|
|
2
2
|
import { EnergyBand, SubMode } from './energy-band';
|
|
3
3
|
import { ConditionLogic, PinchCondition } from './pinch-condition';
|
|
4
|
+
export type SubBackMode = 'FATIGUE' | 'CONDITIONS';
|
|
4
5
|
export interface SetSubConfig {
|
|
5
6
|
readonly mode: SubMode;
|
|
6
7
|
readonly bench?: Player;
|
|
@@ -8,6 +9,10 @@ export interface SetSubConfig {
|
|
|
8
9
|
readonly benchFatigueBand?: EnergyBand;
|
|
9
10
|
readonly conditions?: PinchCondition[];
|
|
10
11
|
readonly conditionLogic?: ConditionLogic;
|
|
12
|
+
readonly pinchServer?: boolean;
|
|
13
|
+
readonly subBackMode?: SubBackMode;
|
|
14
|
+
readonly subBackConditions?: PinchCondition[];
|
|
15
|
+
readonly subBackConditionLogic?: ConditionLogic;
|
|
11
16
|
}
|
|
12
17
|
export interface DesignatedSub extends SetSubConfig {
|
|
13
18
|
readonly starter: Player;
|
|
@@ -22,6 +22,10 @@ export declare enum ScoreDirection {
|
|
|
22
22
|
TRAILING = "TRAILING",
|
|
23
23
|
LEADING = "LEADING"
|
|
24
24
|
}
|
|
25
|
+
export declare enum Comparison {
|
|
26
|
+
AT_LEAST = "AT_LEAST",
|
|
27
|
+
AT_MOST = "AT_MOST"
|
|
28
|
+
}
|
|
25
29
|
export interface AsapCondition {
|
|
26
30
|
readonly type: PinchConditionType.ASAP;
|
|
27
31
|
}
|
|
@@ -38,6 +42,7 @@ export interface ScoreDiffCondition {
|
|
|
38
42
|
readonly type: PinchConditionType.SCORE_DIFF;
|
|
39
43
|
readonly direction: ScoreDirection;
|
|
40
44
|
readonly points: number;
|
|
45
|
+
readonly comparison?: Comparison;
|
|
41
46
|
}
|
|
42
47
|
export interface AfterRotationsCondition {
|
|
43
48
|
readonly type: PinchConditionType.AFTER_ROTATIONS;
|
|
@@ -50,10 +55,12 @@ export interface FromSetCondition {
|
|
|
50
55
|
export interface MinOwnScoreCondition {
|
|
51
56
|
readonly type: PinchConditionType.MIN_OWN_SCORE;
|
|
52
57
|
readonly score: number;
|
|
58
|
+
readonly comparison?: Comparison;
|
|
53
59
|
}
|
|
54
60
|
export interface MinOpponentScoreCondition {
|
|
55
61
|
readonly type: PinchConditionType.MIN_OPPONENT_SCORE;
|
|
56
62
|
readonly score: number;
|
|
63
|
+
readonly comparison?: Comparison;
|
|
57
64
|
}
|
|
58
65
|
export interface PhaseCondition {
|
|
59
66
|
readonly type: PinchConditionType.PHASE;
|
|
@@ -31,3 +31,12 @@ export var ScoreDirection;
|
|
|
31
31
|
ScoreDirection["TRAILING"] = "TRAILING";
|
|
32
32
|
ScoreDirection["LEADING"] = "LEADING";
|
|
33
33
|
})(ScoreDirection || (ScoreDirection = {}));
|
|
34
|
+
// Comparison direction for a numeric-threshold condition (SCORE_DIFF / MIN_OWN_SCORE / MIN_OPPONENT_SCORE).
|
|
35
|
+
// AT_LEAST ("Or more", value >= threshold) is the default when absent, so every existing stored condition keeps
|
|
36
|
+
// its `>=` behavior. AT_MOST ("Or less", value <= threshold) lets a rule fire as a value SHRINKS (e.g. a sub-back
|
|
37
|
+
// once "Leading by 2 or less" holds, instead of the always-implied "Leading by 2 or more").
|
|
38
|
+
export var Comparison;
|
|
39
|
+
(function (Comparison) {
|
|
40
|
+
Comparison["AT_LEAST"] = "AT_LEAST";
|
|
41
|
+
Comparison["AT_MOST"] = "AT_MOST";
|
|
42
|
+
})(Comparison || (Comparison = {}));
|
|
@@ -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 { MatchPhase, OpponentRelation, PinchConditionType, ScoreDirection } from '../pinch-condition';
|
|
4
|
+
import { Comparison, 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>;
|
|
@@ -16,6 +16,7 @@ export declare const PinchConditionSchema: z.ZodDiscriminatedUnion<[z.ZodObject<
|
|
|
16
16
|
type: z.ZodLiteral<PinchConditionType.SCORE_DIFF>;
|
|
17
17
|
direction: z.ZodEnum<typeof ScoreDirection>;
|
|
18
18
|
points: z.ZodNumber;
|
|
19
|
+
comparison: z.ZodOptional<z.ZodEnum<typeof Comparison>>;
|
|
19
20
|
}, z.core.$strip>, z.ZodObject<{
|
|
20
21
|
type: z.ZodLiteral<PinchConditionType.AFTER_ROTATIONS>;
|
|
21
22
|
rotations: z.ZodNumber;
|
|
@@ -25,9 +26,11 @@ export declare const PinchConditionSchema: z.ZodDiscriminatedUnion<[z.ZodObject<
|
|
|
25
26
|
}, z.core.$strip>, z.ZodObject<{
|
|
26
27
|
type: z.ZodLiteral<PinchConditionType.MIN_OWN_SCORE>;
|
|
27
28
|
score: z.ZodNumber;
|
|
29
|
+
comparison: z.ZodOptional<z.ZodEnum<typeof Comparison>>;
|
|
28
30
|
}, z.core.$strip>, z.ZodObject<{
|
|
29
31
|
type: z.ZodLiteral<PinchConditionType.MIN_OPPONENT_SCORE>;
|
|
30
32
|
score: z.ZodNumber;
|
|
33
|
+
comparison: z.ZodOptional<z.ZodEnum<typeof Comparison>>;
|
|
31
34
|
}, z.core.$strip>, z.ZodObject<{
|
|
32
35
|
type: z.ZodLiteral<PinchConditionType.PHASE>;
|
|
33
36
|
phase: z.ZodEnum<typeof MatchPhase>;
|
|
@@ -38,6 +41,10 @@ export declare const SubModeSchema: z.ZodEnum<{
|
|
|
38
41
|
FATIGUE: "FATIGUE";
|
|
39
42
|
PINCH: "PINCH";
|
|
40
43
|
}>;
|
|
44
|
+
export declare const SubBackModeSchema: z.ZodEnum<{
|
|
45
|
+
FATIGUE: "FATIGUE";
|
|
46
|
+
CONDITIONS: "CONDITIONS";
|
|
47
|
+
}>;
|
|
41
48
|
export declare const SetSubConfigSchema: z.ZodObject<{
|
|
42
49
|
mode: z.ZodEnum<{
|
|
43
50
|
NEVER: "NEVER";
|
|
@@ -60,6 +67,7 @@ export declare const SetSubConfigSchema: z.ZodObject<{
|
|
|
60
67
|
type: z.ZodLiteral<PinchConditionType.SCORE_DIFF>;
|
|
61
68
|
direction: z.ZodEnum<typeof ScoreDirection>;
|
|
62
69
|
points: z.ZodNumber;
|
|
70
|
+
comparison: z.ZodOptional<z.ZodEnum<typeof Comparison>>;
|
|
63
71
|
}, z.core.$strip>, z.ZodObject<{
|
|
64
72
|
type: z.ZodLiteral<PinchConditionType.AFTER_ROTATIONS>;
|
|
65
73
|
rotations: z.ZodNumber;
|
|
@@ -69,14 +77,54 @@ export declare const SetSubConfigSchema: z.ZodObject<{
|
|
|
69
77
|
}, z.core.$strip>, z.ZodObject<{
|
|
70
78
|
type: z.ZodLiteral<PinchConditionType.MIN_OWN_SCORE>;
|
|
71
79
|
score: z.ZodNumber;
|
|
80
|
+
comparison: z.ZodOptional<z.ZodEnum<typeof Comparison>>;
|
|
72
81
|
}, z.core.$strip>, z.ZodObject<{
|
|
73
82
|
type: z.ZodLiteral<PinchConditionType.MIN_OPPONENT_SCORE>;
|
|
74
83
|
score: z.ZodNumber;
|
|
84
|
+
comparison: z.ZodOptional<z.ZodEnum<typeof Comparison>>;
|
|
75
85
|
}, z.core.$strip>, z.ZodObject<{
|
|
76
86
|
type: z.ZodLiteral<PinchConditionType.PHASE>;
|
|
77
87
|
phase: z.ZodEnum<typeof MatchPhase>;
|
|
78
88
|
}, z.core.$strip>], "type">>>;
|
|
79
89
|
conditionLogic: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"ALL">, z.ZodLiteral<"ANY">]>>;
|
|
90
|
+
pinchServer: z.ZodOptional<z.ZodBoolean>;
|
|
91
|
+
subBackMode: z.ZodOptional<z.ZodEnum<{
|
|
92
|
+
FATIGUE: "FATIGUE";
|
|
93
|
+
CONDITIONS: "CONDITIONS";
|
|
94
|
+
}>>;
|
|
95
|
+
subBackConditions: z.ZodOptional<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
96
|
+
type: z.ZodLiteral<PinchConditionType.ASAP>;
|
|
97
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
98
|
+
type: z.ZodLiteral<PinchConditionType.TEAM_SET_POINT>;
|
|
99
|
+
margin: z.ZodNumber;
|
|
100
|
+
opponent: z.ZodEnum<typeof OpponentRelation>;
|
|
101
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
102
|
+
type: z.ZodLiteral<PinchConditionType.OPPONENT_SET_POINT>;
|
|
103
|
+
margin: z.ZodNumber;
|
|
104
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
105
|
+
type: z.ZodLiteral<PinchConditionType.SCORE_DIFF>;
|
|
106
|
+
direction: z.ZodEnum<typeof ScoreDirection>;
|
|
107
|
+
points: z.ZodNumber;
|
|
108
|
+
comparison: z.ZodOptional<z.ZodEnum<typeof Comparison>>;
|
|
109
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
110
|
+
type: z.ZodLiteral<PinchConditionType.AFTER_ROTATIONS>;
|
|
111
|
+
rotations: z.ZodNumber;
|
|
112
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
113
|
+
type: z.ZodLiteral<PinchConditionType.FROM_SET>;
|
|
114
|
+
set: z.ZodNumber;
|
|
115
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
116
|
+
type: z.ZodLiteral<PinchConditionType.MIN_OWN_SCORE>;
|
|
117
|
+
score: z.ZodNumber;
|
|
118
|
+
comparison: z.ZodOptional<z.ZodEnum<typeof Comparison>>;
|
|
119
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
120
|
+
type: z.ZodLiteral<PinchConditionType.MIN_OPPONENT_SCORE>;
|
|
121
|
+
score: z.ZodNumber;
|
|
122
|
+
comparison: z.ZodOptional<z.ZodEnum<typeof Comparison>>;
|
|
123
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
124
|
+
type: z.ZodLiteral<PinchConditionType.PHASE>;
|
|
125
|
+
phase: z.ZodEnum<typeof MatchPhase>;
|
|
126
|
+
}, z.core.$strip>], "type">>>;
|
|
127
|
+
subBackConditionLogic: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"ALL">, z.ZodLiteral<"ANY">]>>;
|
|
80
128
|
}, z.core.$strip>;
|
|
81
129
|
export declare const DesignatedSubSchema: z.ZodObject<{
|
|
82
130
|
sets: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
@@ -101,6 +149,7 @@ export declare const DesignatedSubSchema: z.ZodObject<{
|
|
|
101
149
|
type: z.ZodLiteral<PinchConditionType.SCORE_DIFF>;
|
|
102
150
|
direction: z.ZodEnum<typeof ScoreDirection>;
|
|
103
151
|
points: z.ZodNumber;
|
|
152
|
+
comparison: z.ZodOptional<z.ZodEnum<typeof Comparison>>;
|
|
104
153
|
}, z.core.$strip>, z.ZodObject<{
|
|
105
154
|
type: z.ZodLiteral<PinchConditionType.AFTER_ROTATIONS>;
|
|
106
155
|
rotations: z.ZodNumber;
|
|
@@ -110,14 +159,54 @@ export declare const DesignatedSubSchema: z.ZodObject<{
|
|
|
110
159
|
}, z.core.$strip>, z.ZodObject<{
|
|
111
160
|
type: z.ZodLiteral<PinchConditionType.MIN_OWN_SCORE>;
|
|
112
161
|
score: z.ZodNumber;
|
|
162
|
+
comparison: z.ZodOptional<z.ZodEnum<typeof Comparison>>;
|
|
113
163
|
}, z.core.$strip>, z.ZodObject<{
|
|
114
164
|
type: z.ZodLiteral<PinchConditionType.MIN_OPPONENT_SCORE>;
|
|
115
165
|
score: z.ZodNumber;
|
|
166
|
+
comparison: z.ZodOptional<z.ZodEnum<typeof Comparison>>;
|
|
116
167
|
}, z.core.$strip>, z.ZodObject<{
|
|
117
168
|
type: z.ZodLiteral<PinchConditionType.PHASE>;
|
|
118
169
|
phase: z.ZodEnum<typeof MatchPhase>;
|
|
119
170
|
}, z.core.$strip>], "type">>>;
|
|
120
171
|
conditionLogic: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"ALL">, z.ZodLiteral<"ANY">]>>;
|
|
172
|
+
pinchServer: z.ZodOptional<z.ZodBoolean>;
|
|
173
|
+
subBackMode: z.ZodOptional<z.ZodEnum<{
|
|
174
|
+
FATIGUE: "FATIGUE";
|
|
175
|
+
CONDITIONS: "CONDITIONS";
|
|
176
|
+
}>>;
|
|
177
|
+
subBackConditions: z.ZodOptional<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
178
|
+
type: z.ZodLiteral<PinchConditionType.ASAP>;
|
|
179
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
180
|
+
type: z.ZodLiteral<PinchConditionType.TEAM_SET_POINT>;
|
|
181
|
+
margin: z.ZodNumber;
|
|
182
|
+
opponent: z.ZodEnum<typeof OpponentRelation>;
|
|
183
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
184
|
+
type: z.ZodLiteral<PinchConditionType.OPPONENT_SET_POINT>;
|
|
185
|
+
margin: z.ZodNumber;
|
|
186
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
187
|
+
type: z.ZodLiteral<PinchConditionType.SCORE_DIFF>;
|
|
188
|
+
direction: z.ZodEnum<typeof ScoreDirection>;
|
|
189
|
+
points: z.ZodNumber;
|
|
190
|
+
comparison: z.ZodOptional<z.ZodEnum<typeof Comparison>>;
|
|
191
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
192
|
+
type: z.ZodLiteral<PinchConditionType.AFTER_ROTATIONS>;
|
|
193
|
+
rotations: z.ZodNumber;
|
|
194
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
195
|
+
type: z.ZodLiteral<PinchConditionType.FROM_SET>;
|
|
196
|
+
set: z.ZodNumber;
|
|
197
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
198
|
+
type: z.ZodLiteral<PinchConditionType.MIN_OWN_SCORE>;
|
|
199
|
+
score: z.ZodNumber;
|
|
200
|
+
comparison: z.ZodOptional<z.ZodEnum<typeof Comparison>>;
|
|
201
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
202
|
+
type: z.ZodLiteral<PinchConditionType.MIN_OPPONENT_SCORE>;
|
|
203
|
+
score: z.ZodNumber;
|
|
204
|
+
comparison: z.ZodOptional<z.ZodEnum<typeof Comparison>>;
|
|
205
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
206
|
+
type: z.ZodLiteral<PinchConditionType.PHASE>;
|
|
207
|
+
phase: z.ZodEnum<typeof MatchPhase>;
|
|
208
|
+
}, z.core.$strip>], "type">>>;
|
|
209
|
+
subBackConditionLogic: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"ALL">, z.ZodLiteral<"ANY">]>>;
|
|
121
210
|
}, z.core.$strip>>>;
|
|
122
211
|
mode: z.ZodEnum<{
|
|
123
212
|
NEVER: "NEVER";
|
|
@@ -140,6 +229,7 @@ export declare const DesignatedSubSchema: z.ZodObject<{
|
|
|
140
229
|
type: z.ZodLiteral<PinchConditionType.SCORE_DIFF>;
|
|
141
230
|
direction: z.ZodEnum<typeof ScoreDirection>;
|
|
142
231
|
points: z.ZodNumber;
|
|
232
|
+
comparison: z.ZodOptional<z.ZodEnum<typeof Comparison>>;
|
|
143
233
|
}, z.core.$strip>, z.ZodObject<{
|
|
144
234
|
type: z.ZodLiteral<PinchConditionType.AFTER_ROTATIONS>;
|
|
145
235
|
rotations: z.ZodNumber;
|
|
@@ -149,13 +239,53 @@ export declare const DesignatedSubSchema: z.ZodObject<{
|
|
|
149
239
|
}, z.core.$strip>, z.ZodObject<{
|
|
150
240
|
type: z.ZodLiteral<PinchConditionType.MIN_OWN_SCORE>;
|
|
151
241
|
score: z.ZodNumber;
|
|
242
|
+
comparison: z.ZodOptional<z.ZodEnum<typeof Comparison>>;
|
|
152
243
|
}, z.core.$strip>, z.ZodObject<{
|
|
153
244
|
type: z.ZodLiteral<PinchConditionType.MIN_OPPONENT_SCORE>;
|
|
154
245
|
score: z.ZodNumber;
|
|
246
|
+
comparison: z.ZodOptional<z.ZodEnum<typeof Comparison>>;
|
|
155
247
|
}, z.core.$strip>, z.ZodObject<{
|
|
156
248
|
type: z.ZodLiteral<PinchConditionType.PHASE>;
|
|
157
249
|
phase: z.ZodEnum<typeof MatchPhase>;
|
|
158
250
|
}, z.core.$strip>], "type">>>;
|
|
159
251
|
conditionLogic: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"ALL">, z.ZodLiteral<"ANY">]>>;
|
|
252
|
+
pinchServer: z.ZodOptional<z.ZodBoolean>;
|
|
253
|
+
subBackMode: z.ZodOptional<z.ZodEnum<{
|
|
254
|
+
FATIGUE: "FATIGUE";
|
|
255
|
+
CONDITIONS: "CONDITIONS";
|
|
256
|
+
}>>;
|
|
257
|
+
subBackConditions: z.ZodOptional<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
258
|
+
type: z.ZodLiteral<PinchConditionType.ASAP>;
|
|
259
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
260
|
+
type: z.ZodLiteral<PinchConditionType.TEAM_SET_POINT>;
|
|
261
|
+
margin: z.ZodNumber;
|
|
262
|
+
opponent: z.ZodEnum<typeof OpponentRelation>;
|
|
263
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
264
|
+
type: z.ZodLiteral<PinchConditionType.OPPONENT_SET_POINT>;
|
|
265
|
+
margin: z.ZodNumber;
|
|
266
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
267
|
+
type: z.ZodLiteral<PinchConditionType.SCORE_DIFF>;
|
|
268
|
+
direction: z.ZodEnum<typeof ScoreDirection>;
|
|
269
|
+
points: z.ZodNumber;
|
|
270
|
+
comparison: z.ZodOptional<z.ZodEnum<typeof Comparison>>;
|
|
271
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
272
|
+
type: z.ZodLiteral<PinchConditionType.AFTER_ROTATIONS>;
|
|
273
|
+
rotations: z.ZodNumber;
|
|
274
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
275
|
+
type: z.ZodLiteral<PinchConditionType.FROM_SET>;
|
|
276
|
+
set: z.ZodNumber;
|
|
277
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
278
|
+
type: z.ZodLiteral<PinchConditionType.MIN_OWN_SCORE>;
|
|
279
|
+
score: z.ZodNumber;
|
|
280
|
+
comparison: z.ZodOptional<z.ZodEnum<typeof Comparison>>;
|
|
281
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
282
|
+
type: z.ZodLiteral<PinchConditionType.MIN_OPPONENT_SCORE>;
|
|
283
|
+
score: z.ZodNumber;
|
|
284
|
+
comparison: z.ZodOptional<z.ZodEnum<typeof Comparison>>;
|
|
285
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
286
|
+
type: z.ZodLiteral<PinchConditionType.PHASE>;
|
|
287
|
+
phase: z.ZodEnum<typeof MatchPhase>;
|
|
288
|
+
}, z.core.$strip>], "type">>>;
|
|
289
|
+
subBackConditionLogic: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"ALL">, z.ZodLiteral<"ANY">]>>;
|
|
160
290
|
starter: z.ZodCustom<Player, Player>;
|
|
161
291
|
}, z.core.$strip>;
|
|
@@ -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 { MatchPhase, OpponentRelation, PinchConditionType, ScoreDirection } from '../pinch-condition';
|
|
4
|
+
import { Comparison, MatchPhase, OpponentRelation, PinchConditionType, ScoreDirection } from '../pinch-condition';
|
|
5
5
|
const playerInstanceSchema = z.custom((v) => v instanceof Player, {
|
|
6
6
|
message: 'INVALID_PLAYER_INSTANCE'
|
|
7
7
|
});
|
|
@@ -10,16 +10,19 @@ export const PinchConditionSchema = z.discriminatedUnion('type', [
|
|
|
10
10
|
z.object({ type: z.literal(PinchConditionType.ASAP) }),
|
|
11
11
|
z.object({ type: z.literal(PinchConditionType.TEAM_SET_POINT), margin: z.number().int().min(1).max(25), opponent: z.nativeEnum(OpponentRelation) }),
|
|
12
12
|
z.object({ type: z.literal(PinchConditionType.OPPONENT_SET_POINT), margin: z.number().int().min(1).max(25) }),
|
|
13
|
-
|
|
13
|
+
// SCORE_DIFF / MIN_OWN_SCORE / MIN_OPPONENT_SCORE carry an optional comparison direction ("Or more" AT_LEAST,
|
|
14
|
+
// the default; "Or less" AT_MOST). Absent = AT_LEAST so existing conditions keep their `>=` behavior.
|
|
15
|
+
z.object({ type: z.literal(PinchConditionType.SCORE_DIFF), direction: z.nativeEnum(ScoreDirection), points: z.number().int().min(1).max(25), comparison: z.nativeEnum(Comparison).optional() }),
|
|
14
16
|
z.object({ type: z.literal(PinchConditionType.AFTER_ROTATIONS), rotations: z.number().int().min(1).max(6) }),
|
|
15
17
|
z.object({ type: z.literal(PinchConditionType.FROM_SET), set: z.number().int().min(1).max(5) }),
|
|
16
|
-
z.object({ type: z.literal(PinchConditionType.MIN_OWN_SCORE), score: z.number().int().min(0).max(40) }),
|
|
17
|
-
z.object({ type: z.literal(PinchConditionType.MIN_OPPONENT_SCORE), score: z.number().int().min(0).max(40) }),
|
|
18
|
+
z.object({ type: z.literal(PinchConditionType.MIN_OWN_SCORE), score: z.number().int().min(0).max(40), comparison: z.nativeEnum(Comparison).optional() }),
|
|
19
|
+
z.object({ type: z.literal(PinchConditionType.MIN_OPPONENT_SCORE), score: z.number().int().min(0).max(40), comparison: z.nativeEnum(Comparison).optional() }),
|
|
18
20
|
// PHASE is used by the libero deployment rule (which reuses this schema); pinch servers never offer it.
|
|
19
21
|
z.object({ type: z.literal(PinchConditionType.PHASE), phase: z.nativeEnum(MatchPhase) })
|
|
20
22
|
]);
|
|
21
23
|
export const ConditionLogicSchema = z.union([z.literal('ALL'), z.literal('ANY')]);
|
|
22
24
|
export const SubModeSchema = z.enum(['FATIGUE', 'PINCH', 'NEVER']);
|
|
25
|
+
export const SubBackModeSchema = z.enum(['FATIGUE', 'CONDITIONS']);
|
|
23
26
|
// Fields shared by the all-sets config and each per-set config.
|
|
24
27
|
const setSubConfigShape = {
|
|
25
28
|
mode: SubModeSchema,
|
|
@@ -27,9 +30,16 @@ const setSubConfigShape = {
|
|
|
27
30
|
fatigueBand: z.nativeEnum(EnergyBand).optional(),
|
|
28
31
|
benchFatigueBand: z.nativeEnum(EnergyBand).optional(),
|
|
29
32
|
conditions: z.array(PinchConditionSchema).optional(),
|
|
30
|
-
conditionLogic: ConditionLogicSchema.optional()
|
|
33
|
+
conditionLogic: ConditionLogicSchema.optional(),
|
|
34
|
+
// pinch ("Conditions") mode. true = serve-and-return pinch server; false/absent = regular conditional sub.
|
|
35
|
+
pinchServer: z.boolean().optional(),
|
|
36
|
+
// a regular conditional sub's sub-back trigger + its condition set (subBackMode === 'CONDITIONS').
|
|
37
|
+
subBackMode: SubBackModeSchema.optional(),
|
|
38
|
+
subBackConditions: z.array(PinchConditionSchema).optional(),
|
|
39
|
+
subBackConditionLogic: ConditionLogicSchema.optional()
|
|
31
40
|
};
|
|
32
|
-
// Pinch mode needs a designated bench player
|
|
41
|
+
// Pinch ("Conditions") mode needs a designated bench player and at least one sub-in condition. A regular
|
|
42
|
+
// conditional sub (pinchServer !== true) with a CONDITIONS sub-back also needs at least one sub-back condition.
|
|
33
43
|
function refinePinch(data, ctx) {
|
|
34
44
|
if (data.mode !== 'PINCH')
|
|
35
45
|
return;
|
|
@@ -39,6 +49,10 @@ function refinePinch(data, ctx) {
|
|
|
39
49
|
if (data.conditions == null || data.conditions.length === 0) {
|
|
40
50
|
ctx.addIssue({ code: 'custom', message: 'PINCH_SERVER_REQUIRES_CONDITIONS', path: ['conditions'] });
|
|
41
51
|
}
|
|
52
|
+
if (data.pinchServer !== true && data.subBackMode === 'CONDITIONS' &&
|
|
53
|
+
(data.subBackConditions == null || data.subBackConditions.length === 0)) {
|
|
54
|
+
ctx.addIssue({ code: 'custom', message: 'CONDITIONAL_SUB_BACK_REQUIRES_CONDITIONS', path: ['subBackConditions'] });
|
|
55
|
+
}
|
|
42
56
|
}
|
|
43
57
|
export const SetSubConfigSchema = z.object(setSubConfigShape).superRefine(refinePinch);
|
|
44
58
|
export const DesignatedSubSchema = z.object({
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { describe, it, expect } from '@jest/globals';
|
|
2
2
|
import { ConditionLogicSchema, DesignatedSubSchema, PinchConditionSchema, SubBandSchema } from './designated-sub.z';
|
|
3
3
|
import { EnergyBand } from '../energy-band';
|
|
4
|
-
import { OpponentRelation, PinchConditionType, ScoreDirection } from '../pinch-condition';
|
|
4
|
+
import { Comparison, OpponentRelation, PinchConditionType, ScoreDirection } from '../pinch-condition';
|
|
5
5
|
import { makeCountry, makePlayer } from '../../test-helpers';
|
|
6
6
|
describe('SubBandSchema', () => {
|
|
7
7
|
it('accepts every energy band and NEVER', () => {
|
|
@@ -57,6 +57,16 @@ describe('PinchConditionSchema', () => {
|
|
|
57
57
|
it('rejects a non-integer numeric field', () => {
|
|
58
58
|
expect(PinchConditionSchema.safeParse({ type: PinchConditionType.FROM_SET, set: 2.5 }).success).toBe(false);
|
|
59
59
|
});
|
|
60
|
+
it('accepts an optional comparison (Or more / Or less) on the numeric-threshold conditions', () => {
|
|
61
|
+
expect(PinchConditionSchema.safeParse({ type: PinchConditionType.SCORE_DIFF, direction: ScoreDirection.LEADING, points: 2, comparison: Comparison.AT_MOST }).success).toBe(true);
|
|
62
|
+
expect(PinchConditionSchema.safeParse({ type: PinchConditionType.MIN_OWN_SCORE, score: 20, comparison: Comparison.AT_MOST }).success).toBe(true);
|
|
63
|
+
expect(PinchConditionSchema.safeParse({ type: PinchConditionType.MIN_OPPONENT_SCORE, score: 20, comparison: Comparison.AT_LEAST }).success).toBe(true);
|
|
64
|
+
// absent comparison stays valid (defaults to AT_LEAST at eval time)
|
|
65
|
+
expect(PinchConditionSchema.safeParse({ type: PinchConditionType.SCORE_DIFF, direction: ScoreDirection.LEADING, points: 2 }).success).toBe(true);
|
|
66
|
+
});
|
|
67
|
+
it('rejects an invalid comparison value', () => {
|
|
68
|
+
expect(PinchConditionSchema.safeParse({ type: PinchConditionType.MIN_OWN_SCORE, score: 20, comparison: 'EXACTLY' }).success).toBe(false);
|
|
69
|
+
});
|
|
60
70
|
});
|
|
61
71
|
describe('DesignatedSubSchema', () => {
|
|
62
72
|
const country = makeCountry();
|
|
@@ -216,4 +226,77 @@ describe('DesignatedSubSchema', () => {
|
|
|
216
226
|
});
|
|
217
227
|
expect(res.success).toBe(false);
|
|
218
228
|
});
|
|
229
|
+
it('accepts a pinch-mode entry marked as a pinch server (serve-and-return)', () => {
|
|
230
|
+
const res = DesignatedSubSchema.safeParse({
|
|
231
|
+
starter,
|
|
232
|
+
bench,
|
|
233
|
+
mode: 'PINCH',
|
|
234
|
+
conditions: [{ type: PinchConditionType.ASAP }],
|
|
235
|
+
pinchServer: true
|
|
236
|
+
});
|
|
237
|
+
expect(res.success).toBe(true);
|
|
238
|
+
});
|
|
239
|
+
it('accepts a regular conditional sub (pinchServer false) with a tiredness sub-back', () => {
|
|
240
|
+
const res = DesignatedSubSchema.safeParse({
|
|
241
|
+
starter,
|
|
242
|
+
bench,
|
|
243
|
+
mode: 'PINCH',
|
|
244
|
+
conditions: [{ type: PinchConditionType.SCORE_DIFF, direction: ScoreDirection.TRAILING, points: 3 }],
|
|
245
|
+
pinchServer: false,
|
|
246
|
+
subBackMode: 'FATIGUE',
|
|
247
|
+
benchFatigueBand: EnergyBand.TIRED
|
|
248
|
+
});
|
|
249
|
+
expect(res.success).toBe(true);
|
|
250
|
+
});
|
|
251
|
+
it('accepts a regular conditional sub with a condition-based sub-back', () => {
|
|
252
|
+
const res = DesignatedSubSchema.safeParse({
|
|
253
|
+
starter,
|
|
254
|
+
bench,
|
|
255
|
+
mode: 'PINCH',
|
|
256
|
+
conditions: [{ type: PinchConditionType.SCORE_DIFF, direction: ScoreDirection.TRAILING, points: 3 }],
|
|
257
|
+
pinchServer: false,
|
|
258
|
+
subBackMode: 'CONDITIONS',
|
|
259
|
+
subBackConditions: [{ type: PinchConditionType.TEAM_SET_POINT, margin: 2, opponent: OpponentRelation.EITHER }],
|
|
260
|
+
subBackConditionLogic: 'ANY'
|
|
261
|
+
});
|
|
262
|
+
expect(res.success).toBe(true);
|
|
263
|
+
});
|
|
264
|
+
it('rejects a condition-based sub-back with no sub-back conditions', () => {
|
|
265
|
+
const res = DesignatedSubSchema.safeParse({
|
|
266
|
+
starter,
|
|
267
|
+
bench,
|
|
268
|
+
mode: 'PINCH',
|
|
269
|
+
conditions: [{ type: PinchConditionType.ASAP }],
|
|
270
|
+
pinchServer: false,
|
|
271
|
+
subBackMode: 'CONDITIONS',
|
|
272
|
+
subBackConditions: []
|
|
273
|
+
});
|
|
274
|
+
expect(res.success).toBe(false);
|
|
275
|
+
if (!res.success) {
|
|
276
|
+
expect(res.error.issues.some(issue => issue.message === 'CONDITIONAL_SUB_BACK_REQUIRES_CONDITIONS')).toBe(true);
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
it('does not require sub-back conditions for a pinch server even under subBackMode CONDITIONS', () => {
|
|
280
|
+
// A pinch server never uses a sub-back rule (it serve-reverts), so the condition requirement is skipped.
|
|
281
|
+
const res = DesignatedSubSchema.safeParse({
|
|
282
|
+
starter,
|
|
283
|
+
bench,
|
|
284
|
+
mode: 'PINCH',
|
|
285
|
+
conditions: [{ type: PinchConditionType.ASAP }],
|
|
286
|
+
pinchServer: true,
|
|
287
|
+
subBackMode: 'CONDITIONS'
|
|
288
|
+
});
|
|
289
|
+
expect(res.success).toBe(true);
|
|
290
|
+
});
|
|
291
|
+
it('rejects an invalid subBackMode', () => {
|
|
292
|
+
const res = DesignatedSubSchema.safeParse({
|
|
293
|
+
starter,
|
|
294
|
+
bench,
|
|
295
|
+
mode: 'PINCH',
|
|
296
|
+
conditions: [{ type: PinchConditionType.ASAP }],
|
|
297
|
+
pinchServer: false,
|
|
298
|
+
subBackMode: 'WHENEVER'
|
|
299
|
+
});
|
|
300
|
+
expect(res.success).toBe(false);
|
|
301
|
+
});
|
|
219
302
|
});
|