tods-competition-factory 1.8.18 → 1.8.20

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.
@@ -9454,8 +9454,8 @@ function updateInContextMatchUp({ tournamentId, inContextMatchUp }) {
9454
9454
  return { error: MISSING_MATCHUP };
9455
9455
  }
9456
9456
  addNotice({
9457
- topic: UPDATE_INCONTEXT_MATCHUP,
9458
9457
  payload: { inContextMatchUp, tournamentId },
9458
+ topic: UPDATE_INCONTEXT_MATCHUP,
9459
9459
  key: inContextMatchUp.matchUpId
9460
9460
  });
9461
9461
  return { ...SUCCESS };
@@ -10654,8 +10654,8 @@ function updateSideLineUp({
10654
10654
  element: drawDefinition,
10655
10655
  name: LINEUPS
10656
10656
  });
10657
- const value = existingExtension?.value || {};
10658
- const lineUp = value[teamParticipantId];
10657
+ const lineUps = existingExtension?.value || {};
10658
+ const lineUp = makeDeepCopy(lineUps[teamParticipantId], false, true);
10659
10659
  if (sideExists) {
10660
10660
  matchUp?.sides?.forEach((side) => {
10661
10661
  if (side.sideNumber === drawPositionSideNumber) {
@@ -10670,13 +10670,12 @@ function updateSideLineUp({
10670
10670
  const targetSide = matchUp.sides.find(
10671
10671
  (side) => side.sideNumber === drawPositionSideNumber
10672
10672
  );
10673
- if (targetSide) {
10673
+ if (targetSide)
10674
10674
  targetSide.lineUp = lineUp;
10675
- }
10676
10675
  }
10677
10676
  modifyMatchUpNotice({
10678
10677
  tournamentId: tournamentRecord?.tournamentId,
10679
- context: "updateSidLineUps",
10678
+ context: "updateSidLineUp",
10680
10679
  eventId: event?.eventId,
10681
10680
  drawDefinition,
10682
10681
  matchUp
@@ -11493,10 +11492,10 @@ function removeLineUpSubstitutions({ lineUp }) {
11493
11492
  const participantAssignments = {};
11494
11493
  const permutations = unique(
11495
11494
  lineUp.flatMap(
11496
- ({ collectionAssignments }) => collectionAssignments.map(
11495
+ ({ collectionAssignments }) => collectionAssignments?.map(
11497
11496
  ({ collectionId, collectionPosition }) => [collectionId, collectionPosition].join("|")
11498
11497
  )
11499
- )
11498
+ ).filter(Boolean)
11500
11499
  );
11501
11500
  permutations.forEach((permutation) => {
11502
11501
  const [collectionId, position] = permutation.split("|");
@@ -15973,7 +15972,7 @@ const toBePlayed = {
15973
15972
  winningSide: void 0
15974
15973
  };
15975
15974
 
15976
- function findMatchUp({
15975
+ function findDrawMatchUp({
15977
15976
  tournamentParticipants,
15978
15977
  afterRecoveryTimes,
15979
15978
  contextContent,
@@ -16035,7 +16034,7 @@ function modifyMatchUpScore({
16035
16034
  const isDualMatchUp = matchUp.matchUpType === TEAM$2;
16036
16035
  if (isDualMatchUp && drawDefinition) {
16037
16036
  if (matchUpId && matchUp.matchUpId !== matchUpId) {
16038
- const findResult = findMatchUp({
16037
+ const findResult = findDrawMatchUp({
16039
16038
  drawDefinition,
16040
16039
  matchUpId,
16041
16040
  event
@@ -16064,7 +16063,7 @@ function modifyMatchUpScore({
16064
16063
  if (removeWinningSide)
16065
16064
  matchUp.winningSide = void 0;
16066
16065
  if (!structure && drawDefinition) {
16067
- ({ structure } = findMatchUp({
16066
+ ({ structure } = findDrawMatchUp({
16068
16067
  drawDefinition,
16069
16068
  matchUpId,
16070
16069
  event
@@ -16219,6 +16218,48 @@ function drawPositionsAssignedParticipantIds({ structure, matchUp }) {
16219
16218
  return assignedParticipantIds?.length === 2;
16220
16219
  }
16221
16220
 
16221
+ function ensureSideLineUps({
16222
+ inContextDualMatchUp,
16223
+ drawDefinition,
16224
+ tournamentId,
16225
+ dualMatchUp,
16226
+ eventId
16227
+ }) {
16228
+ if (dualMatchUp && !dualMatchUp?.sides?.length) {
16229
+ if (!inContextDualMatchUp) {
16230
+ inContextDualMatchUp = findDrawMatchUp({
16231
+ matchUpId: dualMatchUp.matchUpId,
16232
+ inContext: true,
16233
+ drawDefinition
16234
+ })?.matchUp;
16235
+ }
16236
+ const { extension } = findExtension$1({
16237
+ element: drawDefinition,
16238
+ name: LINEUPS
16239
+ });
16240
+ const lineUps = makeDeepCopy(extension?.value || {}, false, true);
16241
+ const extractSideDetail = ({
16242
+ displaySideNumber,
16243
+ drawPosition,
16244
+ sideNumber
16245
+ }) => ({ drawPosition, sideNumber, displaySideNumber });
16246
+ dualMatchUp.sides = inContextDualMatchUp?.sides?.map((side) => {
16247
+ const participantId = side.participantId;
16248
+ return {
16249
+ ...extractSideDetail(side),
16250
+ lineUp: participantId && lineUps[participantId] || []
16251
+ };
16252
+ });
16253
+ modifyMatchUpNotice({
16254
+ context: "ensureSidLineUps",
16255
+ matchUp: dualMatchUp,
16256
+ drawDefinition,
16257
+ tournamentId,
16258
+ eventId
16259
+ });
16260
+ }
16261
+ }
16262
+
16222
16263
  const typeMatch = (arr, type) => arr.filter(Boolean).every((i) => typeof i === type);
16223
16264
  const allNumeric = (arr) => arr.filter(Boolean).every(isNumeric);
16224
16265
  function getCategoryAgeDetails(params) {
@@ -16390,28 +16431,53 @@ function getCategoryAgeDetails(params) {
16390
16431
  return result;
16391
16432
  }
16392
16433
 
16434
+ function validateCategory({ category }) {
16435
+ if (!isObject(category))
16436
+ return { error: INVALID_VALUES };
16437
+ const categoryDetails = getCategoryAgeDetails({ category });
16438
+ if (categoryDetails.error)
16439
+ return { error: categoryDetails };
16440
+ const { ratingMax, ratingMin } = category;
16441
+ if (ratingMax && !isNumeric(ratingMax))
16442
+ return decorateResult({
16443
+ result: { error: INVALID_VALUES },
16444
+ context: { ratingMax }
16445
+ });
16446
+ if (ratingMin && !isNumeric(ratingMin))
16447
+ return decorateResult({
16448
+ result: { error: INVALID_VALUES },
16449
+ context: { ratingMin }
16450
+ });
16451
+ return { ...categoryDetails };
16452
+ }
16453
+
16393
16454
  function categoryCanContain({
16394
16455
  childCategory,
16395
16456
  withDetails,
16396
16457
  category
16397
16458
  }) {
16398
- const categoryDetails = getCategoryAgeDetails({ category });
16399
- const childCategoryDetails = getCategoryAgeDetails({
16459
+ const categoryDetails = validateCategory({ category });
16460
+ const childCategoryDetails = validateCategory({
16400
16461
  category: childCategory
16401
16462
  });
16402
16463
  const invalidAgeMin = childCategoryDetails.ageMin && (categoryDetails.ageMin && childCategoryDetails.ageMin < categoryDetails.ageMin || categoryDetails.ageMax && childCategoryDetails.ageMin > categoryDetails.ageMax);
16403
16464
  const invalidAgeMax = childCategoryDetails.ageMax && (categoryDetails.ageMax && childCategoryDetails.ageMax > categoryDetails.ageMax || categoryDetails.ageMin && childCategoryDetails.ageMax < categoryDetails.ageMin);
16404
16465
  const invalidAgeMinDate = childCategoryDetails.ageMinDate && categoryDetails.ageMaxDate && new Date(childCategoryDetails.ageMinDate) > new Date(categoryDetails.ageMaxDate);
16405
16466
  const invalidAgeMaxDate = childCategoryDetails.ageMaxDate && categoryDetails.ageMinDate && new Date(childCategoryDetails.ageMaxDate) < new Date(categoryDetails.ageMinDate);
16406
- const valid = !invalidAgeMax && !invalidAgeMin && !invalidAgeMinDate && !invalidAgeMaxDate;
16467
+ const ratingComparison = category.ratingType && childCategory.ratingType && category.ratingType === childCategory.ratingType;
16468
+ const invalidRatingRange = ratingComparison && (category.ratingMin && childCategory.ratingMin && childCategory.ratingMin < category.ratingMin || category.ratingMax && childCategory.ratingMax && childCategory.ratingMax > category.ratingMax || category.ratingMin && childCategory.ratingMax && childCategory.ratingMax < category.ratingMin || category.ratingMax && childCategory.ratingMin && childCategory.ratingMin > category.ratingMax);
16469
+ const invalidBallType = category.ballType && childCategory.ballType && category.ballType !== childCategory.ballType;
16470
+ const valid = !invalidRatingRange && !invalidAgeMinDate && !invalidAgeMaxDate && !invalidBallType && !invalidAgeMax && !invalidAgeMin;
16407
16471
  const ignoreFalse = true;
16408
16472
  const result = definedAttributes(
16409
16473
  {
16410
- valid,
16474
+ invalidRatingRange,
16475
+ invalidAgeMinDate,
16476
+ invalidAgeMaxDate,
16477
+ invalidBallType,
16411
16478
  invalidAgeMax,
16412
16479
  invalidAgeMin,
16413
- invalidAgeMinDate,
16414
- invalidAgeMaxDate
16480
+ valid
16415
16481
  },
16416
16482
  ignoreFalse
16417
16483
  );
@@ -16686,8 +16752,8 @@ function validateCollectionDefinition({
16686
16752
  if (checkGender && referenceGender && gender && [GenderEnum.Male, GenderEnum.Female].includes(referenceGender) && referenceGender !== gender) {
16687
16753
  errors.push(`Invalid gender: ${gender}`);
16688
16754
  return decorateResult({
16755
+ result: { error: INVALID_GENDER, errors },
16689
16756
  context: { referenceGender, gender },
16690
- result: { error: INVALID_GENDER },
16691
16757
  stack
16692
16758
  });
16693
16759
  }
@@ -17007,7 +17073,7 @@ function generateTieMatchUpScore(params) {
17007
17073
  }
17008
17074
  if (!winningSide && tallyDirectives) {
17009
17075
  const matchUpId = matchUp.matchUpId;
17010
- const inContextMatchUp = matchUp.hasContext ? matchUp : matchUpsMap?.drawMatchUps?.[matchUpId] || drawDefinition && findMatchUp({
17076
+ const inContextMatchUp = matchUp.hasContext ? matchUp : matchUpsMap?.drawMatchUps?.[matchUpId] || drawDefinition && findDrawMatchUp({
17011
17077
  inContext: true,
17012
17078
  drawDefinition,
17013
17079
  matchUpId
@@ -17051,7 +17117,7 @@ function updateTieMatchUpScore({
17051
17117
  matchUpId,
17052
17118
  event
17053
17119
  }) {
17054
- const result = findMatchUp({ drawDefinition, event, matchUpId });
17120
+ const result = findDrawMatchUp({ drawDefinition, event, matchUpId });
17055
17121
  if (result.error)
17056
17122
  return result;
17057
17123
  if (!result.matchUp)
@@ -17059,6 +17125,12 @@ function updateTieMatchUpScore({
17059
17125
  const { matchUp, structure } = result;
17060
17126
  if (!matchUp.tieMatchUps)
17061
17127
  return { error: INVALID_MATCHUP };
17128
+ ensureSideLineUps({
17129
+ tournamentId: tournamentRecord?.tournamentId,
17130
+ eventId: event?.eventId,
17131
+ dualMatchUp: matchUp,
17132
+ drawDefinition
17133
+ });
17062
17134
  const { extension } = findExtension({
17063
17135
  name: DISABLE_AUTO_CALC,
17064
17136
  element: matchUp
@@ -21040,7 +21112,7 @@ function setMatchUpFormat(params) {
21040
21112
  return { error: UNRECOGNIZED_MATCHUP_FORMAT };
21041
21113
  const stack = "setMatchUpFormat";
21042
21114
  if (matchUpId) {
21043
- const result = findMatchUp({
21115
+ const result = findDrawMatchUp({
21044
21116
  drawDefinition,
21045
21117
  matchUpId,
21046
21118
  event
@@ -21325,25 +21397,65 @@ function isUngrouped(entryStatus) {
21325
21397
  return [UNPAIRED, UNGROUPED].includes(entryStatus);
21326
21398
  }
21327
21399
 
21400
+ const POLICY_MATCHUP_ACTIONS_DEFAULT = {
21401
+ [POLICY_TYPE_MATCHUP_ACTIONS]: {
21402
+ policyName: "matchUpActionsDefault",
21403
+ // matchUpActions will be selectively enabled for structures matching { stages: [], stageSequences: [] }
21404
+ // enabledStructures: [] => all structures are enabled
21405
+ enabledStructures: [
21406
+ {
21407
+ stages: [],
21408
+ // stages: [] => applies to all stages
21409
+ stageSequences: [],
21410
+ // stageSequences: [] => applies to all stageSequences
21411
+ enabledActions: [],
21412
+ disabledActions: []
21413
+ // disabledActions: [] => no actions are disabled
21414
+ }
21415
+ ],
21416
+ participants: {
21417
+ enforceCategory: true,
21418
+ // validate collectionDefinition.category against event.category
21419
+ enforceGender: true
21420
+ // disallow placing FEMALEs in MALE events and vice versa
21421
+ },
21422
+ processCodes: {
21423
+ substitution: ["RANKING.IGNORE", "RATING.IGNORE"]
21424
+ },
21425
+ substituteAfterCompleted: false,
21426
+ substituteWithoutScore: false
21427
+ }
21428
+ };
21429
+
21328
21430
  function checkValidEntries({
21329
- enforceGender = true,
21330
21431
  consideredEntries,
21432
+ policyDefinitions,
21331
21433
  tournamentRecord,
21434
+ appliedPolicies,
21435
+ participantMap,
21436
+ enforceGender,
21332
21437
  participants,
21333
21438
  event
21334
21439
  }) {
21335
- participants = participants || tournamentRecord?.participants;
21440
+ if ((!participants || !participantMap) && tournamentRecord) {
21441
+ ({ participants, participantMap } = getParticipants({
21442
+ tournamentRecord
21443
+ }));
21444
+ }
21336
21445
  if (!participants)
21337
21446
  return { error: MISSING_PARTICIPANTS };
21338
21447
  if (!Array.isArray(participants))
21339
21448
  return { error: INVALID_VALUES };
21340
21449
  if (!event)
21341
21450
  return { error: MISSING_EVENT };
21451
+ const matchUpActionsPolicy = policyDefinitions?.[POLICY_TYPE_MATCHUP_ACTIONS] ?? appliedPolicies?.[POLICY_TYPE_MATCHUP_ACTIONS] ?? POLICY_MATCHUP_ACTIONS_DEFAULT[POLICY_TYPE_MATCHUP_ACTIONS];
21452
+ const genderEnforced = (enforceGender ?? matchUpActionsPolicy?.participants?.enforceGender) !== false;
21342
21453
  const { eventType, gender: eventGender } = event;
21343
- const participantType = eventType === TEAM_EVENT && TEAM || eventType === DOUBLES_EVENT && PAIR || INDIVIDUAL;
21454
+ const isDoubles = eventType === DOUBLES_EVENT;
21455
+ const participantType = eventType === TEAM_EVENT && TEAM || isDoubles && PAIR || INDIVIDUAL;
21344
21456
  const entryStatusMap = Object.assign(
21345
21457
  {},
21346
- ...(consideredEntries || event.entries || []).map((entry) => ({
21458
+ ...(consideredEntries ?? event.entries ?? []).map((entry) => ({
21347
21459
  [entry.participantId]: entry.entryStatus
21348
21460
  }))
21349
21461
  );
@@ -21355,9 +21467,14 @@ function checkValidEntries({
21355
21467
  const entryStatus = entryStatusMap[participant.participantId];
21356
21468
  const ungroupedParticipant = eventType && [TypeEnum.Doubles, TypeEnum.Team].includes(eventType) && participant.participantType === INDIVIDUAL && (isUngrouped(entryStatus) || entryStatus === WITHDRAWN);
21357
21469
  const mismatch = participant.participantType !== participantType && !ungroupedParticipant;
21470
+ const pairGender = !mismatch && isDoubles && unique(
21471
+ participant?.individualParticipantIds?.map((id) => participantMap?.[id]?.participant?.person?.sex).filter(Boolean) ?? []
21472
+ );
21473
+ const validPairGender = !eventGender || !pairGender?.length || GenderEnum.Any === eventGender || [GenderEnum.Male, GenderEnum.Female].includes(eventGender) && pairGender[0] === eventGender || GenderEnum.Mixed === eventGender && (pairGender.length == 1 && participant.individualParticipantIds?.length === 1 || pairGender.length === 2);
21358
21474
  const personGender = participant?.person?.sex;
21359
- const wrongGender = enforceGender && eventGender && eventType === TypeEnum.Singles && [GenderEnum.Male, GenderEnum.Female].includes(eventGender) && personGender !== eventGender;
21360
- return mismatch || wrongGender;
21475
+ const validPersonGender = !participant?.person || !eventGender || [GenderEnum.Any, GenderEnum.Mixed].includes(eventGender) || [GenderEnum.Male, GenderEnum.Female].includes(eventGender) && personGender === eventGender;
21476
+ const validGender = !genderEnforced || validPairGender && validPersonGender;
21477
+ return mismatch || !validGender;
21361
21478
  });
21362
21479
  if (invalidEntries.length) {
21363
21480
  const invalidParticipantIds = invalidEntries.map(
@@ -21365,7 +21482,7 @@ function checkValidEntries({
21365
21482
  );
21366
21483
  return { error: INVALID_ENTRIES, invalidParticipantIds };
21367
21484
  }
21368
- return { ...SUCCESS };
21485
+ return { ...SUCCESS, valid: true };
21369
21486
  }
21370
21487
 
21371
21488
  function getValidStage({ stage, drawDefinition }) {
@@ -23249,7 +23366,7 @@ function generateDrawDefinition(params) {
23249
23366
  }).appliedPolicies ?? {};
23250
23367
  const drawTypeCoercion = params.drawTypeCoercion ?? appliedPolicies?.[POLICY_TYPE_DRAWS]?.drawTypeCoercion ?? true;
23251
23368
  const drawType = drawTypeCoercion && params.drawSize === 2 && DrawTypeEnum.SingleElimination || params.drawType || DrawTypeEnum.SingleElimination;
23252
- const { participants } = getParticipants({
23369
+ const { participants, participantMap } = getParticipants({
23253
23370
  withIndividualParticipants: true,
23254
23371
  tournamentRecord
23255
23372
  });
@@ -23268,6 +23385,8 @@ function generateDrawDefinition(params) {
23268
23385
  const consideredEntries = (qualifyingOnly && [] || drawEntries || (considerEventEntries ? eventEntries : [])).filter(({ entryStage }) => !entryStage || entryStage === MAIN);
23269
23386
  const validEntriesResult = event && participants && checkValidEntries({
23270
23387
  consideredEntries,
23388
+ appliedPolicies,
23389
+ participantMap,
23271
23390
  enforceGender,
23272
23391
  participants,
23273
23392
  event