tods-competition-factory 1.8.19 → 1.8.21

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.
@@ -4308,6 +4308,9 @@ const POLICY_ROUND_NAMING_DEFAULT = {
4308
4308
  namingConventions: {
4309
4309
  round: "Round"
4310
4310
  },
4311
+ qualifyingFinishMap: {
4312
+ 1: "Final"
4313
+ },
4311
4314
  abbreviatedRoundNamingMap: {
4312
4315
  // key is matchUpsCount for the round
4313
4316
  1: "F",
@@ -4321,7 +4324,8 @@ const POLICY_ROUND_NAMING_DEFAULT = {
4321
4324
  },
4322
4325
  affixes: {
4323
4326
  roundNumber: "R",
4324
- preFeedRound: "Q"
4327
+ preFeedRound: "Q",
4328
+ preQualifying: "P"
4325
4329
  },
4326
4330
  stageConstants: {
4327
4331
  [MAIN]: "",
@@ -4334,6 +4338,7 @@ const POLICY_ROUND_NAMING_DEFAULT = {
4334
4338
 
4335
4339
  function getRoundContextProfile({
4336
4340
  roundNamingPolicy,
4341
+ drawDefinition,
4337
4342
  structure,
4338
4343
  matchUps
4339
4344
  }) {
@@ -4344,21 +4349,31 @@ function getRoundContextProfile({
4344
4349
  const isRoundRobin = structure.structures;
4345
4350
  const roundNamingProfile = {};
4346
4351
  const defaultRoundNamingPolicy = POLICY_ROUND_NAMING_DEFAULT[POLICY_TYPE_ROUND_NAMING];
4352
+ const isQualifying = structure.stage === QUALIFYING;
4353
+ const qualifyingFinishgMap = isQualifying && (roundNamingPolicy?.qualifyingFinishMap || defaultRoundNamingPolicy?.qualifyingFinishMap || {});
4354
+ const qualifyingStageSequences = isQualifying ? Math.max(
4355
+ ...(drawDefinition?.structures ?? []).filter((structure2) => structure2.stage === QUALIFYING).map(({ stageSequence }) => stageSequence ?? 1),
4356
+ 0
4357
+ ) : 0;
4358
+ const preQualifyingSequence = qualifyingStageSequences ? qualifyingStageSequences - (structure.stageSequence || 1) || "" : "";
4359
+ const preQualifyingAffix = preQualifyingSequence ? roundNamingPolicy?.affixes?.preQualifying || defaultRoundNamingPolicy.affixes.preQualifying || "" : "";
4347
4360
  const roundNamingMap = roundNamingPolicy?.roundNamingMap || defaultRoundNamingPolicy.roundNamingMap || {};
4348
4361
  const abbreviatedRoundNamingMap = roundNamingPolicy?.abbreviatedRoundNamingMap || defaultRoundNamingPolicy.abbreviatedRoundNamingMap || {};
4349
- const roundNamePrefix = roundNamingPolicy?.affixes || defaultRoundNamingPolicy.affixes;
4350
- const roundNumberAffix = roundNamePrefix.roundNumber || defaultRoundNamingPolicy.affixes.roundNumber;
4362
+ const preFeedAffix = roundNamingPolicy?.affixes?.preFeedRound || defaultRoundNamingPolicy.affixes.preFeedRound;
4363
+ const roundNumberAffix = roundNamingPolicy?.affixes?.roundNumber || defaultRoundNamingPolicy.affixes.roundNumber;
4351
4364
  const namingConventions = roundNamingPolicy?.namingConventions || defaultRoundNamingPolicy.namingConventions;
4352
4365
  const roundNameFallback = namingConventions.round;
4353
- const stageInitial = stage && stage !== MAIN && stage[0];
4354
- const stageConstants = roundNamingPolicy?.stageConstants;
4355
- const stageConstant = stage && stageConstants?.[stage] || stageInitial;
4366
+ const stageInitial = stage && stage !== MAIN ? stage[0] : "";
4367
+ const stageConstants = roundNamingPolicy?.stageConstants || defaultRoundNamingPolicy.stageConstants;
4368
+ const stageIndicator = stage && stageConstants?.[stage] || stageInitial;
4369
+ const stageConstant = `${preQualifyingAffix}${stageIndicator}${preQualifyingSequence}`;
4356
4370
  const roundProfileKeys = roundProfile ? Object.keys(roundProfile) : [];
4371
+ const qualifyingAffix = isQualifying && stageConstants?.[QUALIFYING] ? `${stageConstants?.[QUALIFYING]}-` : "";
4357
4372
  if (isRoundRobin || isAdHocStructure || isLuckyStructure) {
4358
4373
  Object.assign(
4359
4374
  roundNamingProfile,
4360
4375
  ...roundProfileKeys.map((key) => {
4361
- const roundName = `${roundNameFallback} ${key}`;
4376
+ const roundName = `${qualifyingAffix}${roundNameFallback} ${key}`;
4362
4377
  const abbreviatedRoundName = `${roundNumberAffix}${key}`;
4363
4378
  return { [key]: { roundName, abbreviatedRoundName } };
4364
4379
  })
@@ -4371,15 +4386,15 @@ function getRoundContextProfile({
4371
4386
  return;
4372
4387
  const { matchUpsCount, preFeedRound } = roundProfile[round];
4373
4388
  const participantsCount = matchUpsCount * 2;
4374
- const sizedRoundName = roundNamingMap[matchUpsCount] || `${roundNamePrefix.roundNumber}${participantsCount}`;
4375
- const suffix = preFeedRound ? `-${roundNamePrefix.preFeedRound}` : "";
4389
+ const sizedRoundName = qualifyingFinishgMap?.[roundProfile?.[round].finishingRound] || qualifyingFinishgMap && `${roundNumberAffix}${participantsCount}` || roundNamingMap[matchUpsCount] || `${roundNumberAffix}${participantsCount}`;
4390
+ const suffix = preFeedRound ? `-${preFeedAffix}` : "";
4376
4391
  const profileRoundName = `${sizedRoundName}${suffix}`;
4377
4392
  const roundName = [
4378
4393
  stageConstant,
4379
4394
  structureAbbreviation,
4380
4395
  profileRoundName
4381
4396
  ].filter(Boolean).join("-");
4382
- const sizedAbbreviation = abbreviatedRoundNamingMap[matchUpsCount] || `${roundNamePrefix.roundNumber}${participantsCount}`;
4397
+ const sizedAbbreviation = abbreviatedRoundNamingMap[matchUpsCount] || `${roundNumberAffix}${participantsCount}`;
4383
4398
  const profileAbbreviation = `${sizedAbbreviation}${suffix}`;
4384
4399
  const abbreviatedRoundName = [
4385
4400
  stageConstant,
@@ -4552,6 +4567,7 @@ function getAllStructureMatchUps({
4552
4567
  const roundNamingPolicy = appliedPolicies?.[POLICY_TYPE_ROUND_NAMING];
4553
4568
  const result = getRoundContextProfile({
4554
4569
  roundNamingPolicy,
4570
+ drawDefinition,
4555
4571
  structure,
4556
4572
  matchUps
4557
4573
  });
@@ -16752,8 +16768,8 @@ function validateCollectionDefinition({
16752
16768
  if (checkGender && referenceGender && gender && [GenderEnum.Male, GenderEnum.Female].includes(referenceGender) && referenceGender !== gender) {
16753
16769
  errors.push(`Invalid gender: ${gender}`);
16754
16770
  return decorateResult({
16771
+ result: { error: INVALID_GENDER, errors },
16755
16772
  context: { referenceGender, gender },
16756
- result: { error: INVALID_GENDER },
16757
16773
  stack
16758
16774
  });
16759
16775
  }
@@ -21397,25 +21413,65 @@ function isUngrouped(entryStatus) {
21397
21413
  return [UNPAIRED, UNGROUPED].includes(entryStatus);
21398
21414
  }
21399
21415
 
21416
+ const POLICY_MATCHUP_ACTIONS_DEFAULT = {
21417
+ [POLICY_TYPE_MATCHUP_ACTIONS]: {
21418
+ policyName: "matchUpActionsDefault",
21419
+ // matchUpActions will be selectively enabled for structures matching { stages: [], stageSequences: [] }
21420
+ // enabledStructures: [] => all structures are enabled
21421
+ enabledStructures: [
21422
+ {
21423
+ stages: [],
21424
+ // stages: [] => applies to all stages
21425
+ stageSequences: [],
21426
+ // stageSequences: [] => applies to all stageSequences
21427
+ enabledActions: [],
21428
+ disabledActions: []
21429
+ // disabledActions: [] => no actions are disabled
21430
+ }
21431
+ ],
21432
+ participants: {
21433
+ enforceCategory: true,
21434
+ // validate collectionDefinition.category against event.category
21435
+ enforceGender: true
21436
+ // disallow placing FEMALEs in MALE events and vice versa
21437
+ },
21438
+ processCodes: {
21439
+ substitution: ["RANKING.IGNORE", "RATING.IGNORE"]
21440
+ },
21441
+ substituteAfterCompleted: false,
21442
+ substituteWithoutScore: false
21443
+ }
21444
+ };
21445
+
21400
21446
  function checkValidEntries({
21401
- enforceGender = true,
21402
21447
  consideredEntries,
21448
+ policyDefinitions,
21403
21449
  tournamentRecord,
21450
+ appliedPolicies,
21451
+ participantMap,
21452
+ enforceGender,
21404
21453
  participants,
21405
21454
  event
21406
21455
  }) {
21407
- participants = participants || tournamentRecord?.participants;
21456
+ if ((!participants || !participantMap) && tournamentRecord) {
21457
+ ({ participants, participantMap } = getParticipants({
21458
+ tournamentRecord
21459
+ }));
21460
+ }
21408
21461
  if (!participants)
21409
21462
  return { error: MISSING_PARTICIPANTS };
21410
21463
  if (!Array.isArray(participants))
21411
21464
  return { error: INVALID_VALUES };
21412
21465
  if (!event)
21413
21466
  return { error: MISSING_EVENT };
21467
+ const matchUpActionsPolicy = policyDefinitions?.[POLICY_TYPE_MATCHUP_ACTIONS] ?? appliedPolicies?.[POLICY_TYPE_MATCHUP_ACTIONS] ?? POLICY_MATCHUP_ACTIONS_DEFAULT[POLICY_TYPE_MATCHUP_ACTIONS];
21468
+ const genderEnforced = (enforceGender ?? matchUpActionsPolicy?.participants?.enforceGender) !== false;
21414
21469
  const { eventType, gender: eventGender } = event;
21415
- const participantType = eventType === TEAM_EVENT && TEAM || eventType === DOUBLES_EVENT && PAIR || INDIVIDUAL;
21470
+ const isDoubles = eventType === DOUBLES_EVENT;
21471
+ const participantType = eventType === TEAM_EVENT && TEAM || isDoubles && PAIR || INDIVIDUAL;
21416
21472
  const entryStatusMap = Object.assign(
21417
21473
  {},
21418
- ...(consideredEntries || event.entries || []).map((entry) => ({
21474
+ ...(consideredEntries ?? event.entries ?? []).map((entry) => ({
21419
21475
  [entry.participantId]: entry.entryStatus
21420
21476
  }))
21421
21477
  );
@@ -21427,9 +21483,14 @@ function checkValidEntries({
21427
21483
  const entryStatus = entryStatusMap[participant.participantId];
21428
21484
  const ungroupedParticipant = eventType && [TypeEnum.Doubles, TypeEnum.Team].includes(eventType) && participant.participantType === INDIVIDUAL && (isUngrouped(entryStatus) || entryStatus === WITHDRAWN);
21429
21485
  const mismatch = participant.participantType !== participantType && !ungroupedParticipant;
21486
+ const pairGender = !mismatch && isDoubles && unique(
21487
+ participant?.individualParticipantIds?.map((id) => participantMap?.[id]?.participant?.person?.sex).filter(Boolean) ?? []
21488
+ );
21489
+ 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);
21430
21490
  const personGender = participant?.person?.sex;
21431
- const wrongGender = enforceGender && eventGender && eventType === TypeEnum.Singles && [GenderEnum.Male, GenderEnum.Female].includes(eventGender) && personGender !== eventGender;
21432
- return mismatch || wrongGender;
21491
+ const validPersonGender = !participant?.person || !eventGender || [GenderEnum.Any, GenderEnum.Mixed].includes(eventGender) || [GenderEnum.Male, GenderEnum.Female].includes(eventGender) && personGender === eventGender;
21492
+ const validGender = !genderEnforced || validPairGender && validPersonGender;
21493
+ return mismatch || !validGender;
21433
21494
  });
21434
21495
  if (invalidEntries.length) {
21435
21496
  const invalidParticipantIds = invalidEntries.map(
@@ -21437,7 +21498,7 @@ function checkValidEntries({
21437
21498
  );
21438
21499
  return { error: INVALID_ENTRIES, invalidParticipantIds };
21439
21500
  }
21440
- return { ...SUCCESS };
21501
+ return { ...SUCCESS, valid: true };
21441
21502
  }
21442
21503
 
21443
21504
  function getValidStage({ stage, drawDefinition }) {
@@ -23321,7 +23382,7 @@ function generateDrawDefinition(params) {
23321
23382
  }).appliedPolicies ?? {};
23322
23383
  const drawTypeCoercion = params.drawTypeCoercion ?? appliedPolicies?.[POLICY_TYPE_DRAWS]?.drawTypeCoercion ?? true;
23323
23384
  const drawType = drawTypeCoercion && params.drawSize === 2 && DrawTypeEnum.SingleElimination || params.drawType || DrawTypeEnum.SingleElimination;
23324
- const { participants } = getParticipants({
23385
+ const { participants, participantMap } = getParticipants({
23325
23386
  withIndividualParticipants: true,
23326
23387
  tournamentRecord
23327
23388
  });
@@ -23340,6 +23401,8 @@ function generateDrawDefinition(params) {
23340
23401
  const consideredEntries = (qualifyingOnly && [] || drawEntries || (considerEventEntries ? eventEntries : [])).filter(({ entryStage }) => !entryStage || entryStage === MAIN);
23341
23402
  const validEntriesResult = event && participants && checkValidEntries({
23342
23403
  consideredEntries,
23404
+ appliedPolicies,
23405
+ participantMap,
23343
23406
  enforceGender,
23344
23407
  participants,
23345
23408
  event