tods-competition-factory 1.8.22 → 1.8.24

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/README.md CHANGED
@@ -39,7 +39,7 @@ By default a deep copy of documents are made as they are loaded into each state
39
39
  ## Other Utilities
40
40
 
41
41
  1. [**mocksEngine**](./overview/mocks-engine-overview) - generates complete tournament objects, or tournamentRecords, as well as mock persons, participants and matchUp outcomes.
42
- It is used extensively in the ~1850 tests that are run against the factory methods before every package release.
42
+ It is used extensively in the ~1900 tests that are run against the factory methods before every package release.
43
43
  2. [**scoreGovernor**](./scoreGovernor) - is a collection of scoring related utilities which provide analysis/validation or generate values, but do not make any mutations.
44
44
  3. [**matchUpFormatCode**](./codes/matchup-format) - is an ITF matchUp format code parser, stringifier, and validator.
45
45
  4. [**ageCategoryCode**](./codes/age-category) - is an ITF ageCategoryCode parser.
@@ -2071,7 +2071,7 @@ function findVenue({
2071
2071
  if (!venue && tournamentRecords) {
2072
2072
  const linkedTournamentIds = getLinkedTournamentIds({
2073
2073
  tournamentRecords
2074
- }).linkedTournamentIds || [];
2074
+ }).linkedTournamentIds ?? [];
2075
2075
  const relevantIds = linkedTournamentIds[tournamentRecord.tournamentId];
2076
2076
  for (const tournamentId of relevantIds) {
2077
2077
  const record = tournamentRecords[tournamentId];
@@ -2630,7 +2630,7 @@ function getPairedParticipant({
2630
2630
  result: { error: MISSING_PARTICIPANT_IDS },
2631
2631
  stack
2632
2632
  });
2633
- tournamentParticipants = tournamentParticipants || tournamentRecord?.participants || [];
2633
+ tournamentParticipants = tournamentParticipants ?? tournamentRecord?.participants ?? [];
2634
2634
  const existingPairedParticipants = tournamentParticipants.filter(
2635
2635
  (participant) => participant.participantType === PAIR && intersection(participantIds, participant.individualParticipantIds).length === participantIds.length && participant.individualParticipantIds.length === participantIds.length
2636
2636
  );
@@ -4305,7 +4305,8 @@ const POLICY_ROUND_NAMING_DEFAULT = {
4305
4305
  [POLICY_TYPE_ROUND_NAMING]: {
4306
4306
  policyName: "Round Naming Default",
4307
4307
  namingConventions: {
4308
- round: "Round"
4308
+ round: "Round",
4309
+ pre: "Pre"
4309
4310
  },
4310
4311
  qualifyingFinishMap: {
4311
4312
  1: "Final"
@@ -4349,12 +4350,11 @@ function getRoundContextProfile({
4349
4350
  const roundNamingProfile = {};
4350
4351
  const defaultRoundNamingPolicy = POLICY_ROUND_NAMING_DEFAULT[POLICY_TYPE_ROUND_NAMING];
4351
4352
  const isQualifying = structure.stage === QUALIFYING;
4352
- const qualifyingFinishgMap = isQualifying && (roundNamingPolicy?.qualifyingFinishMap || defaultRoundNamingPolicy?.qualifyingFinishMap || {});
4353
4353
  const qualifyingStageSequences = isQualifying ? Math.max(
4354
4354
  ...(drawDefinition?.structures ?? []).filter((structure2) => structure2.stage === QUALIFYING).map(({ stageSequence }) => stageSequence ?? 1),
4355
4355
  0
4356
4356
  ) : 0;
4357
- const preQualifyingSequence = qualifyingStageSequences ? qualifyingStageSequences - (structure.stageSequence || 1) || "" : "";
4357
+ const preQualifyingSequence = (structure.stageSequence ?? 1) < qualifyingStageSequences ? structure.stageSequence ?? 1 : "";
4358
4358
  const preQualifyingAffix = preQualifyingSequence ? roundNamingPolicy?.affixes?.preQualifying || defaultRoundNamingPolicy.affixes.preQualifying || "" : "";
4359
4359
  const roundNamingMap = roundNamingPolicy?.roundNamingMap || defaultRoundNamingPolicy.roundNamingMap || {};
4360
4360
  const abbreviatedRoundNamingMap = roundNamingPolicy?.abbreviatedRoundNamingMap || defaultRoundNamingPolicy.abbreviatedRoundNamingMap || {};
@@ -4378,6 +4378,7 @@ function getRoundContextProfile({
4378
4378
  })
4379
4379
  );
4380
4380
  } else {
4381
+ const qualifyingFinishgMap = isQualifying && (roundNamingPolicy?.qualifyingFinishMap || defaultRoundNamingPolicy?.qualifyingFinishMap || {});
4381
4382
  Object.assign(
4382
4383
  roundNamingProfile,
4383
4384
  ...roundProfileKeys.map((round) => {
@@ -4652,7 +4653,13 @@ function getAllStructureMatchUps({
4652
4653
  matchUps
4653
4654
  }));
4654
4655
  }
4655
- return { matchUps, roundMatchUps, roundProfile, collectionPositionMatchUps };
4656
+ return {
4657
+ collectionPositionMatchUps,
4658
+ roundMatchUps,
4659
+ roundProfile,
4660
+ matchUpsMap,
4661
+ matchUps
4662
+ };
4656
4663
  function addMatchUpContext({
4657
4664
  scheduleVisibilityFilters: scheduleVisibilityFilters2,
4658
4665
  sourceDrawPositionRanges,
@@ -9198,7 +9205,7 @@ function getContainedStructures({
9198
9205
  const containerStructures = {};
9199
9206
  const structureContainers = drawDefinitions.map((dd) => dd?.structures?.filter((structure) => structure?.structures)).flat().filter(Boolean);
9200
9207
  for (const structureContainer of structureContainers) {
9201
- const { structures, structureId } = structureContainer || {};
9208
+ const { structures, structureId } = structureContainer ?? {};
9202
9209
  structures && structureId && (containedStructures[structureId] = structures?.map(
9203
9210
  (structure) => structure.structureId
9204
9211
  )) && structures.forEach(
@@ -13214,7 +13221,10 @@ function automatedPositioning$1({
13214
13221
  return { positionAssignments, conflicts, ...SUCCESS, positioningReport };
13215
13222
  }
13216
13223
 
13217
- function getPlayoffStructures({ drawDefinition, structureId }) {
13224
+ function getPlayoffStructures({
13225
+ drawDefinition,
13226
+ structureId
13227
+ }) {
13218
13228
  if (!drawDefinition)
13219
13229
  return { error: MISSING_DRAW_DEFINITION };
13220
13230
  const { structure } = findStructure({ drawDefinition, structureId });
@@ -13333,6 +13343,7 @@ function automatedPlayoffPositioning(params) {
13333
13343
 
13334
13344
  function getStructureRoundProfile({
13335
13345
  drawDefinition,
13346
+ matchUpsMap,
13336
13347
  structureId
13337
13348
  }) {
13338
13349
  const result = findStructure({
@@ -13340,9 +13351,12 @@ function getStructureRoundProfile({
13340
13351
  structureId
13341
13352
  });
13342
13353
  if (result.error)
13343
- return result;
13344
- const { matchUps } = getAllStructureMatchUps({ structure: result.structure });
13345
- return getRoundMatchUps({ matchUps });
13354
+ return decorateResult({ result });
13355
+ const { matchUps } = getAllStructureMatchUps({
13356
+ structure: result.structure,
13357
+ matchUpsMap
13358
+ });
13359
+ return { ...getRoundMatchUps({ matchUps }), matchUps, matchUpsMap };
13346
13360
  }
13347
13361
 
13348
13362
  function getFinishingPositionSourceRoundsMap({
@@ -13393,16 +13407,18 @@ function roundValueRanges(values) {
13393
13407
 
13394
13408
  function getPositionsPlayedOff({
13395
13409
  drawDefinition,
13396
- structureIds
13410
+ structureIds,
13411
+ matchUpsMap
13397
13412
  }) {
13398
13413
  if (structureIds && !Array.isArray(structureIds))
13399
13414
  return { error: INVALID_VALUES, context: { structureIds } };
13400
13415
  if (!drawDefinition)
13401
13416
  return { error: MISSING_DRAW_DEFINITION };
13402
- structureIds = structureIds || (drawDefinition.structures || []).filter((structure) => structure.stage !== QUALIFYING).map(({ structureId }) => structureId);
13417
+ structureIds = structureIds ?? (drawDefinition.structures ?? []).filter((structure) => structure.stage !== QUALIFYING).map(({ structureId }) => structureId);
13403
13418
  const allFinishingPositionRanges = structureIds.map((structureId) => {
13404
13419
  const { roundProfile } = getStructureRoundProfile({
13405
13420
  drawDefinition,
13421
+ matchUpsMap,
13406
13422
  structureId
13407
13423
  });
13408
13424
  const values = roundProfile && Object.values(roundProfile);
@@ -13497,18 +13513,19 @@ function getPlayoffRoundsRanges({ playoffSourceRounds, roundProfile }) {
13497
13513
  function getAvailablePlayoffProfiles({ drawDefinition, structureId }) {
13498
13514
  if (!drawDefinition)
13499
13515
  return { error: MISSING_DRAW_DEFINITION };
13500
- const { positionsNotPlayedOff, positionsPlayedOff } = getPositionsPlayedOff({
13516
+ const { matchUps, matchUpsMap } = allDrawMatchUps({
13517
+ inContext: true,
13501
13518
  drawDefinition
13502
13519
  });
13520
+ const { positionsNotPlayedOff, positionsPlayedOff } = getPositionsPlayedOff({
13521
+ drawDefinition,
13522
+ matchUpsMap
13523
+ });
13503
13524
  const { structures } = getDrawStructures({ drawDefinition });
13504
13525
  const filteredStructures = structures.filter(
13505
13526
  (structure) => !structureId && structure.stage !== VOLUNTARY_CONSOLATION || structure.structureId === structureId
13506
13527
  );
13507
13528
  const available = {};
13508
- const matchUps = allDrawMatchUps({
13509
- inContext: true,
13510
- drawDefinition
13511
- }).matchUps;
13512
13529
  for (const structure of filteredStructures) {
13513
13530
  const structureId2 = structure?.structureId;
13514
13531
  const result = availablePlayoffProfiles({
@@ -13982,7 +13999,7 @@ function treeMatchUps({
13982
13999
  uuids
13983
14000
  }));
13984
14001
  roundNumber++;
13985
- roundLimit = roundLimit || qualifyingRoundNumber;
14002
+ roundLimit = roundLimit ?? qualifyingRoundNumber;
13986
14003
  while (roundNodes.length > 1) {
13987
14004
  if (qualifyingPositions && roundNodes.length === qualifyingPositions) {
13988
14005
  roundLimit = roundNumber - 1;
@@ -14010,7 +14027,7 @@ function treeMatchUps({
14010
14027
  roundLimit = roundNumber - 1;
14011
14028
  } else {
14012
14029
  matchUps = matchUps.filter(
14013
- (matchUp) => roundLimit && (matchUp.roundNumber || 0) <= roundLimit
14030
+ (matchUp) => roundLimit && (matchUp.roundNumber ?? 0) <= roundLimit
14014
14031
  );
14015
14032
  }
14016
14033
  return { drawSize, matchUps, roundsCount, roundLimit };
@@ -15506,18 +15523,17 @@ function getTallyReport({ matchUps, order, report }) {
15506
15523
  readable.push(excluded);
15507
15524
  } else {
15508
15525
  const floatSort = (a, b) => parseFloat(step.reversed ? a : b) - parseFloat(step.reversed ? b : a);
15526
+ const participantsCount = step.groups ? Object.values(step.groups).flat(Infinity).length : step.participantIds?.length ?? 0;
15509
15527
  const getExplanation = (step2) => {
15510
- Object.keys(step2.groups).sort(floatSort).forEach((key) => {
15528
+ step2.groups && Object.keys(step2.groups).sort(floatSort).forEach((key) => {
15511
15529
  const participantNames = step2.groups[key].map((participantId) => participants[participantId]).join(", ");
15512
15530
  const explanation = `${key} ${step2.attribute}: ${participantNames}`;
15513
15531
  readable.push(explanation);
15514
15532
  });
15515
15533
  };
15516
15534
  const reversed = step.reversed ? " in reverse order" : "";
15517
- const participantsCount = Object.values(step.groups).flat(
15518
- Infinity
15519
- ).length;
15520
- const description = `Step ${i + 1}: ${participantsCount} particiants were grouped${reversed} by ${step.attribute}`;
15535
+ const action = step.groups ? "grouped" : "separated";
15536
+ const description = `Step ${i + 1}: ${participantsCount} particiants were ${action}${reversed} by ${step.attribute}`;
15521
15537
  readable.push(description);
15522
15538
  if (step.idsFilter) {
15523
15539
  const note = `${step.attribute} was calculated considering ONLY TIED PARTICIPANTS`;
@@ -15533,7 +15549,7 @@ function getTallyReport({ matchUps, order, report }) {
15533
15549
  const { participantId, resolved } = orderEntry;
15534
15550
  const pOrder = orderEntry.groupOrder || orderEntry.provisionalOrder;
15535
15551
  readable.push(
15536
- `${pOrder}: ${participants[participantId]} => resolved: ${resolved}`
15552
+ `${pOrder}: ${participants[participantId]} => resolved: ${!!resolved}`
15537
15553
  );
15538
15554
  });
15539
15555
  return readable.join("\r\n");
@@ -15622,7 +15638,7 @@ function getGroupOrder(params) {
15622
15638
  report.push({ attribute, groups: orderedTallyGroups });
15623
15639
  const groupOrder = Object.keys(orderedTallyGroups).map((key) => parseFloat(key)).sort((a, b) => b - a).map((key) => orderedTallyGroups[key]).map((participantIds) => {
15624
15640
  const result = groupSubSort({ participantIds, ...params });
15625
- report.push(result.report);
15641
+ report.push(...result.report || []);
15626
15642
  return result.order;
15627
15643
  }).flat(Infinity);
15628
15644
  let groupPosition = 1;
@@ -15714,7 +15730,7 @@ function processAttribute({
15714
15730
  tallyPolicy,
15715
15731
  matchUps
15716
15732
  });
15717
- report.push(result.report);
15733
+ report.push(...result.report || []);
15718
15734
  return result.order;
15719
15735
  }).flat(Infinity);
15720
15736
  }
@@ -15728,6 +15744,9 @@ function groupSubSort({
15728
15744
  tallyPolicy,
15729
15745
  matchUps
15730
15746
  }) {
15747
+ const excludedDirectives = [];
15748
+ const report = [];
15749
+ let result;
15731
15750
  if (participantIds?.length === 1) {
15732
15751
  const participantId = participantIds[0];
15733
15752
  return {
@@ -15736,13 +15755,13 @@ function groupSubSort({
15736
15755
  }
15737
15756
  if (participantIds?.length === 2 && (!tallyPolicy?.headToHead || !tallyPolicy.headToHead.disabled && !disableHeadToHead)) {
15738
15757
  const result2 = headToHeadWinner({ participantIds, participantResults });
15739
- if (result2)
15740
- return { order: [result2], headToHeadWinner: result2[0].participantId };
15758
+ if (result2) {
15759
+ const headToHeadWinner2 = result2[0].participantId;
15760
+ report.push({ attribute: "head2Head", participantIds, headToHeadWinner: headToHeadWinner2 });
15761
+ return { order: [result2], headToHeadWinner: headToHeadWinner2, report };
15762
+ }
15741
15763
  }
15742
15764
  const directives = tallyPolicy?.tallyDirectives || headToHeadTallyDirectives;
15743
- const excludedDirectives = [];
15744
- const report = [];
15745
- let result;
15746
15765
  const filteredDirectives = directives.filter((directive) => {
15747
15766
  const keepDirective = isNumeric(directive.maxParticipants) && participantIds?.length > directive.maxParticipants ? false : true;
15748
15767
  if (!keepDirective)
@@ -16106,8 +16125,10 @@ function modifyMatchUpScore({
16106
16125
  const matchUpFilters = isDualMatchUp ? { matchUpTypes: [TEAM$2] } : void 0;
16107
16126
  const { matchUps } = getAllStructureMatchUps({
16108
16127
  afterRecoveryTimes: false,
16128
+ tournamentRecord,
16109
16129
  inContext: true,
16110
16130
  matchUpFilters,
16131
+ drawDefinition,
16111
16132
  structure: structure2,
16112
16133
  event
16113
16134
  });
@@ -19096,7 +19117,7 @@ function filterParticipants({
19096
19117
  );
19097
19118
  if (event.eventType === SINGLES)
19098
19119
  return enteredParticipantIds;
19099
- const individualParticipantIds = (tournamentRecord?.participants || []).filter(
19120
+ const individualParticipantIds = (tournamentRecord?.participants ?? []).filter(
19100
19121
  (participant) => enteredParticipantIds.includes(participant.participantId)
19101
19122
  ).map((participant) => participant.individualParticipantIds).flat(1);
19102
19123
  return enteredParticipantIds.concat(...individualParticipantIds);
@@ -20695,7 +20716,6 @@ function generateQualifyingStructures({
20695
20716
  roundTarget,
20696
20717
  linkType
20697
20718
  });
20698
- targetRoundQualifiersCount = 0;
20699
20719
  roundTarget += 1;
20700
20720
  }
20701
20721
  return {
@@ -23000,7 +23020,7 @@ function getScaledEntries({
23000
23020
  }) {
23001
23021
  if (!tournamentRecord)
23002
23022
  return { error: MISSING_TOURNAMENT_RECORD };
23003
- entries = entries || event?.entries || [];
23023
+ entries = entries ?? event?.entries ?? [];
23004
23024
  const stageEntries = entries.filter(
23005
23025
  (entry) => (!stage || !entry.entryStage || entry.entryStage === stage) && (!stageSequence || !entry.entryStageSequence || entry.entryStageSequence === stageSequence) && STRUCTURE_SELECTED_STATUSES.includes(entry.entryStatus)
23006
23026
  );
@@ -23871,7 +23891,7 @@ function generateFlightProfile(params) {
23871
23891
  } = params;
23872
23892
  if (!event)
23873
23893
  return { error: MISSING_EVENT };
23874
- const eventEntries = event.entries || [];
23894
+ const eventEntries = event.entries ?? [];
23875
23895
  const { flightProfile } = getFlightProfile({ event });
23876
23896
  if (flightProfile && attachFlightProfile$1 && !deleteExisting) {
23877
23897
  return { error: EXISTING_PROFILE };
@@ -23920,7 +23940,7 @@ function generateFlightProfile(params) {
23920
23940
  const flightNumber = index + 1;
23921
23941
  return {
23922
23942
  flightNumber,
23923
- drawId: uuids?.pop() || UUID(),
23943
+ drawId: uuids?.pop() ?? UUID(),
23924
23944
  drawEntries: getDrawEntries(splitEntries[index]),
23925
23945
  drawName: drawNames?.length && drawNames[index] || `${drawNameRoot} ${flightNumber}`
23926
23946
  };