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.
package/dist/index.mjs CHANGED
@@ -11,9 +11,7 @@ const setTypes$1 = {
11
11
  function stringify(matchUpFormatObject, preserveRedundant) {
12
12
  if (typeof matchUpFormatObject !== "object")
13
13
  return;
14
- if (matchUpFormatObject.timed && !isNaN(matchUpFormatObject.minutes))
15
- return timedSetFormat(matchUpFormatObject);
16
- if (matchUpFormatObject.bestOf && matchUpFormatObject.setFormat)
14
+ if ((matchUpFormatObject.bestOf || matchUpFormatObject.exactly) && matchUpFormatObject.setFormat)
17
15
  return getSetFormat(matchUpFormatObject, preserveRedundant);
18
16
  return void 0;
19
17
  }
@@ -29,11 +27,13 @@ function timedSetFormat(matchUpFormatObject) {
29
27
  return value;
30
28
  }
31
29
  function getSetFormat(matchUpFormatObject, preserveRedundant) {
32
- const bestOfValue = getNumber$1(matchUpFormatObject.bestOf);
33
- if (matchUpFormatObject.setFormat?.timed && matchUpFormatObject.simplified && bestOfValue === 1) {
30
+ const bestOfValue = getNumber$1(matchUpFormatObject.bestOf) || void 0;
31
+ const exactly = getNumber$1(matchUpFormatObject.exactly) || void 0;
32
+ const setLimit = bestOfValue || exactly;
33
+ if (matchUpFormatObject.setFormat?.timed && matchUpFormatObject.simplified && setLimit === 1) {
34
34
  return timedSetFormat(matchUpFormatObject.setFormat);
35
35
  }
36
- const bestOfCode = bestOfValue && `${SET}${bestOfValue}` || "";
36
+ const setLimitCode = setLimit && `${SET}${setLimit}` || "";
37
37
  const setCountValue = stringifySet(
38
38
  matchUpFormatObject.setFormat,
39
39
  preserveRedundant
@@ -43,11 +43,11 @@ function getSetFormat(matchUpFormatObject, preserveRedundant) {
43
43
  matchUpFormatObject.finalSetFormat,
44
44
  preserveRedundant
45
45
  );
46
- const finalSetCode = bestOfValue && bestOfValue > 1 && finalSetCountValue && setCountValue !== finalSetCountValue && // don't include final set code if equivalent to other sets
46
+ const finalSetCode = setLimit && setLimit > 1 && finalSetCountValue && setCountValue !== finalSetCountValue && // don't include final set code if equivalent to other sets
47
47
  `F:${finalSetCountValue}` || "";
48
- const valid = bestOfCode && setCountValue;
48
+ const valid = setLimitCode && setCountValue;
49
49
  if (valid) {
50
- return [bestOfCode, setCode, finalSetCode].filter((f) => f).join("-");
50
+ return [setLimitCode, setCode, finalSetCode].filter((f) => f).join("-");
51
51
  }
52
52
  return void 0;
53
53
  }
@@ -171,235 +171,6 @@ function skewedDistribution(min, max, skew, step, significantDecimals = 2) {
171
171
  return parseFloat(num.toFixed(significantDecimals));
172
172
  }
173
173
 
174
- function parse(matchUpFormatCode) {
175
- if (typeof matchUpFormatCode === "string") {
176
- const type = matchUpFormatCode.startsWith("T") && TIMED || matchUpFormatCode.startsWith(SET) && SET || "";
177
- if (type === TIMED) {
178
- const setFormat = parseTimedSet(matchUpFormatCode);
179
- const parsedFormat = {
180
- simplified: true,
181
- setFormat,
182
- bestOf: 1
183
- };
184
- if (parsedFormat.setFormat)
185
- return parsedFormat;
186
- }
187
- if (type === SET)
188
- return setsMatch(matchUpFormatCode);
189
- }
190
- return void 0;
191
- }
192
- function setsMatch(formatstring) {
193
- const parts = formatstring.split("-");
194
- const bestOf = getNumber(parts[0].slice(3));
195
- const setFormat = parts && parseSetFormat(parts[1]);
196
- const finalSetFormat = parts && parseSetFormat(parts[2]);
197
- const validBestOf = bestOf && bestOf < 6;
198
- const validFinalSet = !parts[2] || finalSetFormat;
199
- const validSetsFormat = setFormat;
200
- const result = { bestOf, setFormat };
201
- if (finalSetFormat)
202
- result.finalSetFormat = finalSetFormat;
203
- if (validBestOf && validSetsFormat && validFinalSet)
204
- return result;
205
- }
206
- function parseSetFormat(formatstring) {
207
- if (formatstring?.[1] === ":") {
208
- const parts = formatstring.split(":");
209
- const setType = setTypes$1[parts[0]];
210
- const setFormatString = parts[1];
211
- if (setType && setFormatString) {
212
- const isTiebreakSet = setFormatString.indexOf("TB") === 0;
213
- if (isTiebreakSet) {
214
- const tiebreakSet = parseTiebreakFormat(setFormatString);
215
- if (tiebreakSet === false)
216
- return false;
217
- return typeof tiebreakSet === "object" ? { tiebreakSet } : void 0;
218
- }
219
- const timedSet = setFormatString.indexOf("T") === 0;
220
- if (timedSet)
221
- return parseTimedSet(setFormatString);
222
- const parts2 = formatstring.match(/^[FS]:(\d+)([A-Za-z]*)/);
223
- const NoAD = parts2 && isNoAD(parts2[2]) || false;
224
- const validNoAD = !parts2?.[2] || NoAD;
225
- const setTo = parts2 ? getNumber(parts2[1]) : void 0;
226
- const tiebreakAtValue = parseTiebreakAt(setFormatString);
227
- const validTiebreakAt = tiebreakAtValue !== false;
228
- const tiebreakAt = validTiebreakAt && tiebreakAtValue || setTo;
229
- const tiebreakFormat = parseTiebreakFormat(setFormatString.split("/")[1]);
230
- const validTiebreak = tiebreakFormat !== false;
231
- const result = { setTo };
232
- if (NoAD)
233
- result.NoAD = true;
234
- if (tiebreakFormat) {
235
- result.tiebreakFormat = tiebreakFormat;
236
- result.tiebreakAt = tiebreakAt;
237
- } else {
238
- result.noTiebreak = true;
239
- }
240
- return setTo && validNoAD && validTiebreak && validTiebreakAt && result || false;
241
- }
242
- }
243
- return void 0;
244
- }
245
- function parseTiebreakAt(setFormatString, expectNumber = true) {
246
- const tiebreakAtValue = setFormatString?.indexOf("@") > 0 && setFormatString.split("@");
247
- if (tiebreakAtValue) {
248
- const tiebreakAt = expectNumber ? getNumber(tiebreakAtValue[1]) : tiebreakAtValue[1];
249
- return tiebreakAt || false;
250
- }
251
- return void 0;
252
- }
253
- function parseTiebreakFormat(formatstring) {
254
- if (formatstring) {
255
- if (formatstring.startsWith("TB")) {
256
- const modifier = parseTiebreakAt(formatstring, false);
257
- const parts = formatstring.match(/^TB(\d+)([A-Za-z]*)/);
258
- const tiebreakToString = parts?.[1];
259
- const NoAD = parts && isNoAD(parts[2]);
260
- const validNoAD = !parts?.[2] || NoAD;
261
- const tiebreakTo = getNumber(tiebreakToString);
262
- if (tiebreakTo && validNoAD) {
263
- const result = { tiebreakTo };
264
- if (modifier && typeof modifier === "string" && !isConvertableInteger(modifier)) {
265
- result.modifier = modifier;
266
- }
267
- if (NoAD)
268
- result.NoAD = true;
269
- return result;
270
- } else {
271
- return false;
272
- }
273
- } else {
274
- return false;
275
- }
276
- }
277
- return void 0;
278
- }
279
- function parseTimedSet(formatstring) {
280
- const timestring = formatstring.slice(1);
281
- const parts = timestring.match(/^(\d+)(@?[A-Za-z]*)/);
282
- const minutes = getNumber(parts?.[1]);
283
- if (!minutes)
284
- return;
285
- const setFormat = { timed: true, minutes };
286
- const based = parts?.[2];
287
- const validModifier = [void 0, "P", "G"].includes(based);
288
- if (based && !validModifier) {
289
- const modifier = timestring.match(/^(\d+)(@)([A-Za-z]+)$/)?.[3];
290
- if (modifier) {
291
- setFormat.modifier = modifier;
292
- return setFormat;
293
- }
294
- return;
295
- }
296
- if (based)
297
- setFormat.based = parts[2];
298
- return setFormat;
299
- }
300
- function isNoAD(formatstring) {
301
- return formatstring && formatstring.indexOf(NOAD) >= 0;
302
- }
303
- function getNumber(formatstring) {
304
- return !isNaN(Number(formatstring)) ? Number(formatstring) : 0;
305
- }
306
-
307
- function isValid(matchUpFormat) {
308
- if (typeof matchUpFormat !== "string")
309
- return false;
310
- const parsedFormat = parse(matchUpFormat);
311
- const setParts = matchUpFormat.match(
312
- /-S:([1-9])+\/TB([0-9]{1,2})@?([1-9]?)*/
313
- );
314
- const setsTo = setParts?.[1];
315
- const tiebreakTo = setParts?.[2];
316
- const tiebreakAt = setParts?.[3];
317
- const finalSetParts = matchUpFormat.match(
318
- /-F:([1-9])+\/TB([0-9]{1,2})@?([1-9]?)*/
319
- );
320
- const finalSetTo = finalSetParts?.[1];
321
- const finalSetTiebreakTo = finalSetParts?.[2];
322
- const finalTiebreakAt = finalSetParts?.[3];
323
- const preserveRedundant = !!(setParts && tiebreakTo && setsTo === tiebreakAt || finalSetParts && finalSetTiebreakTo && finalSetTo === finalTiebreakAt);
324
- const stringified = stringify(parsedFormat, preserveRedundant);
325
- return stringified === matchUpFormat;
326
- }
327
-
328
- const matchUpFormatCode = {
329
- isValidMatchUpFormat: isValid,
330
- stringify,
331
- isValid,
332
- parse
333
- };
334
-
335
- function factoryVersion() {
336
- return "1.8.3";
337
- }
338
-
339
- function getObjectTieFormat(obj) {
340
- if (!obj)
341
- return;
342
- const { tieFormatId, tieFormats } = obj;
343
- if (obj.tieFormat) {
344
- return obj.tieFormat;
345
- } else if (tieFormatId && Array.isArray(tieFormats)) {
346
- return tieFormats.find((tf) => tf.tieFormatId === tieFormatId);
347
- }
348
- }
349
-
350
- function getItemTieFormat({ item, drawDefinition, structure, event }) {
351
- if (!item)
352
- return;
353
- if (item.tieFormat)
354
- return item.tieFormat;
355
- if (item.tieFormatId) {
356
- if (drawDefinition.tieFormat)
357
- return drawDefinition.tieFormat;
358
- const tieFormat = drawDefinition.tieFormats?.find(
359
- (tf) => item.tieFormatId === tf.tieFormatId
360
- );
361
- if (tieFormat)
362
- return tieFormat;
363
- if (event.tieFormat)
364
- return event.tieFormat;
365
- return event.tieFormats?.find((tf) => item.tieFormatId === tf.tieFormatId);
366
- }
367
- if (structure.tieFormat)
368
- return structure.tieFormat;
369
- if (structure.tieFormatId) {
370
- const structureTieFormat = drawDefinition.tieFormats?.find(
371
- (tf) => structure.tieFormatId === tf.tieFormatId
372
- );
373
- if (structureTieFormat)
374
- return structureTieFormat;
375
- }
376
- }
377
-
378
- function resolveTieFormat({
379
- drawDefinition,
380
- structure,
381
- matchUp,
382
- event
383
- }) {
384
- return {
385
- tieFormat: getItemTieFormat({
386
- item: matchUp,
387
- drawDefinition,
388
- structure,
389
- event
390
- }) || getItemTieFormat({
391
- item: structure,
392
- drawDefinition,
393
- structure,
394
- event
395
- }) || getObjectTieFormat(drawDefinition) || getObjectTieFormat(event)
396
- };
397
- }
398
-
399
- function mustBeAnArray(value) {
400
- return `${value} must be an array`;
401
- }
402
-
403
174
  function unique(arr) {
404
175
  return arr.filter((item, i, s) => s.lastIndexOf(item) === i);
405
176
  }
@@ -1166,10 +937,18 @@ const INVALID_CONFIGURATION = {
1166
937
  message: "Invalid configuration",
1167
938
  code: "ERR_INVALID_CONFIG"
1168
939
  };
940
+ const INVALID_COLLECTION_DEFINITION = {
941
+ message: "Invalid collectionDefinition",
942
+ code: "ERR_INVALID_COLLECTION_DEFINITION"
943
+ };
1169
944
  const INVALID_OBJECT = {
1170
945
  message: "Invalid object",
1171
946
  code: "ERR_INVALID_OBJECT"
1172
947
  };
948
+ const INVALID_CATEGORY = {
949
+ message: "Invalid category",
950
+ code: "ERR_INVALID_CATEGORY"
951
+ };
1173
952
  const INVALID_VALUES = {
1174
953
  message: "Invalid values",
1175
954
  code: "ERR_INVALID_VALUES"
@@ -1270,6 +1049,8 @@ const errorConditionConstants = {
1270
1049
  INVALID_ACTION,
1271
1050
  INVALID_ASSIGNMENT,
1272
1051
  INVALID_BOOKINGS,
1052
+ INVALID_CATEGORY,
1053
+ INVALID_COLLECTION_DEFINITION,
1273
1054
  INVALID_CONFIGURATION,
1274
1055
  INVALID_DATE_AVAILABILITY,
1275
1056
  INVALID_DATE,
@@ -1712,6 +1493,9 @@ function setTournamentId(tournamentId) {
1712
1493
  function removeTournamentRecord(tournamentId) {
1713
1494
  return _globalStateProvider.removeTournamentRecord(tournamentId);
1714
1495
  }
1496
+ function getProvider() {
1497
+ return _globalStateProvider;
1498
+ }
1715
1499
  function handleCaughtError({
1716
1500
  engineName,
1717
1501
  methodName,
@@ -2040,6 +1824,13 @@ const dateTime = {
2040
1824
  };
2041
1825
 
2042
1826
  function makeDeepCopy(sourceObject, convertExtensions, internalUse, removeExtensions, iteration = 0) {
1827
+ if (getProvider().makeDeepCopy)
1828
+ return getProvider().makeDeepCopy(
1829
+ sourceObject,
1830
+ convertExtensions,
1831
+ internalUse,
1832
+ removeExtensions
1833
+ );
2043
1834
  const deepCopy = deepCopyEnabled();
2044
1835
  const { stringify, toJSON, ignore, modulate } = deepCopy || {};
2045
1836
  if (!deepCopy?.enabled && !internalUse || typeof sourceObject !== "object" || typeof sourceObject === "function" || sourceObject === null || typeof deepCopy?.threshold === "number" && iteration >= deepCopy.threshold) {
@@ -2415,6 +2206,444 @@ function UUID() {
2415
2206
  lut[d3 & 255] + lut[d3 >> 8 & 255] + lut[d3 >> 16 & 255] + lut[d3 >> 24 & 255];
2416
2207
  }
2417
2208
 
2209
+ function parse(matchUpFormatCode) {
2210
+ if (typeof matchUpFormatCode === "string") {
2211
+ const type = matchUpFormatCode.startsWith("T") && TIMED || matchUpFormatCode.startsWith(SET) && SET || "";
2212
+ if (type === TIMED) {
2213
+ const setFormat = parseTimedSet(matchUpFormatCode);
2214
+ const parsedFormat = {
2215
+ simplified: true,
2216
+ setFormat,
2217
+ bestOf: 1
2218
+ };
2219
+ if (setFormat)
2220
+ return parsedFormat;
2221
+ }
2222
+ if (type === SET)
2223
+ return setsMatch(matchUpFormatCode);
2224
+ }
2225
+ return void 0;
2226
+ }
2227
+ function setsMatch(formatstring) {
2228
+ const parts = formatstring.split("-");
2229
+ const setsCount = getNumber(parts[0].slice(3));
2230
+ const bestOf = setsCount === 1 || setsCount % 2 !== 0 ? setsCount : void 0;
2231
+ const exactly = setsCount !== 1 && setsCount % 2 === 0 ? setsCount : void 0;
2232
+ const setFormat = parts && parseSetFormat(parts[1]);
2233
+ const finalSetFormat = parts && parseSetFormat(parts[2]);
2234
+ const timed = setFormat && setFormat.timed || finalSetFormat && finalSetFormat.timed;
2235
+ const validSetsCount = bestOf && bestOf < 6 || timed && exactly;
2236
+ const validFinalSet = !parts[2] || finalSetFormat;
2237
+ const validSetsFormat = setFormat;
2238
+ const result = definedAttributes({
2239
+ setFormat,
2240
+ exactly,
2241
+ bestOf
2242
+ });
2243
+ if (finalSetFormat)
2244
+ result.finalSetFormat = finalSetFormat;
2245
+ if (validSetsCount && validSetsFormat && validFinalSet)
2246
+ return result;
2247
+ }
2248
+ function parseSetFormat(formatstring) {
2249
+ if (formatstring?.[1] === ":") {
2250
+ const parts = formatstring.split(":");
2251
+ const setType = setTypes$1[parts[0]];
2252
+ const setFormatString = parts[1];
2253
+ if (setType && setFormatString) {
2254
+ const isTiebreakSet = setFormatString.indexOf("TB") === 0;
2255
+ if (isTiebreakSet) {
2256
+ const tiebreakSet = parseTiebreakFormat(setFormatString);
2257
+ if (tiebreakSet === false)
2258
+ return false;
2259
+ return typeof tiebreakSet === "object" ? { tiebreakSet } : void 0;
2260
+ }
2261
+ const timedSet = setFormatString.indexOf("T") === 0;
2262
+ if (timedSet)
2263
+ return parseTimedSet(setFormatString);
2264
+ const parts2 = formatstring.match(/^[FS]:(\d+)([A-Za-z]*)/);
2265
+ const NoAD = parts2 && isNoAD(parts2[2]) || false;
2266
+ const validNoAD = !parts2?.[2] || NoAD;
2267
+ const setTo = parts2 ? getNumber(parts2[1]) : void 0;
2268
+ const tiebreakAtValue = parseTiebreakAt(setFormatString);
2269
+ const validTiebreakAt = tiebreakAtValue !== false;
2270
+ const tiebreakAt = validTiebreakAt && tiebreakAtValue || setTo;
2271
+ const tiebreakFormat = parseTiebreakFormat(setFormatString.split("/")[1]);
2272
+ const validTiebreak = tiebreakFormat !== false;
2273
+ const result = { setTo };
2274
+ if (NoAD)
2275
+ result.NoAD = true;
2276
+ if (tiebreakFormat) {
2277
+ result.tiebreakFormat = tiebreakFormat;
2278
+ result.tiebreakAt = tiebreakAt;
2279
+ } else {
2280
+ result.noTiebreak = true;
2281
+ }
2282
+ return setTo && validNoAD && validTiebreak && validTiebreakAt && result || false;
2283
+ }
2284
+ }
2285
+ return void 0;
2286
+ }
2287
+ function parseTiebreakAt(setFormatString, expectNumber = true) {
2288
+ const tiebreakAtValue = setFormatString?.indexOf("@") > 0 && setFormatString.split("@");
2289
+ if (tiebreakAtValue) {
2290
+ const tiebreakAt = expectNumber ? getNumber(tiebreakAtValue[1]) : tiebreakAtValue[1];
2291
+ return tiebreakAt || false;
2292
+ }
2293
+ return void 0;
2294
+ }
2295
+ function parseTiebreakFormat(formatstring) {
2296
+ if (formatstring) {
2297
+ if (formatstring.startsWith("TB")) {
2298
+ const modifier = parseTiebreakAt(formatstring, false);
2299
+ const parts = formatstring.match(/^TB(\d+)([A-Za-z]*)/);
2300
+ const tiebreakToString = parts?.[1];
2301
+ const NoAD = parts && isNoAD(parts[2]);
2302
+ const validNoAD = !parts?.[2] || NoAD;
2303
+ const tiebreakTo = getNumber(tiebreakToString);
2304
+ if (tiebreakTo && validNoAD) {
2305
+ const result = { tiebreakTo };
2306
+ if (modifier && typeof modifier === "string" && !isConvertableInteger(modifier)) {
2307
+ result.modifier = modifier;
2308
+ }
2309
+ if (NoAD)
2310
+ result.NoAD = true;
2311
+ return result;
2312
+ } else {
2313
+ return false;
2314
+ }
2315
+ } else {
2316
+ return false;
2317
+ }
2318
+ }
2319
+ return void 0;
2320
+ }
2321
+ function parseTimedSet(formatstring) {
2322
+ const timestring = formatstring.slice(1);
2323
+ const parts = timestring.match(/^(\d+)(@?[A-Za-z]*)/);
2324
+ const minutes = getNumber(parts?.[1]);
2325
+ if (!minutes)
2326
+ return;
2327
+ const setFormat = { timed: true, minutes };
2328
+ const based = parts?.[2];
2329
+ const validModifier = [void 0, "P", "G"].includes(based);
2330
+ if (based && !validModifier) {
2331
+ const modifier = timestring.match(/^(\d+)(@)([A-Za-z]+)$/)?.[3];
2332
+ if (modifier) {
2333
+ setFormat.modifier = modifier;
2334
+ return setFormat;
2335
+ }
2336
+ return;
2337
+ }
2338
+ if (based)
2339
+ setFormat.based = parts[2];
2340
+ return setFormat;
2341
+ }
2342
+ function isNoAD(formatstring) {
2343
+ return formatstring && formatstring.indexOf(NOAD) >= 0;
2344
+ }
2345
+ function getNumber(formatstring) {
2346
+ return !isNaN(Number(formatstring)) ? Number(formatstring) : 0;
2347
+ }
2348
+
2349
+ function isValid(matchUpFormat) {
2350
+ if (typeof matchUpFormat !== "string")
2351
+ return false;
2352
+ const parsedFormat = parse(matchUpFormat);
2353
+ const setParts = matchUpFormat.match(
2354
+ /-S:([1-9])+\/TB([0-9]{1,2})@?([1-9]?)*/
2355
+ );
2356
+ const setsTo = setParts?.[1];
2357
+ const tiebreakTo = setParts?.[2];
2358
+ const tiebreakAt = setParts?.[3];
2359
+ const finalSetParts = matchUpFormat.match(
2360
+ /-F:([1-9])+\/TB([0-9]{1,2})@?([1-9]?)*/
2361
+ );
2362
+ const finalSetTo = finalSetParts?.[1];
2363
+ const finalSetTiebreakTo = finalSetParts?.[2];
2364
+ const finalTiebreakAt = finalSetParts?.[3];
2365
+ const preserveRedundant = !!(setParts && tiebreakTo && setsTo === tiebreakAt || finalSetParts && finalSetTiebreakTo && finalSetTo === finalTiebreakAt);
2366
+ const stringified = stringify(parsedFormat, preserveRedundant);
2367
+ return stringified === matchUpFormat;
2368
+ }
2369
+
2370
+ const matchUpFormatCode = {
2371
+ isValidMatchUpFormat: isValid,
2372
+ stringify,
2373
+ isValid,
2374
+ parse
2375
+ };
2376
+
2377
+ function factoryVersion() {
2378
+ return "1.8.5";
2379
+ }
2380
+
2381
+ function getObjectTieFormat(obj) {
2382
+ if (!obj)
2383
+ return;
2384
+ const { tieFormatId, tieFormats } = obj;
2385
+ if (obj.tieFormat) {
2386
+ return obj.tieFormat;
2387
+ } else if (tieFormatId && Array.isArray(tieFormats)) {
2388
+ return tieFormats.find((tf) => tf.tieFormatId === tieFormatId);
2389
+ }
2390
+ }
2391
+
2392
+ function getItemTieFormat({ item, drawDefinition, structure, event }) {
2393
+ if (!item)
2394
+ return;
2395
+ if (item.tieFormat)
2396
+ return item.tieFormat;
2397
+ if (item.tieFormatId) {
2398
+ if (drawDefinition.tieFormat)
2399
+ return drawDefinition.tieFormat;
2400
+ const tieFormat = drawDefinition.tieFormats?.find(
2401
+ (tf) => item.tieFormatId === tf.tieFormatId
2402
+ );
2403
+ if (tieFormat)
2404
+ return tieFormat;
2405
+ if (event.tieFormat)
2406
+ return event.tieFormat;
2407
+ return event.tieFormats?.find((tf) => item.tieFormatId === tf.tieFormatId);
2408
+ }
2409
+ if (structure.tieFormat)
2410
+ return structure.tieFormat;
2411
+ if (structure.tieFormatId) {
2412
+ const structureTieFormat = drawDefinition.tieFormats?.find(
2413
+ (tf) => structure.tieFormatId === tf.tieFormatId
2414
+ );
2415
+ if (structureTieFormat)
2416
+ return structureTieFormat;
2417
+ }
2418
+ }
2419
+
2420
+ function resolveTieFormat({
2421
+ drawDefinition,
2422
+ structure,
2423
+ matchUp,
2424
+ event
2425
+ }) {
2426
+ return {
2427
+ tieFormat: getItemTieFormat({
2428
+ item: matchUp,
2429
+ drawDefinition,
2430
+ structure,
2431
+ event
2432
+ }) || getItemTieFormat({
2433
+ item: structure,
2434
+ drawDefinition,
2435
+ structure,
2436
+ event
2437
+ }) || getObjectTieFormat(drawDefinition) || getObjectTieFormat(event)
2438
+ };
2439
+ }
2440
+
2441
+ const typeMatch = (arr, type) => arr.filter(Boolean).every((i) => typeof i === type);
2442
+ const allNumeric = (arr) => arr.filter(Boolean).every(isNumeric);
2443
+ function getCategoryAgeDetails(params) {
2444
+ const category = params.category;
2445
+ if (typeof category !== "object")
2446
+ return { error: INVALID_CATEGORY };
2447
+ let { ageCategoryCode, ageMaxDate, ageMinDate, ageMax, ageMin } = category;
2448
+ const categoryName = category.categoryName;
2449
+ let combinedAge;
2450
+ if (!typeMatch(
2451
+ [ageCategoryCode, ageMaxDate, ageMinDate, categoryName],
2452
+ "string"
2453
+ ) || !allNumeric(
2454
+ [ageMax, ageMin]
2455
+ ))
2456
+ return { error: INVALID_CATEGORY };
2457
+ const consideredDate = params.consideredDate ?? extractDate((/* @__PURE__ */ new Date()).toLocaleDateString("sv"));
2458
+ if (!isValidDateString(consideredDate))
2459
+ return { error: INVALID_DATE };
2460
+ const [consideredYear] = consideredDate.split("-").slice(0, 3).map((n) => parseInt(n));
2461
+ const previousDayDate = dateStringDaysChange(consideredDate, -1);
2462
+ const [previousDayMonth, previousDay] = previousDayDate.split("-").slice(1, 3).map((n) => parseInt(n));
2463
+ const previousMonthDay = `${zeroPad(previousDayMonth)}-${zeroPad(
2464
+ previousDay
2465
+ )}`;
2466
+ const nextDayDate = dateStringDaysChange(consideredDate, 1);
2467
+ const [nextDayMonth, nextDay] = nextDayDate.split("-").slice(1, 3).map((n) => parseInt(n));
2468
+ const nextMonthDay = `${zeroPad(nextDayMonth)}-${zeroPad(nextDay)}`;
2469
+ let calculatedAgeMaxDate = ageMin && dateStringDaysChange(consideredDate, -1 * 365 * ageMin);
2470
+ let calculatedAgeMinDate = ageMax && dateStringDaysChange(consideredDate, -1 * 365 * ageMax);
2471
+ const errors = [];
2472
+ const addError = (errorString) => !errors.includes(errorString) && errors.push(errorString);
2473
+ ageCategoryCode = ageCategoryCode ?? categoryName;
2474
+ const prePost = /^([UO]?)(\d{1,2})([UO]?)$/;
2475
+ const extractCombined = /^C(\d{1,2})-(\d{1,2})$/;
2476
+ const isBetween = ageCategoryCode?.includes("-");
2477
+ const isCombined = isBetween && ageCategoryCode?.match(extractCombined);
2478
+ const isCoded = ageCategoryCode?.match(prePost);
2479
+ const constructedDate = (y, df) => `${y}-${df}`;
2480
+ const uPre = (ageInt) => {
2481
+ const ageMinYear = consideredYear - ageInt;
2482
+ const newMinDate = constructedDate(ageMinYear, nextMonthDay);
2483
+ if (category.ageMinDate && category.ageMinDate !== newMinDate)
2484
+ addError(`Invalid submitted ageMinDate: ${ageMinDate}`);
2485
+ ageMinDate = newMinDate;
2486
+ if (ageCategoryCode) {
2487
+ if (category.ageMax && category.ageMax !== ageInt - 1) {
2488
+ addError(`Invalid submitted ageMax: ${ageMax}`);
2489
+ calculatedAgeMinDate = void 0;
2490
+ }
2491
+ ageMax = ageInt - 1;
2492
+ }
2493
+ };
2494
+ const uPost = (ageInt) => {
2495
+ const ageMinYear = consideredYear - ageInt - 1;
2496
+ const newMinDate = constructedDate(ageMinYear, nextMonthDay);
2497
+ if (category.ageMin && category.ageMin > ageInt) {
2498
+ addError(`Invalid submitted ageMin: ${ageMin}`);
2499
+ }
2500
+ if (category.ageMax && category.ageMax > ageInt) {
2501
+ addError(`Invalid submitted ageMax: ${ageMax}`);
2502
+ }
2503
+ if (category.ageMinDate && category.ageMinDate !== newMinDate)
2504
+ addError(`Invalid submitted ageMinDate: ${ageMinDate}`);
2505
+ ageMinDate = newMinDate;
2506
+ if (ageCategoryCode) {
2507
+ if (category.ageMax && category.ageMax !== ageInt) {
2508
+ addError(`Invalid submitted ageMax: ${ageMax}`);
2509
+ calculatedAgeMaxDate = void 0;
2510
+ }
2511
+ ageMax = ageInt;
2512
+ }
2513
+ };
2514
+ const oPre = (ageInt) => {
2515
+ const ageMaxYear = consideredYear - ageInt;
2516
+ const newMaxDate = constructedDate(ageMaxYear, previousMonthDay);
2517
+ if (category.ageMaxDate && category.ageMaxDate !== newMaxDate)
2518
+ addError(`Invalid submitted ageMaxDate: ${ageMaxDate}`);
2519
+ ageMaxDate = newMaxDate;
2520
+ if (ageCategoryCode) {
2521
+ if (category.ageMin && category.ageMin !== ageInt + 1) {
2522
+ addError(`Invalid submitted ageMin: ${ageMin}`);
2523
+ calculatedAgeMaxDate = void 0;
2524
+ }
2525
+ ageMin = ageInt + 1;
2526
+ }
2527
+ };
2528
+ const oPost = (ageInt) => {
2529
+ const ageMaxYear = consideredYear - ageInt - 1;
2530
+ const newMaxDate = constructedDate(ageMaxYear, previousMonthDay);
2531
+ if (category.ageMaxDate && category.ageMaxDate !== newMaxDate)
2532
+ addError(`Invalid submitted ageMaxDate: ${ageMaxDate}`);
2533
+ ageMaxDate = newMaxDate;
2534
+ if (ageCategoryCode) {
2535
+ if (category.ageMin && category.ageMin !== ageInt) {
2536
+ addError(`Invalid submitted ageMin: ${ageMin}`);
2537
+ calculatedAgeMaxDate = void 0;
2538
+ }
2539
+ ageMin = ageInt;
2540
+ }
2541
+ };
2542
+ const processCode = (code) => {
2543
+ const [pre, age, post] = (code.match(prePost) || []).slice(1);
2544
+ const ageInt = parseInt(age);
2545
+ if (pre === "U") {
2546
+ if (category.ageMaxDate && category.ageMaxDate !== ageMaxDate) {
2547
+ addError(`Invalid submitted ageMaxDate: ${category.ageMaxDate}`);
2548
+ }
2549
+ uPre(ageInt);
2550
+ } else if (pre === "O") {
2551
+ oPre(ageInt);
2552
+ }
2553
+ if (post === "U") {
2554
+ if (category.ageMaxDate && category.ageMaxDate !== ageMaxDate) {
2555
+ addError(`Invalid submitted ageMaxDate: ${category.ageMaxDate}`);
2556
+ }
2557
+ uPost(ageInt);
2558
+ } else if (post === "O") {
2559
+ oPost(ageInt);
2560
+ }
2561
+ ageMaxDate = ageMaxDate ?? calculatedAgeMaxDate;
2562
+ ageMinDate = ageMinDate ?? calculatedAgeMinDate;
2563
+ };
2564
+ if (isCombined) {
2565
+ ageMaxDate = void 0;
2566
+ ageMinDate = void 0;
2567
+ ageMax = void 0;
2568
+ ageMin = void 0;
2569
+ if (category.ageMin) {
2570
+ const ageMaxYear = consideredYear - category.ageMin;
2571
+ ageMaxDate = constructedDate(ageMaxYear, previousMonthDay);
2572
+ }
2573
+ if (category.ageMax) {
2574
+ const ageMinYear = consideredYear - category.ageMax - 1;
2575
+ ageMinDate = constructedDate(ageMinYear, nextMonthDay);
2576
+ }
2577
+ const [lowAge, highAge] = (ageCategoryCode?.match(extractCombined) ?? []).slice(1).map((n) => parseInt(n));
2578
+ if (lowAge <= highAge) {
2579
+ ageMin = lowAge;
2580
+ ageMax = highAge;
2581
+ combinedAge = true;
2582
+ } else {
2583
+ addError(`Invalid combined age range ${ageCategoryCode}`);
2584
+ }
2585
+ } else if (isBetween) {
2586
+ ageCategoryCode?.split("-").forEach(processCode);
2587
+ } else if (isCoded) {
2588
+ processCode(ageCategoryCode);
2589
+ } else {
2590
+ if (ageMin)
2591
+ oPre(ageMin);
2592
+ if (ageMax)
2593
+ uPost(ageMax);
2594
+ }
2595
+ if (ageMax && category.ageMin && category.ageMin > ageMax) {
2596
+ addError(`Invalid submitted ageMin: ${category.ageMin}`);
2597
+ ageMin = void 0;
2598
+ }
2599
+ const result = definedAttributes({
2600
+ consideredDate,
2601
+ combinedAge,
2602
+ ageMaxDate,
2603
+ ageMinDate,
2604
+ ageMax,
2605
+ ageMin
2606
+ });
2607
+ if (errors.length)
2608
+ result.errors = errors;
2609
+ return result;
2610
+ }
2611
+
2612
+ function categoryCanContain({
2613
+ childCategory,
2614
+ withDetails,
2615
+ category
2616
+ }) {
2617
+ const categoryDetails = getCategoryAgeDetails({ category });
2618
+ const childCategoryDetails = getCategoryAgeDetails({
2619
+ category: childCategory
2620
+ });
2621
+ const invalidAgeMin = childCategoryDetails.ageMin && (categoryDetails.ageMin && childCategoryDetails.ageMin < categoryDetails.ageMin || categoryDetails.ageMax && childCategoryDetails.ageMin > categoryDetails.ageMax);
2622
+ const invalidAgeMax = childCategoryDetails.ageMax && (categoryDetails.ageMax && childCategoryDetails.ageMax > categoryDetails.ageMax || categoryDetails.ageMin && childCategoryDetails.ageMax < categoryDetails.ageMin);
2623
+ const invalidAgeMinDate = childCategoryDetails.ageMinDate && categoryDetails.ageMaxDate && new Date(childCategoryDetails.ageMinDate) > new Date(categoryDetails.ageMaxDate);
2624
+ const invalidAgeMaxDate = childCategoryDetails.ageMaxDate && categoryDetails.ageMinDate && new Date(childCategoryDetails.ageMaxDate) < new Date(categoryDetails.ageMinDate);
2625
+ const valid = !invalidAgeMax && !invalidAgeMin && !invalidAgeMinDate && !invalidAgeMaxDate;
2626
+ const ignoreFalse = true;
2627
+ const result = definedAttributes(
2628
+ {
2629
+ valid,
2630
+ invalidAgeMax,
2631
+ invalidAgeMin,
2632
+ invalidAgeMinDate,
2633
+ invalidAgeMaxDate
2634
+ },
2635
+ ignoreFalse
2636
+ );
2637
+ if (withDetails) {
2638
+ Object.assign(result, { categoryDetails, childCategoryDetails });
2639
+ }
2640
+ return result;
2641
+ }
2642
+
2643
+ function mustBeAnArray(value) {
2644
+ return `${value} must be an array`;
2645
+ }
2646
+
2418
2647
  function decorateResult({
2419
2648
  context,
2420
2649
  result,
@@ -2553,6 +2782,7 @@ var ParticipantTypeEnum = /* @__PURE__ */ ((ParticipantTypeEnum2) => {
2553
2782
  })(ParticipantTypeEnum || {});
2554
2783
 
2555
2784
  function validateTieFormat(params) {
2785
+ const checkCategory = !!(params?.enforceCategory !== false && params?.category);
2556
2786
  const checkGender = !!(params?.enforceGender !== false && params?.gender);
2557
2787
  const checkCollectionIds = params?.checkCollectionIds;
2558
2788
  const tieFormat = params?.tieFormat;
@@ -2589,9 +2819,11 @@ function validateTieFormat(params) {
2589
2819
  if ((setValue || scoreValue) && !collectionValue)
2590
2820
  aggregateValueImperative = true;
2591
2821
  const { valid: valid2, errors: collectionDefinitionErrors } = validateCollectionDefinition({
2822
+ referenceCategory: params.category,
2592
2823
  referenceGender: params.gender,
2593
2824
  collectionDefinition,
2594
2825
  checkCollectionIds,
2826
+ checkCategory,
2595
2827
  checkGender
2596
2828
  });
2597
2829
  if (valid2) {
@@ -2633,19 +2865,22 @@ function validateTieFormat(params) {
2633
2865
  return result;
2634
2866
  }
2635
2867
  function validateCollectionDefinition({
2868
+ checkCategory = true,
2636
2869
  collectionDefinition,
2637
2870
  checkCollectionIds,
2638
2871
  checkGender = true,
2872
+ referenceCategory,
2639
2873
  referenceGender,
2640
2874
  event
2641
2875
  }) {
2642
2876
  referenceGender = referenceGender ?? event?.gender;
2877
+ const stack = "validateCollectionDefinition";
2643
2878
  const errors = [];
2644
2879
  if (typeof collectionDefinition !== "object") {
2645
2880
  errors.push(
2646
2881
  `collectionDefinition must be an object: ${collectionDefinition}`
2647
2882
  );
2648
- return { errors, error: INVALID_OBJECT };
2883
+ return decorateResult({ result: { errors, error: INVALID_OBJECT }, stack });
2649
2884
  }
2650
2885
  const {
2651
2886
  collectionValueProfiles,
@@ -2658,6 +2893,7 @@ function validateCollectionDefinition({
2658
2893
  matchUpType,
2659
2894
  scoreValue,
2660
2895
  setValue,
2896
+ category,
2661
2897
  gender
2662
2898
  } = collectionDefinition;
2663
2899
  if (checkCollectionIds && typeof collectionId !== "string") {
@@ -2703,8 +2939,23 @@ function validateCollectionDefinition({
2703
2939
  if (checkGender && referenceGender && gender && [GenderEnum.Male, GenderEnum.Female].includes(referenceGender) && referenceGender !== gender) {
2704
2940
  errors.push(`Invalid gender: ${gender}`);
2705
2941
  }
2942
+ if (checkCategory && referenceCategory && category) {
2943
+ const result = categoryCanContain({
2944
+ category: referenceCategory,
2945
+ childCategory: category
2946
+ });
2947
+ if (!result.valid)
2948
+ return decorateResult({
2949
+ result: { error: INVALID_CATEGORY },
2950
+ context: result,
2951
+ stack
2952
+ });
2953
+ }
2706
2954
  if (errors.length)
2707
- return { errors, error: INVALID_OBJECT };
2955
+ return decorateResult({
2956
+ result: { errors, error: INVALID_COLLECTION_DEFINITION },
2957
+ stack
2958
+ });
2708
2959
  return { valid: true };
2709
2960
  }
2710
2961
  function checkTieFormat(tieFormat) {
@@ -7287,10 +7538,10 @@ function getOrderedDrawPositions({
7287
7538
  const pairedDrawPositions = targetRoundProfile?.pairedDrawPositions;
7288
7539
  const displayOrder = pairedDrawPositions?.find(
7289
7540
  (pair) => overlap(pair || [], drawPositions.filter(Boolean))
7290
- ) || unassignedDrawPositions;
7541
+ ) ?? unassignedDrawPositions;
7291
7542
  const isFeedRound = targetRoundProfile?.feedRound;
7292
7543
  if (allNumeric$1(drawPositions)) {
7293
- const orderedDrawPositions = drawPositions.sort(numericSort);
7544
+ const orderedDrawPositions = [...drawPositions].sort(numericSort);
7294
7545
  return {
7295
7546
  orderedDrawPositions: orderedDrawPositions.length === 2 ? orderedDrawPositions : displayOrder,
7296
7547
  displayOrder: isFeedRound ? orderedDrawPositions : displayOrder
@@ -8024,7 +8275,7 @@ function getAllStructureMatchUps({
8024
8275
  matchUp,
8025
8276
  event: event2
8026
8277
  }) {
8027
- additionalContext = additionalContext || {};
8278
+ additionalContext = additionalContext ?? {};
8028
8279
  const tieFormat = resolveTieFormat({
8029
8280
  drawDefinition,
8030
8281
  structure,
@@ -8035,7 +8286,7 @@ function getAllStructureMatchUps({
8035
8286
  const collectionDefinition = matchUp.collectionId && collectionDefinitions?.find(
8036
8287
  (definition) => definition.collectionId === matchUp.collectionId
8037
8288
  );
8038
- const matchUpFormat = matchUp.collectionId ? collectionDefinition?.matchUpFormat : matchUp.matchUpFormat || structure?.matchUpFormat || drawDefinition?.matchUpFormat || event2?.matchUpFormat;
8289
+ const matchUpFormat = matchUp.collectionId ? collectionDefinition?.matchUpFormat : matchUp.matchUpFormat ?? structure?.matchUpFormat ?? drawDefinition?.matchUpFormat ?? event2?.matchUpFormat;
8039
8290
  const matchUpType = matchUp.matchUpType || collectionDefinition?.matchUpType || structure?.matchUpType || drawDefinition?.matchUpType || event2?.eventType !== TEAM$1 && event2?.eventType;
8040
8291
  const matchUpStatus = isCollectionBye ? BYE : matchUp.matchUpStatus;
8041
8292
  const { schedule, endDate } = getMatchUpScheduleDetails({
@@ -8050,7 +8301,7 @@ function getAllStructureMatchUps({
8050
8301
  });
8051
8302
  const drawPositions = tieDrawPositions ?? matchUp.drawPositions ?? [];
8052
8303
  const { collectionPosition, collectionId, roundPosition } = matchUp;
8053
- const roundNumber = matchUp.roundNumber || additionalContext.roundNumber;
8304
+ const roundNumber = matchUp.roundNumber ?? additionalContext.roundNumber;
8054
8305
  const drawPositionCollectionAssignment = collectionId ? getDrawPositionCollectionAssignment({
8055
8306
  tournamentParticipants,
8056
8307
  positionAssignments,
@@ -8076,7 +8327,7 @@ function getAllStructureMatchUps({
8076
8327
  } : context?.category;
8077
8328
  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;
8078
8329
  const competitiveProfile = contextProfile?.withCompetitiveness && getMatchUpCompetitiveProfile({ ...contextContent, matchUp });
8079
- const finishingPositionRange = matchUp.finishingPositionRange || additionalContext.finishingPositionRange;
8330
+ const finishingPositionRange = matchUp.finishingPositionRange ?? additionalContext.finishingPositionRange;
8080
8331
  const onlyDefined = (obj) => definedAttributes(obj, void 0, true);
8081
8332
  const matchUpWithContext = {
8082
8333
  ...onlyDefined(context),
@@ -8084,7 +8335,7 @@ function getAllStructureMatchUps({
8084
8335
  matchUpFormat: matchUp.matchUpType === TEAM$1 ? void 0 : matchUpFormat,
8085
8336
  tieFormat: matchUp.matchUpType !== TEAM$1 ? void 0 : tieFormat,
8086
8337
  roundOfPlay: stage !== QUALIFYING && isConvertableInteger(initialRoundOfPlay2) && initialRoundOfPlay2 + (roundNumber || 0),
8087
- endDate: matchUp.endDate || endDate,
8338
+ endDate: matchUp.endDate ?? endDate,
8088
8339
  gender: collectionDefinition?.gender,
8089
8340
  discipline: event2?.discipline,
8090
8341
  category: matchUpCategory,
@@ -9291,10 +9542,10 @@ function addUpcomingMatchUps({ drawDefinition, inContextDrawMatchUps }) {
9291
9542
  if (structure?.finishingPosition === WIN_RATIO) {
9292
9543
  const { roundNumber } = inContextMatchUp;
9293
9544
  const nextRoundNumber = roundNumber && ensureInt(roundNumber) + 1;
9294
- const matchUps = structure.matchUps || [];
9545
+ const matchUps = structure.matchUps ?? [];
9295
9546
  const { roundMatchUps } = getRoundMatchUps$1({ matchUps });
9296
9547
  if (nextRoundNumber && roundMatchUps?.[nextRoundNumber]) {
9297
- const sidesTo = drawPositions.sort().map((drawPosition, index) => {
9548
+ const sidesTo = [...drawPositions].sort(numericSort).map((drawPosition, index) => {
9298
9549
  const nextRoundMatchUp = roundMatchUps[nextRoundNumber].find(
9299
9550
  (matchUp) => matchUp.drawPositions?.includes(drawPosition)
9300
9551
  );
@@ -10961,7 +11212,7 @@ function getScoreAnalysis({
10961
11212
  const matchUpScoringFormat = parse(matchUpFormat);
10962
11213
  const isDecidingSet = setNumber === matchUpScoringFormat?.bestOf;
10963
11214
  const setFormat = isDecidingSet && matchUpScoringFormat?.finalSetFormat || matchUpScoringFormat?.setFormat || {};
10964
- const isTimedSet = setFormat?.timed || matchUpScoringFormat?.timed;
11215
+ const isTimedSet = setFormat?.timed;
10965
11216
  const finalSet = isDecidingSet && sets[matchUpScoringFormat?.bestOf - 1];
10966
11217
  const finalSetIsComplete = finalSet?.winningSide;
10967
11218
  const { isTiebreakEntry: isSetTiebreakEntry } = testTiebreakEntry({
@@ -17427,103 +17678,6 @@ const garman = {
17427
17678
  courtGenerator
17428
17679
  };
17429
17680
 
17430
- const typeMatch = (arr, type) => arr.filter(Boolean).every((i) => typeof i === type);
17431
- const allNumeric = (arr) => arr.filter(Boolean).every(isNumeric);
17432
- function parseAgeCategoryCode({ consideredDate, category } = { consideredDate: "" }) {
17433
- const invalid = { error: INVALID_VALUES, ageMin: 8, ageMax: 99 };
17434
- if (typeof category !== "object" || !isValidDateString(consideredDate))
17435
- return invalid;
17436
- const consideredYear = parseInt(consideredDate.split("-")[0]);
17437
- const errors = [];
17438
- let { ageCategoryCode, ageMaxDate, ageMinDate, ageMax, ageMin } = category;
17439
- const categoryName = category.categoryName;
17440
- let combinedAge;
17441
- if (!typeMatch(
17442
- [ageCategoryCode, ageMaxDate, ageMinDate, categoryName],
17443
- "string"
17444
- ) || !allNumeric([ageMax, ageMin]))
17445
- return invalid;
17446
- ageCategoryCode = ageCategoryCode ?? categoryName;
17447
- const prePost = /^([UO]?)(\d{1,2})([UO]?)$/;
17448
- const extractCombined = /^C(\d{1,2})-(\d{1,2})$/;
17449
- const isBetween = ageCategoryCode?.includes("-");
17450
- const isCombined = isBetween && ageCategoryCode?.match(extractCombined);
17451
- const isCoded = ageCategoryCode?.match(prePost);
17452
- const isYYMM = (datePart) => datePart.match(/^\d{2}-\d{2}$/);
17453
- const constructedDate = (y, d, df) => isValidDateString(d) && d || d && isYYMM(d) && `${y}-${d}` || `${y}-${df}`;
17454
- const uPre = (ageInt) => {
17455
- const ageMinYear = consideredYear - ageInt;
17456
- ageMinDate = constructedDate(ageMinYear, ageMinDate, "01-01");
17457
- if (ageMax && ageMax !== ageInt - 1)
17458
- errors.push(`Invalid ageMax: ${ageMax}`);
17459
- if (!ageMax)
17460
- ageMax = ageInt - 1;
17461
- return { ageMinDate, ageMax };
17462
- };
17463
- const uPost = (ageInt) => {
17464
- const ageMinYear = consideredYear - ageInt - 1;
17465
- ageMinDate = constructedDate(ageMinYear, ageMinDate, "01-01");
17466
- if (ageMax && ageMax !== ageInt)
17467
- errors.push(`Invalid ageMax: ${ageMax}`);
17468
- if (!ageMax)
17469
- ageMax = ageInt;
17470
- return { ageMinDate, ageMax };
17471
- };
17472
- const oPre = (ageInt) => {
17473
- const ageMaxYear = consideredYear - ageInt - 2;
17474
- ageMaxDate = constructedDate(ageMaxYear, ageMaxDate, "12-31");
17475
- if (ageMin && ageMin !== ageInt + 1)
17476
- errors.push(`Invalid ageMin: ${ageMin}`);
17477
- if (!ageMin)
17478
- ageMin = ageInt + 1;
17479
- return { ageMaxDate, ageMin };
17480
- };
17481
- const oPost = (ageInt) => {
17482
- const ageMaxYear = consideredYear - ageInt - 1;
17483
- ageMaxDate = constructedDate(ageMaxYear, ageMaxDate, "12-31");
17484
- if (ageMin && ageMin !== ageInt)
17485
- errors.push(`Invalid ageMin: ${ageMin}`);
17486
- if (!ageMin)
17487
- ageMin = ageInt;
17488
- return { ageMaxDate, ageMin };
17489
- };
17490
- const processCode = (code) => {
17491
- const [pre, age, post] = (code.match(prePost) || []).slice(1);
17492
- const ageInt = parseInt(age);
17493
- if (pre === "U")
17494
- ({ ageMinDate, ageMax } = uPre(ageInt));
17495
- if (post === "U")
17496
- ({ ageMinDate, ageMax } = uPost(ageInt));
17497
- if (pre === "O")
17498
- ({ ageMaxDate, ageMin } = oPre(ageInt));
17499
- if (post === "O")
17500
- ({ ageMaxDate, ageMin } = oPost(ageInt));
17501
- };
17502
- if (isCombined) {
17503
- const [lowAge, highAge] = (ageCategoryCode?.match(extractCombined) ?? []).slice(1).map((n) => parseInt(n));
17504
- if (lowAge <= highAge) {
17505
- ageMin = ageMin ?? lowAge;
17506
- ageMax = ageMax ?? highAge;
17507
- combinedAge = true;
17508
- } else {
17509
- errors.push(`Invalid combined age range ${ageCategoryCode}`);
17510
- }
17511
- } else if (isBetween) {
17512
- ageCategoryCode?.split("-").forEach(processCode);
17513
- } else if (isCoded) {
17514
- processCode(ageCategoryCode);
17515
- }
17516
- if (errors.length)
17517
- return { error: errors, ageMin: 8, ageMax: 99 };
17518
- return definedAttributes({
17519
- combinedAge,
17520
- ageMaxDate,
17521
- ageMinDate,
17522
- ageMax,
17523
- ageMin
17524
- });
17525
- }
17526
-
17527
17681
  function parseScoreString({
17528
17682
  tiebreakTo = 7,
17529
17683
  scoreString
@@ -17565,7 +17719,7 @@ function getRoundRobinGroupMatchUps({ drawPositions }) {
17565
17719
  return { groupMatchUps, uniqueMatchUpGroupings };
17566
17720
  }
17567
17721
  function drawPositionsHash(drawPositions) {
17568
- return drawPositions.sort(numericSort).join("|");
17722
+ return [...drawPositions].sort(numericSort).join("|");
17569
17723
  }
17570
17724
  function groupRounds({ groupSize, drawPositionOffset }) {
17571
17725
  const numArr = (count) => [...Array(count)].map((_, i) => i);
@@ -17591,7 +17745,7 @@ function groupRounds({ groupSize, drawPositionOffset }) {
17591
17745
  aRow = [aHead, bUp, ...aRow].filter(Boolean);
17592
17746
  bRow = [...bRow, aDown].filter(Boolean);
17593
17747
  const sum = (x) => x[0].reduce((a, b) => a + b);
17594
- return rounds.reverse().sort((a, b) => sum(a) - sum(b)).map(
17748
+ return [...rounds].reverse().sort((a, b) => sum(a) - sum(b)).map(
17595
17749
  (round) => round.filter(
17596
17750
  (groupPositions2) => groupPositions2.every((position) => position <= groupSize)
17597
17751
  ).map((groupPositions2) => {
@@ -23108,22 +23262,25 @@ const structureTemplate = ({
23108
23262
  return structure;
23109
23263
  };
23110
23264
 
23111
- function generateRoundRobin({
23112
- structureName = constantToString(MAIN),
23113
- groupNameBase = "Group",
23114
- stageSequence = 1,
23115
- structureOptions,
23116
- appliedPolicies,
23117
- seedingProfile,
23118
- stage = MAIN,
23119
- matchUpType,
23120
- roundTarget,
23121
- structureId,
23122
- drawSize,
23123
- idPrefix,
23124
- isMock,
23125
- uuids
23126
- }) {
23265
+ function generateRoundRobin(params) {
23266
+ const {
23267
+ groupNameBase = "Group",
23268
+ playoffAttributes,
23269
+ stageSequence = 1,
23270
+ structureOptions,
23271
+ appliedPolicies,
23272
+ seedingProfile,
23273
+ stage = MAIN,
23274
+ matchUpType,
23275
+ roundTarget,
23276
+ structureId,
23277
+ groupNames,
23278
+ drawSize,
23279
+ idPrefix,
23280
+ isMock,
23281
+ uuids
23282
+ } = params;
23283
+ const structureName = params.structureName ?? playoffAttributes?.["0"]?.name ?? constantToString(MAIN);
23127
23284
  const { groupCount, groupSize } = deriveGroups({
23128
23285
  structureOptions,
23129
23286
  appliedPolicies,
@@ -23143,12 +23300,13 @@ function generateRoundRobin({
23143
23300
  maxRoundNumber = Math.max(
23144
23301
  ...matchUps.map(({ roundNumber }) => roundNumber)
23145
23302
  );
23303
+ const structureName2 = groupNames?.[structureOrder - 1] ?? `${groupNameBase} ${structureOrder}`;
23146
23304
  return structureTemplate({
23147
- structureName: `${groupNameBase} ${structureOrder}`,
23148
23305
  structureId: uuids?.pop(),
23149
23306
  structureType: ITEM,
23150
23307
  finishingPosition,
23151
23308
  structureOrder,
23309
+ structureName: structureName2,
23152
23310
  matchUps
23153
23311
  });
23154
23312
  });
@@ -30305,7 +30463,9 @@ function removeCollectionDefinition(params) {
30305
30463
  function addCollectionDefinition$1({
30306
30464
  updateInProgressMatchUps = true,
30307
30465
  collectionDefinition,
30466
+ referenceCategory,
30308
30467
  tournamentRecord,
30468
+ enforceCategory,
30309
30469
  referenceGender,
30310
30470
  drawDefinition,
30311
30471
  tieFormatName,
@@ -30323,16 +30483,21 @@ function addCollectionDefinition$1({
30323
30483
  drawDefinition,
30324
30484
  event
30325
30485
  }).appliedPolicies ?? {};
30326
- enforceGender = enforceGender ?? appliedPolicies?.[POLICY_TYPE_MATCHUP_ACTIONS]?.participants?.enforceGender;
30327
- const checkGender = !!(enforceGender !== false && event?.gender);
30328
- const { valid, errors } = validateCollectionDefinition({
30486
+ const matchUpActionsPolicy = appliedPolicies?.[POLICY_TYPE_MATCHUP_ACTIONS];
30487
+ enforceCategory = enforceCategory ?? matchUpActionsPolicy?.participants?.enforceCategory;
30488
+ enforceGender = enforceGender ?? matchUpActionsPolicy?.participants?.enforceGender;
30489
+ const checkCategory = !!((referenceCategory ?? event?.category) && enforceCategory !== false);
30490
+ const checkGender = !!((referenceGender ?? event?.gender) && enforceGender !== false);
30491
+ const validationResult = validateCollectionDefinition({
30492
+ referenceCategory: referenceCategory ?? event?.category,
30329
30493
  collectionDefinition,
30330
30494
  referenceGender,
30495
+ checkCategory,
30331
30496
  checkGender,
30332
30497
  event
30333
30498
  });
30334
- if (!valid) {
30335
- return decorateResult({ result: { error: INVALID_VALUES, errors }, stack });
30499
+ if (validationResult.error) {
30500
+ return decorateResult({ result: validationResult, stack });
30336
30501
  }
30337
30502
  let result = !matchUp?.tieFormat ? getTieFormat$1({
30338
30503
  drawDefinition,
@@ -35951,7 +36116,8 @@ function bulkRescheduleMatchUps$1({
35951
36116
  scheduledTime,
35952
36117
  minutesChange
35953
36118
  );
35954
- newScheduledTime = scheduledTimeDate && newScheduledDate ? `${newScheduledDate}T${timeString}` : timeString;
36119
+ const timeStringDate = scheduledTimeDate && newScheduledDate || scheduledDate === scheduledTimeDate && scheduledTimeDate;
36120
+ newScheduledTime = timeStringDate ? `${timeStringDate}T${timeString}` : timeString;
35955
36121
  }
35956
36122
  }
35957
36123
  if (doNotReschedule) {
@@ -36991,6 +37157,8 @@ const POLICY_MATCHUP_ACTIONS_DEFAULT = {
36991
37157
  }
36992
37158
  ],
36993
37159
  participants: {
37160
+ enforceCategory: true,
37161
+ // validate collectionDefinition.category against event.category
36994
37162
  enforceGender: true
36995
37163
  // disallow placing FEMALEs in MALE events and vice versa
36996
37164
  },
@@ -40403,7 +40571,7 @@ function generatePlayoffStructures(params) {
40403
40571
  const attributeProfile = playoffAttributes?.[exitProfile];
40404
40572
  const base = playoffStructureNameBase && `${playoffStructureNameBase} ` || "";
40405
40573
  const customNaming = playoffAttributes?.[finishingPositionRange] ?? finishingPositionNaming?.[finishingPositionRange];
40406
- const structureName = customNaming?.name || attributeProfile?.name && (addNameBaseToAttributeName ? `${base}${attributeProfile?.name}` : attributeProfile.name) || `${base}${finishingPositionRange}`;
40574
+ const structureName = params.structureName || customNaming?.name || attributeProfile?.name && (addNameBaseToAttributeName ? `${base}${attributeProfile?.name}` : attributeProfile.name) || `${base}${finishingPositionRange}`;
40407
40575
  const structureAbbreviation = customNaming?.abbreviation || attributeProfile?.abbreviation;
40408
40576
  const mainParams = {
40409
40577
  idPrefix: idPrefix && `${idPrefix}-${structureName}-RP`,
@@ -40559,12 +40727,14 @@ function feedInChampionship(params) {
40559
40727
  fmlc
40560
40728
  });
40561
40729
  if (drawSize > 2) {
40730
+ const name = playoffAttributes?.["0-1"]?.name ?? constantToString(CONSOLATION);
40731
+ const structureName2 = params.playoffStructureNameBase ? `${params.playoffStructureNameBase} ${name}` : name;
40562
40732
  const consolationStructure = structureTemplate({
40563
- structureName: playoffAttributes?.["0-1"]?.name ?? constantToString(CONSOLATION),
40564
40733
  matchUps: consolationMatchUps,
40565
40734
  structureId: uuids?.pop(),
40566
40735
  stage: CONSOLATION,
40567
40736
  stageSequence: 1,
40737
+ structureName: structureName2,
40568
40738
  matchUpType
40569
40739
  });
40570
40740
  structures.push(consolationStructure);
@@ -40710,8 +40880,9 @@ function processPlayoffGroups({
40710
40880
  } else if ([COMPASS, OLYMPIC, PLAY_OFF].includes(playoffDrawType)) {
40711
40881
  const params2 = {
40712
40882
  playoffAttributes: playoffGroup.playoffAttributes ?? playoffAttributes,
40883
+ playoffStructureNameBase: playoffGroup.playoffStructureNameBase,
40713
40884
  structureId: playoffGroup.structureId ?? uuids?.pop(),
40714
- playoffStructureNameBase: structureName,
40885
+ structureName: playoffGroup.structureName,
40715
40886
  idPrefix: idPrefix && `${idPrefix}-po`,
40716
40887
  addNameBaseToAttributeName: true,
40717
40888
  finishingPositionOffset,
@@ -40764,7 +40935,9 @@ function processPlayoffGroups({
40764
40935
  ].includes(playoffDrawType)) {
40765
40936
  const uuidsFMLC = [uuids?.pop(), uuids?.pop()];
40766
40937
  const params2 = {
40938
+ playoffStructureNameBase: playoffGroup.playoffStructureNameBase,
40767
40939
  structureId: playoffGroup.structureId ?? uuids?.pop(),
40940
+ playoffAttributes: playoffGroup.playoffAttributes,
40768
40941
  idPrefix: idPrefix && `${idPrefix}-po`,
40769
40942
  finishingPositionOffset,
40770
40943
  uuids: uuidsFMLC,
@@ -40855,7 +41028,7 @@ function generateRoundRobinWithPlayOff(params) {
40855
41028
  };
40856
41029
  const { structures, groupCount, groupSize } = generateRoundRobin(mainDrawProperties);
40857
41030
  if (groupCount < 1) {
40858
- console.log(INVALID_CONFIGURATION);
41031
+ return { error: INVALID_CONFIGURATION };
40859
41032
  }
40860
41033
  const playoffGroups = structureOptions?.playoffGroups || [
40861
41034
  { finishingPositions: [1], structureName: constantToString(PLAY_OFF) }
@@ -58240,8 +58413,8 @@ function prepareStage(params) {
58240
58413
  });
58241
58414
  if (!scaledEntries?.length && seedByRanking) {
58242
58415
  const rankingScaleAttributes = {
58243
- scaleType: RANKING$1,
58244
58416
  scaleName: categoryName || ageCategoryCode,
58417
+ scaleType: RANKING$1,
58245
58418
  eventType
58246
58419
  };
58247
58420
  ({ scaledEntries } = getScaledEntries({
@@ -61264,7 +61437,7 @@ function generatePersons(params) {
61264
61437
  shuffledPersons.push(person);
61265
61438
  });
61266
61439
  }
61267
- const { ageMinDate, ageMaxDate } = parseAgeCategoryCode({
61440
+ const { ageMinDate, ageMaxDate } = getCategoryAgeDetails({
61268
61441
  consideredDate,
61269
61442
  category
61270
61443
  });
@@ -64125,7 +64298,8 @@ const utilities = {
64125
64298
  nextPowerOf2,
64126
64299
  numericSort,
64127
64300
  overlap,
64128
- parseAgeCategoryCode,
64301
+ getCategoryAgeDetails,
64302
+ categoryCanContain,
64129
64303
  randomMember,
64130
64304
  randomPop,
64131
64305
  shuffleArray,