tods-competition-factory 1.8.3 → 1.8.5

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.
@@ -319,7 +319,7 @@ function groupConsecutiveNumbers(arr) {
319
319
  return result;
320
320
  }, []);
321
321
  }
322
- function allNumeric(arr) {
322
+ function allNumeric$1(arr) {
323
323
  return arr.reduce((numeric, item) => !isNaN(parseInt(item)) && numeric, true);
324
324
  }
325
325
  function noNumeric(arr) {
@@ -587,6 +587,10 @@ const MISSING_VALUE = {
587
587
  message: "Missing value",
588
588
  code: "ERR_MISSING_VALUE"
589
589
  };
590
+ const INVALID_DATE = {
591
+ message: "Invalid Date",
592
+ code: "ERR_INVALID_DATE"
593
+ };
590
594
  const INVALID_PARTICIPANT_ID = {
591
595
  message: "Invalid participantId",
592
596
  code: "ERR_INVALID_PARTICIPANT_ID"
@@ -703,10 +707,18 @@ const INVALID_CONFIGURATION = {
703
707
  message: "Invalid configuration",
704
708
  code: "ERR_INVALID_CONFIG"
705
709
  };
710
+ const INVALID_COLLECTION_DEFINITION = {
711
+ message: "Invalid collectionDefinition",
712
+ code: "ERR_INVALID_COLLECTION_DEFINITION"
713
+ };
706
714
  const INVALID_OBJECT = {
707
715
  message: "Invalid object",
708
716
  code: "ERR_INVALID_OBJECT"
709
717
  };
718
+ const INVALID_CATEGORY = {
719
+ message: "Invalid category",
720
+ code: "ERR_INVALID_CATEGORY"
721
+ };
710
722
  const INVALID_VALUES = {
711
723
  message: "Invalid values",
712
724
  code: "ERR_INVALID_VALUES"
@@ -933,7 +945,11 @@ function deleteNotice({ key, topic }) {
933
945
  function getTopics() {
934
946
  return _globalStateProvider.getTopics();
935
947
  }
948
+ function getProvider() {
949
+ return _globalStateProvider;
950
+ }
936
951
 
952
+ const validDateString = /^[\d]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][\d]|3[0-1])$/;
937
953
  const validTimeString = /^((0[\d]|1[\d]|2[0-3]):[0-5][\d](:[0-5][\d])?)([.,][0-9]{3})?$/;
938
954
  const dateValidation = /^([\d]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][\d]|3[0-1]))([ T](0[\d]|1[\d]|2[0-3]):[0-5][\d](:[0-5][\d])?)?([.,][\d]{3})?Z?$/;
939
955
 
@@ -957,6 +973,9 @@ function isDateObject(value) {
957
973
  return datePrototype === "[object Date]";
958
974
  }
959
975
  }
976
+ function isValidDateString(scheduleDate) {
977
+ return isISODateString(scheduleDate) || validDateString.test(scheduleDate);
978
+ }
960
979
  const getUTCdateString = (date) => {
961
980
  const dateDate = isDate(date) || isISODateString(date) ? new Date(date) : /* @__PURE__ */ new Date();
962
981
  const monthNumber = dateDate.getUTCMonth() + 1;
@@ -1007,6 +1026,11 @@ function extractTime(dateString) {
1007
1026
  function extractDate(dateString) {
1008
1027
  return isISODateString(dateString) || dateValidation.test(dateString) ? dateString.split("T")[0] : void 0;
1009
1028
  }
1029
+ function dateStringDaysChange(dateString, daysChange) {
1030
+ const date = new Date(dateString);
1031
+ date.setDate(date.getDate() + daysChange);
1032
+ return extractDate(date.toISOString());
1033
+ }
1010
1034
  function splitTime(value) {
1011
1035
  value = typeof value !== "string" ? "00:00" : value;
1012
1036
  const o = {}, time = {};
@@ -1060,6 +1084,13 @@ function sameDay(date1, date2) {
1060
1084
  }
1061
1085
 
1062
1086
  function makeDeepCopy(sourceObject, convertExtensions, internalUse, removeExtensions, iteration = 0) {
1087
+ if (getProvider().makeDeepCopy)
1088
+ return getProvider().makeDeepCopy(
1089
+ sourceObject,
1090
+ convertExtensions,
1091
+ internalUse,
1092
+ removeExtensions
1093
+ );
1063
1094
  const deepCopy = deepCopyEnabled();
1064
1095
  const { stringify, toJSON, ignore, modulate } = deepCopy || {};
1065
1096
  if (!deepCopy?.enabled && !internalUse || typeof sourceObject !== "object" || typeof sourceObject === "function" || sourceObject === null || typeof deepCopy?.threshold === "number" && iteration >= deepCopy.threshold) {
@@ -2757,7 +2788,7 @@ function parse(matchUpFormatCode) {
2757
2788
  setFormat,
2758
2789
  bestOf: 1
2759
2790
  };
2760
- if (parsedFormat.setFormat)
2791
+ if (setFormat)
2761
2792
  return parsedFormat;
2762
2793
  }
2763
2794
  if (type === SET)
@@ -2767,16 +2798,23 @@ function parse(matchUpFormatCode) {
2767
2798
  }
2768
2799
  function setsMatch(formatstring) {
2769
2800
  const parts = formatstring.split("-");
2770
- const bestOf = getNumber$1(parts[0].slice(3));
2801
+ const setsCount = getNumber$1(parts[0].slice(3));
2802
+ const bestOf = setsCount === 1 || setsCount % 2 !== 0 ? setsCount : void 0;
2803
+ const exactly = setsCount !== 1 && setsCount % 2 === 0 ? setsCount : void 0;
2771
2804
  const setFormat = parts && parseSetFormat(parts[1]);
2772
2805
  const finalSetFormat = parts && parseSetFormat(parts[2]);
2773
- const validBestOf = bestOf && bestOf < 6;
2806
+ const timed = setFormat && setFormat.timed || finalSetFormat && finalSetFormat.timed;
2807
+ const validSetsCount = bestOf && bestOf < 6 || timed && exactly;
2774
2808
  const validFinalSet = !parts[2] || finalSetFormat;
2775
2809
  const validSetsFormat = setFormat;
2776
- const result = { bestOf, setFormat };
2810
+ const result = definedAttributes({
2811
+ setFormat,
2812
+ exactly,
2813
+ bestOf
2814
+ });
2777
2815
  if (finalSetFormat)
2778
2816
  result.finalSetFormat = finalSetFormat;
2779
- if (validBestOf && validSetsFormat && validFinalSet)
2817
+ if (validSetsCount && validSetsFormat && validFinalSet)
2780
2818
  return result;
2781
2819
  }
2782
2820
  function parseSetFormat(formatstring) {
@@ -3891,10 +3929,10 @@ function getOrderedDrawPositions({
3891
3929
  const pairedDrawPositions = targetRoundProfile?.pairedDrawPositions;
3892
3930
  const displayOrder = pairedDrawPositions?.find(
3893
3931
  (pair) => overlap(pair || [], drawPositions.filter(Boolean))
3894
- ) || unassignedDrawPositions;
3932
+ ) ?? unassignedDrawPositions;
3895
3933
  const isFeedRound = targetRoundProfile?.feedRound;
3896
- if (allNumeric(drawPositions)) {
3897
- const orderedDrawPositions = drawPositions.sort(numericSort);
3934
+ if (allNumeric$1(drawPositions)) {
3935
+ const orderedDrawPositions = [...drawPositions].sort(numericSort);
3898
3936
  return {
3899
3937
  orderedDrawPositions: orderedDrawPositions.length === 2 ? orderedDrawPositions : displayOrder,
3900
3938
  displayOrder: isFeedRound ? orderedDrawPositions : displayOrder
@@ -4617,7 +4655,7 @@ function getAllStructureMatchUps({
4617
4655
  matchUp,
4618
4656
  event: event2
4619
4657
  }) {
4620
- additionalContext = additionalContext || {};
4658
+ additionalContext = additionalContext ?? {};
4621
4659
  const tieFormat = resolveTieFormat({
4622
4660
  drawDefinition,
4623
4661
  structure,
@@ -4628,7 +4666,7 @@ function getAllStructureMatchUps({
4628
4666
  const collectionDefinition = matchUp.collectionId && collectionDefinitions?.find(
4629
4667
  (definition) => definition.collectionId === matchUp.collectionId
4630
4668
  );
4631
- const matchUpFormat = matchUp.collectionId ? collectionDefinition?.matchUpFormat : matchUp.matchUpFormat || structure?.matchUpFormat || drawDefinition?.matchUpFormat || event2?.matchUpFormat;
4669
+ const matchUpFormat = matchUp.collectionId ? collectionDefinition?.matchUpFormat : matchUp.matchUpFormat ?? structure?.matchUpFormat ?? drawDefinition?.matchUpFormat ?? event2?.matchUpFormat;
4632
4670
  const matchUpType = matchUp.matchUpType || collectionDefinition?.matchUpType || structure?.matchUpType || drawDefinition?.matchUpType || event2?.eventType !== TEAM$1 && event2?.eventType;
4633
4671
  const matchUpStatus = isCollectionBye ? BYE : matchUp.matchUpStatus;
4634
4672
  const { schedule, endDate } = getMatchUpScheduleDetails({
@@ -4643,7 +4681,7 @@ function getAllStructureMatchUps({
4643
4681
  });
4644
4682
  const drawPositions = tieDrawPositions ?? matchUp.drawPositions ?? [];
4645
4683
  const { collectionPosition, collectionId, roundPosition } = matchUp;
4646
- const roundNumber = matchUp.roundNumber || additionalContext.roundNumber;
4684
+ const roundNumber = matchUp.roundNumber ?? additionalContext.roundNumber;
4647
4685
  const drawPositionCollectionAssignment = collectionId ? getDrawPositionCollectionAssignment({
4648
4686
  tournamentParticipants,
4649
4687
  positionAssignments,
@@ -4669,7 +4707,7 @@ function getAllStructureMatchUps({
4669
4707
  } : context?.category;
4670
4708
  const processCodes = matchUp.processCodes?.length && matchUp.processCodes || collectionDefinition?.processCodes?.length && collectionDefinition?.processCodes || structure?.processCodes?.length && structure?.processCodes || drawDefinition?.processCodes?.length && drawDefinition?.processCodes || event2?.processCodes?.length && event2?.processCodes || tournamentRecord?.processCodes;
4671
4709
  const competitiveProfile = contextProfile?.withCompetitiveness && getMatchUpCompetitiveProfile({ ...contextContent, matchUp });
4672
- const finishingPositionRange = matchUp.finishingPositionRange || additionalContext.finishingPositionRange;
4710
+ const finishingPositionRange = matchUp.finishingPositionRange ?? additionalContext.finishingPositionRange;
4673
4711
  const onlyDefined = (obj) => definedAttributes(obj, void 0, true);
4674
4712
  const matchUpWithContext = {
4675
4713
  ...onlyDefined(context),
@@ -4677,7 +4715,7 @@ function getAllStructureMatchUps({
4677
4715
  matchUpFormat: matchUp.matchUpType === TEAM$1 ? void 0 : matchUpFormat,
4678
4716
  tieFormat: matchUp.matchUpType !== TEAM$1 ? void 0 : tieFormat,
4679
4717
  roundOfPlay: stage !== QUALIFYING && isConvertableInteger(initialRoundOfPlay2) && initialRoundOfPlay2 + (roundNumber || 0),
4680
- endDate: matchUp.endDate || endDate,
4718
+ endDate: matchUp.endDate ?? endDate,
4681
4719
  gender: collectionDefinition?.gender,
4682
4720
  discipline: event2?.discipline,
4683
4721
  category: matchUpCategory,
@@ -4997,7 +5035,7 @@ function getRoundRobinGroupMatchUps({ drawPositions }) {
4997
5035
  return { groupMatchUps, uniqueMatchUpGroupings };
4998
5036
  }
4999
5037
  function drawPositionsHash(drawPositions) {
5000
- return drawPositions.sort(numericSort).join("|");
5038
+ return [...drawPositions].sort(numericSort).join("|");
5001
5039
  }
5002
5040
  function groupRounds({ groupSize, drawPositionOffset }) {
5003
5041
  const numArr = (count) => [...Array(count)].map((_, i) => i);
@@ -5023,7 +5061,7 @@ function groupRounds({ groupSize, drawPositionOffset }) {
5023
5061
  aRow = [aHead, bUp, ...aRow].filter(Boolean);
5024
5062
  bRow = [...bRow, aDown].filter(Boolean);
5025
5063
  const sum = (x) => x[0].reduce((a, b) => a + b);
5026
- return rounds.reverse().sort((a, b) => sum(a) - sum(b)).map(
5064
+ return [...rounds].reverse().sort((a, b) => sum(a) - sum(b)).map(
5027
5065
  (round) => round.filter(
5028
5066
  (groupPositions2) => groupPositions2.every((position) => position <= groupSize)
5029
5067
  ).map((groupPositions2) => {
@@ -5035,22 +5073,25 @@ function groupRounds({ groupSize, drawPositionOffset }) {
5035
5073
  );
5036
5074
  }
5037
5075
 
5038
- function generateRoundRobin({
5039
- structureName = constantToString(MAIN),
5040
- groupNameBase = "Group",
5041
- stageSequence = 1,
5042
- structureOptions,
5043
- appliedPolicies,
5044
- seedingProfile,
5045
- stage = MAIN,
5046
- matchUpType,
5047
- roundTarget,
5048
- structureId,
5049
- drawSize,
5050
- idPrefix,
5051
- isMock,
5052
- uuids
5053
- }) {
5076
+ function generateRoundRobin(params) {
5077
+ const {
5078
+ groupNameBase = "Group",
5079
+ playoffAttributes,
5080
+ stageSequence = 1,
5081
+ structureOptions,
5082
+ appliedPolicies,
5083
+ seedingProfile,
5084
+ stage = MAIN,
5085
+ matchUpType,
5086
+ roundTarget,
5087
+ structureId,
5088
+ groupNames,
5089
+ drawSize,
5090
+ idPrefix,
5091
+ isMock,
5092
+ uuids
5093
+ } = params;
5094
+ const structureName = params.structureName ?? playoffAttributes?.["0"]?.name ?? constantToString(MAIN);
5054
5095
  const { groupCount, groupSize } = deriveGroups({
5055
5096
  structureOptions,
5056
5097
  appliedPolicies,
@@ -5070,12 +5111,13 @@ function generateRoundRobin({
5070
5111
  maxRoundNumber = Math.max(
5071
5112
  ...matchUps.map(({ roundNumber }) => roundNumber)
5072
5113
  );
5114
+ const structureName2 = groupNames?.[structureOrder - 1] ?? `${groupNameBase} ${structureOrder}`;
5073
5115
  return structureTemplate({
5074
- structureName: `${groupNameBase} ${structureOrder}`,
5075
5116
  structureId: uuids?.pop(),
5076
5117
  structureType: ITEM,
5077
5118
  finishingPosition,
5078
5119
  structureOrder,
5120
+ structureName: structureName2,
5079
5121
  matchUps
5080
5122
  });
5081
5123
  });
@@ -8104,10 +8146,10 @@ function addUpcomingMatchUps({ drawDefinition, inContextDrawMatchUps }) {
8104
8146
  if (structure?.finishingPosition === WIN_RATIO) {
8105
8147
  const { roundNumber } = inContextMatchUp;
8106
8148
  const nextRoundNumber = roundNumber && ensureInt(roundNumber) + 1;
8107
- const matchUps = structure.matchUps || [];
8149
+ const matchUps = structure.matchUps ?? [];
8108
8150
  const { roundMatchUps } = getRoundMatchUps({ matchUps });
8109
8151
  if (nextRoundNumber && roundMatchUps?.[nextRoundNumber]) {
8110
- const sidesTo = drawPositions.sort().map((drawPosition, index) => {
8152
+ const sidesTo = [...drawPositions].sort(numericSort).map((drawPosition, index) => {
8111
8153
  const nextRoundMatchUp = roundMatchUps[nextRoundNumber].find(
8112
8154
  (matchUp) => matchUp.drawPositions?.includes(drawPosition)
8113
8155
  );
@@ -14261,7 +14303,7 @@ function generatePlayoffStructures(params) {
14261
14303
  const attributeProfile = playoffAttributes?.[exitProfile];
14262
14304
  const base = playoffStructureNameBase && `${playoffStructureNameBase} ` || "";
14263
14305
  const customNaming = playoffAttributes?.[finishingPositionRange] ?? finishingPositionNaming?.[finishingPositionRange];
14264
- const structureName = customNaming?.name || attributeProfile?.name && (addNameBaseToAttributeName ? `${base}${attributeProfile?.name}` : attributeProfile.name) || `${base}${finishingPositionRange}`;
14306
+ const structureName = params.structureName || customNaming?.name || attributeProfile?.name && (addNameBaseToAttributeName ? `${base}${attributeProfile?.name}` : attributeProfile.name) || `${base}${finishingPositionRange}`;
14265
14307
  const structureAbbreviation = customNaming?.abbreviation || attributeProfile?.abbreviation;
14266
14308
  const mainParams = {
14267
14309
  idPrefix: idPrefix && `${idPrefix}-${structureName}-RP`,
@@ -14417,12 +14459,14 @@ function feedInChampionship(params) {
14417
14459
  fmlc
14418
14460
  });
14419
14461
  if (drawSize > 2) {
14462
+ const name = playoffAttributes?.["0-1"]?.name ?? constantToString(CONSOLATION);
14463
+ const structureName2 = params.playoffStructureNameBase ? `${params.playoffStructureNameBase} ${name}` : name;
14420
14464
  const consolationStructure = structureTemplate({
14421
- structureName: playoffAttributes?.["0-1"]?.name ?? constantToString(CONSOLATION),
14422
14465
  matchUps: consolationMatchUps,
14423
14466
  structureId: uuids?.pop(),
14424
14467
  stage: CONSOLATION,
14425
14468
  stageSequence: 1,
14469
+ structureName: structureName2,
14426
14470
  matchUpType
14427
14471
  });
14428
14472
  structures.push(consolationStructure);
@@ -14568,8 +14612,9 @@ function processPlayoffGroups({
14568
14612
  } else if ([COMPASS, OLYMPIC, PLAY_OFF].includes(playoffDrawType)) {
14569
14613
  const params2 = {
14570
14614
  playoffAttributes: playoffGroup.playoffAttributes ?? playoffAttributes,
14615
+ playoffStructureNameBase: playoffGroup.playoffStructureNameBase,
14571
14616
  structureId: playoffGroup.structureId ?? uuids?.pop(),
14572
- playoffStructureNameBase: structureName,
14617
+ structureName: playoffGroup.structureName,
14573
14618
  idPrefix: idPrefix && `${idPrefix}-po`,
14574
14619
  addNameBaseToAttributeName: true,
14575
14620
  finishingPositionOffset,
@@ -14622,7 +14667,9 @@ function processPlayoffGroups({
14622
14667
  ].includes(playoffDrawType)) {
14623
14668
  const uuidsFMLC = [uuids?.pop(), uuids?.pop()];
14624
14669
  const params2 = {
14670
+ playoffStructureNameBase: playoffGroup.playoffStructureNameBase,
14625
14671
  structureId: playoffGroup.structureId ?? uuids?.pop(),
14672
+ playoffAttributes: playoffGroup.playoffAttributes,
14626
14673
  idPrefix: idPrefix && `${idPrefix}-po`,
14627
14674
  finishingPositionOffset,
14628
14675
  uuids: uuidsFMLC,
@@ -16164,12 +16211,212 @@ function drawPositionsAssignedParticipantIds({ structure, matchUp }) {
16164
16211
  return assignedParticipantIds?.length === 2;
16165
16212
  }
16166
16213
 
16214
+ const typeMatch = (arr, type) => arr.filter(Boolean).every((i) => typeof i === type);
16215
+ const allNumeric = (arr) => arr.filter(Boolean).every(isNumeric);
16216
+ function getCategoryAgeDetails(params) {
16217
+ const category = params.category;
16218
+ if (typeof category !== "object")
16219
+ return { error: INVALID_CATEGORY };
16220
+ let { ageCategoryCode, ageMaxDate, ageMinDate, ageMax, ageMin } = category;
16221
+ const categoryName = category.categoryName;
16222
+ let combinedAge;
16223
+ if (!typeMatch(
16224
+ [ageCategoryCode, ageMaxDate, ageMinDate, categoryName],
16225
+ "string"
16226
+ ) || !allNumeric(
16227
+ [ageMax, ageMin]
16228
+ ))
16229
+ return { error: INVALID_CATEGORY };
16230
+ const consideredDate = params.consideredDate ?? extractDate((/* @__PURE__ */ new Date()).toLocaleDateString("sv"));
16231
+ if (!isValidDateString(consideredDate))
16232
+ return { error: INVALID_DATE };
16233
+ const [consideredYear] = consideredDate.split("-").slice(0, 3).map((n) => parseInt(n));
16234
+ const previousDayDate = dateStringDaysChange(consideredDate, -1);
16235
+ const [previousDayMonth, previousDay] = previousDayDate.split("-").slice(1, 3).map((n) => parseInt(n));
16236
+ const previousMonthDay = `${zeroPad(previousDayMonth)}-${zeroPad(
16237
+ previousDay
16238
+ )}`;
16239
+ const nextDayDate = dateStringDaysChange(consideredDate, 1);
16240
+ const [nextDayMonth, nextDay] = nextDayDate.split("-").slice(1, 3).map((n) => parseInt(n));
16241
+ const nextMonthDay = `${zeroPad(nextDayMonth)}-${zeroPad(nextDay)}`;
16242
+ let calculatedAgeMaxDate = ageMin && dateStringDaysChange(consideredDate, -1 * 365 * ageMin);
16243
+ let calculatedAgeMinDate = ageMax && dateStringDaysChange(consideredDate, -1 * 365 * ageMax);
16244
+ const errors = [];
16245
+ const addError = (errorString) => !errors.includes(errorString) && errors.push(errorString);
16246
+ ageCategoryCode = ageCategoryCode ?? categoryName;
16247
+ const prePost = /^([UO]?)(\d{1,2})([UO]?)$/;
16248
+ const extractCombined = /^C(\d{1,2})-(\d{1,2})$/;
16249
+ const isBetween = ageCategoryCode?.includes("-");
16250
+ const isCombined = isBetween && ageCategoryCode?.match(extractCombined);
16251
+ const isCoded = ageCategoryCode?.match(prePost);
16252
+ const constructedDate = (y, df) => `${y}-${df}`;
16253
+ const uPre = (ageInt) => {
16254
+ const ageMinYear = consideredYear - ageInt;
16255
+ const newMinDate = constructedDate(ageMinYear, nextMonthDay);
16256
+ if (category.ageMinDate && category.ageMinDate !== newMinDate)
16257
+ addError(`Invalid submitted ageMinDate: ${ageMinDate}`);
16258
+ ageMinDate = newMinDate;
16259
+ if (ageCategoryCode) {
16260
+ if (category.ageMax && category.ageMax !== ageInt - 1) {
16261
+ addError(`Invalid submitted ageMax: ${ageMax}`);
16262
+ calculatedAgeMinDate = void 0;
16263
+ }
16264
+ ageMax = ageInt - 1;
16265
+ }
16266
+ };
16267
+ const uPost = (ageInt) => {
16268
+ const ageMinYear = consideredYear - ageInt - 1;
16269
+ const newMinDate = constructedDate(ageMinYear, nextMonthDay);
16270
+ if (category.ageMin && category.ageMin > ageInt) {
16271
+ addError(`Invalid submitted ageMin: ${ageMin}`);
16272
+ }
16273
+ if (category.ageMax && category.ageMax > ageInt) {
16274
+ addError(`Invalid submitted ageMax: ${ageMax}`);
16275
+ }
16276
+ if (category.ageMinDate && category.ageMinDate !== newMinDate)
16277
+ addError(`Invalid submitted ageMinDate: ${ageMinDate}`);
16278
+ ageMinDate = newMinDate;
16279
+ if (ageCategoryCode) {
16280
+ if (category.ageMax && category.ageMax !== ageInt) {
16281
+ addError(`Invalid submitted ageMax: ${ageMax}`);
16282
+ calculatedAgeMaxDate = void 0;
16283
+ }
16284
+ ageMax = ageInt;
16285
+ }
16286
+ };
16287
+ const oPre = (ageInt) => {
16288
+ const ageMaxYear = consideredYear - ageInt;
16289
+ const newMaxDate = constructedDate(ageMaxYear, previousMonthDay);
16290
+ if (category.ageMaxDate && category.ageMaxDate !== newMaxDate)
16291
+ addError(`Invalid submitted ageMaxDate: ${ageMaxDate}`);
16292
+ ageMaxDate = newMaxDate;
16293
+ if (ageCategoryCode) {
16294
+ if (category.ageMin && category.ageMin !== ageInt + 1) {
16295
+ addError(`Invalid submitted ageMin: ${ageMin}`);
16296
+ calculatedAgeMaxDate = void 0;
16297
+ }
16298
+ ageMin = ageInt + 1;
16299
+ }
16300
+ };
16301
+ const oPost = (ageInt) => {
16302
+ const ageMaxYear = consideredYear - ageInt - 1;
16303
+ const newMaxDate = constructedDate(ageMaxYear, previousMonthDay);
16304
+ if (category.ageMaxDate && category.ageMaxDate !== newMaxDate)
16305
+ addError(`Invalid submitted ageMaxDate: ${ageMaxDate}`);
16306
+ ageMaxDate = newMaxDate;
16307
+ if (ageCategoryCode) {
16308
+ if (category.ageMin && category.ageMin !== ageInt) {
16309
+ addError(`Invalid submitted ageMin: ${ageMin}`);
16310
+ calculatedAgeMaxDate = void 0;
16311
+ }
16312
+ ageMin = ageInt;
16313
+ }
16314
+ };
16315
+ const processCode = (code) => {
16316
+ const [pre, age, post] = (code.match(prePost) || []).slice(1);
16317
+ const ageInt = parseInt(age);
16318
+ if (pre === "U") {
16319
+ if (category.ageMaxDate && category.ageMaxDate !== ageMaxDate) {
16320
+ addError(`Invalid submitted ageMaxDate: ${category.ageMaxDate}`);
16321
+ }
16322
+ uPre(ageInt);
16323
+ } else if (pre === "O") {
16324
+ oPre(ageInt);
16325
+ }
16326
+ if (post === "U") {
16327
+ if (category.ageMaxDate && category.ageMaxDate !== ageMaxDate) {
16328
+ addError(`Invalid submitted ageMaxDate: ${category.ageMaxDate}`);
16329
+ }
16330
+ uPost(ageInt);
16331
+ } else if (post === "O") {
16332
+ oPost(ageInt);
16333
+ }
16334
+ ageMaxDate = ageMaxDate ?? calculatedAgeMaxDate;
16335
+ ageMinDate = ageMinDate ?? calculatedAgeMinDate;
16336
+ };
16337
+ if (isCombined) {
16338
+ ageMaxDate = void 0;
16339
+ ageMinDate = void 0;
16340
+ ageMax = void 0;
16341
+ ageMin = void 0;
16342
+ if (category.ageMin) {
16343
+ const ageMaxYear = consideredYear - category.ageMin;
16344
+ ageMaxDate = constructedDate(ageMaxYear, previousMonthDay);
16345
+ }
16346
+ if (category.ageMax) {
16347
+ const ageMinYear = consideredYear - category.ageMax - 1;
16348
+ ageMinDate = constructedDate(ageMinYear, nextMonthDay);
16349
+ }
16350
+ const [lowAge, highAge] = (ageCategoryCode?.match(extractCombined) ?? []).slice(1).map((n) => parseInt(n));
16351
+ if (lowAge <= highAge) {
16352
+ ageMin = lowAge;
16353
+ ageMax = highAge;
16354
+ combinedAge = true;
16355
+ } else {
16356
+ addError(`Invalid combined age range ${ageCategoryCode}`);
16357
+ }
16358
+ } else if (isBetween) {
16359
+ ageCategoryCode?.split("-").forEach(processCode);
16360
+ } else if (isCoded) {
16361
+ processCode(ageCategoryCode);
16362
+ } else {
16363
+ if (ageMin)
16364
+ oPre(ageMin);
16365
+ if (ageMax)
16366
+ uPost(ageMax);
16367
+ }
16368
+ if (ageMax && category.ageMin && category.ageMin > ageMax) {
16369
+ addError(`Invalid submitted ageMin: ${category.ageMin}`);
16370
+ ageMin = void 0;
16371
+ }
16372
+ const result = definedAttributes({
16373
+ consideredDate,
16374
+ combinedAge,
16375
+ ageMaxDate,
16376
+ ageMinDate,
16377
+ ageMax,
16378
+ ageMin
16379
+ });
16380
+ if (errors.length)
16381
+ result.errors = errors;
16382
+ return result;
16383
+ }
16384
+
16385
+ function categoryCanContain({
16386
+ childCategory,
16387
+ withDetails,
16388
+ category
16389
+ }) {
16390
+ const categoryDetails = getCategoryAgeDetails({ category });
16391
+ const childCategoryDetails = getCategoryAgeDetails({
16392
+ category: childCategory
16393
+ });
16394
+ const invalidAgeMin = childCategoryDetails.ageMin && (categoryDetails.ageMin && childCategoryDetails.ageMin < categoryDetails.ageMin || categoryDetails.ageMax && childCategoryDetails.ageMin > categoryDetails.ageMax);
16395
+ const invalidAgeMax = childCategoryDetails.ageMax && (categoryDetails.ageMax && childCategoryDetails.ageMax > categoryDetails.ageMax || categoryDetails.ageMin && childCategoryDetails.ageMax < categoryDetails.ageMin);
16396
+ const invalidAgeMinDate = childCategoryDetails.ageMinDate && categoryDetails.ageMaxDate && new Date(childCategoryDetails.ageMinDate) > new Date(categoryDetails.ageMaxDate);
16397
+ const invalidAgeMaxDate = childCategoryDetails.ageMaxDate && categoryDetails.ageMinDate && new Date(childCategoryDetails.ageMaxDate) < new Date(categoryDetails.ageMinDate);
16398
+ const valid = !invalidAgeMax && !invalidAgeMin && !invalidAgeMinDate && !invalidAgeMaxDate;
16399
+ const ignoreFalse = true;
16400
+ const result = definedAttributes(
16401
+ {
16402
+ valid,
16403
+ invalidAgeMax,
16404
+ invalidAgeMin,
16405
+ invalidAgeMinDate,
16406
+ invalidAgeMaxDate
16407
+ },
16408
+ ignoreFalse
16409
+ );
16410
+ if (withDetails) {
16411
+ Object.assign(result, { categoryDetails, childCategoryDetails });
16412
+ }
16413
+ return result;
16414
+ }
16415
+
16167
16416
  function stringify(matchUpFormatObject, preserveRedundant) {
16168
16417
  if (typeof matchUpFormatObject !== "object")
16169
16418
  return;
16170
- if (matchUpFormatObject.timed && !isNaN(matchUpFormatObject.minutes))
16171
- return timedSetFormat(matchUpFormatObject);
16172
- if (matchUpFormatObject.bestOf && matchUpFormatObject.setFormat)
16419
+ if ((matchUpFormatObject.bestOf || matchUpFormatObject.exactly) && matchUpFormatObject.setFormat)
16173
16420
  return getSetFormat(matchUpFormatObject, preserveRedundant);
16174
16421
  return void 0;
16175
16422
  }
@@ -16185,11 +16432,13 @@ function timedSetFormat(matchUpFormatObject) {
16185
16432
  return value;
16186
16433
  }
16187
16434
  function getSetFormat(matchUpFormatObject, preserveRedundant) {
16188
- const bestOfValue = getNumber(matchUpFormatObject.bestOf);
16189
- if (matchUpFormatObject.setFormat?.timed && matchUpFormatObject.simplified && bestOfValue === 1) {
16435
+ const bestOfValue = getNumber(matchUpFormatObject.bestOf) || void 0;
16436
+ const exactly = getNumber(matchUpFormatObject.exactly) || void 0;
16437
+ const setLimit = bestOfValue || exactly;
16438
+ if (matchUpFormatObject.setFormat?.timed && matchUpFormatObject.simplified && setLimit === 1) {
16190
16439
  return timedSetFormat(matchUpFormatObject.setFormat);
16191
16440
  }
16192
- const bestOfCode = bestOfValue && `${SET}${bestOfValue}` || "";
16441
+ const setLimitCode = setLimit && `${SET}${setLimit}` || "";
16193
16442
  const setCountValue = stringifySet(
16194
16443
  matchUpFormatObject.setFormat,
16195
16444
  preserveRedundant
@@ -16199,11 +16448,11 @@ function getSetFormat(matchUpFormatObject, preserveRedundant) {
16199
16448
  matchUpFormatObject.finalSetFormat,
16200
16449
  preserveRedundant
16201
16450
  );
16202
- const finalSetCode = bestOfValue && bestOfValue > 1 && finalSetCountValue && setCountValue !== finalSetCountValue && // don't include final set code if equivalent to other sets
16451
+ const finalSetCode = setLimit && setLimit > 1 && finalSetCountValue && setCountValue !== finalSetCountValue && // don't include final set code if equivalent to other sets
16203
16452
  `F:${finalSetCountValue}` || "";
16204
- const valid = bestOfCode && setCountValue;
16453
+ const valid = setLimitCode && setCountValue;
16205
16454
  if (valid) {
16206
- return [bestOfCode, setCode, finalSetCode].filter((f) => f).join("-");
16455
+ return [setLimitCode, setCode, finalSetCode].filter((f) => f).join("-");
16207
16456
  }
16208
16457
  return void 0;
16209
16458
  }
@@ -16272,6 +16521,7 @@ const matchUpFormatCode = {
16272
16521
  };
16273
16522
 
16274
16523
  function validateTieFormat(params) {
16524
+ const checkCategory = !!(params?.enforceCategory !== false && params?.category);
16275
16525
  const checkGender = !!(params?.enforceGender !== false && params?.gender);
16276
16526
  const checkCollectionIds = params?.checkCollectionIds;
16277
16527
  const tieFormat = params?.tieFormat;
@@ -16308,9 +16558,11 @@ function validateTieFormat(params) {
16308
16558
  if ((setValue || scoreValue) && !collectionValue)
16309
16559
  aggregateValueImperative = true;
16310
16560
  const { valid: valid2, errors: collectionDefinitionErrors } = validateCollectionDefinition({
16561
+ referenceCategory: params.category,
16311
16562
  referenceGender: params.gender,
16312
16563
  collectionDefinition,
16313
16564
  checkCollectionIds,
16565
+ checkCategory,
16314
16566
  checkGender
16315
16567
  });
16316
16568
  if (valid2) {
@@ -16352,19 +16604,22 @@ function validateTieFormat(params) {
16352
16604
  return result;
16353
16605
  }
16354
16606
  function validateCollectionDefinition({
16607
+ checkCategory = true,
16355
16608
  collectionDefinition,
16356
16609
  checkCollectionIds,
16357
16610
  checkGender = true,
16611
+ referenceCategory,
16358
16612
  referenceGender,
16359
16613
  event
16360
16614
  }) {
16361
16615
  referenceGender = referenceGender ?? event?.gender;
16616
+ const stack = "validateCollectionDefinition";
16362
16617
  const errors = [];
16363
16618
  if (typeof collectionDefinition !== "object") {
16364
16619
  errors.push(
16365
16620
  `collectionDefinition must be an object: ${collectionDefinition}`
16366
16621
  );
16367
- return { errors, error: INVALID_OBJECT };
16622
+ return decorateResult({ result: { errors, error: INVALID_OBJECT }, stack });
16368
16623
  }
16369
16624
  const {
16370
16625
  collectionValueProfiles,
@@ -16377,6 +16632,7 @@ function validateCollectionDefinition({
16377
16632
  matchUpType,
16378
16633
  scoreValue,
16379
16634
  setValue,
16635
+ category,
16380
16636
  gender
16381
16637
  } = collectionDefinition;
16382
16638
  if (checkCollectionIds && typeof collectionId !== "string") {
@@ -16422,8 +16678,23 @@ function validateCollectionDefinition({
16422
16678
  if (checkGender && referenceGender && gender && [GenderEnum.Male, GenderEnum.Female].includes(referenceGender) && referenceGender !== gender) {
16423
16679
  errors.push(`Invalid gender: ${gender}`);
16424
16680
  }
16681
+ if (checkCategory && referenceCategory && category) {
16682
+ const result = categoryCanContain({
16683
+ category: referenceCategory,
16684
+ childCategory: category
16685
+ });
16686
+ if (!result.valid)
16687
+ return decorateResult({
16688
+ result: { error: INVALID_CATEGORY },
16689
+ context: result,
16690
+ stack
16691
+ });
16692
+ }
16425
16693
  if (errors.length)
16426
- return { errors, error: INVALID_OBJECT };
16694
+ return decorateResult({
16695
+ result: { errors, error: INVALID_COLLECTION_DEFINITION },
16696
+ stack
16697
+ });
16427
16698
  return { valid: true };
16428
16699
  }
16429
16700
  function checkTieFormat(tieFormat) {
@@ -19111,7 +19382,7 @@ function generateRoundRobinWithPlayOff(params) {
19111
19382
  };
19112
19383
  const { structures, groupCount, groupSize } = generateRoundRobin(mainDrawProperties);
19113
19384
  if (groupCount < 1) {
19114
- console.log(INVALID_CONFIGURATION);
19385
+ return { error: INVALID_CONFIGURATION };
19115
19386
  }
19116
19387
  const playoffGroups = structureOptions?.playoffGroups || [
19117
19388
  { finishingPositions: [1], structureName: constantToString(PLAY_OFF) }
@@ -22715,8 +22986,8 @@ function prepareStage(params) {
22715
22986
  });
22716
22987
  if (!scaledEntries?.length && seedByRanking) {
22717
22988
  const rankingScaleAttributes = {
22718
- scaleType: RANKING,
22719
22989
  scaleName: categoryName || ageCategoryCode,
22990
+ scaleType: RANKING,
22720
22991
  eventType
22721
22992
  };
22722
22993
  ({ scaledEntries } = getScaledEntries({