@claudinho/core 0.8.3 → 0.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.d.ts CHANGED
@@ -146,8 +146,10 @@ declare function resolveTz(explicit?: string): string | undefined;
146
146
  interface FormatOpts {
147
147
  tz?: string;
148
148
  locale?: string;
149
+ /** Include month and day (for multi-week schedules like the knockout bracket). */
150
+ date?: boolean;
149
151
  }
150
- /** Format a kickoff like "Thu 19:00" in the target timezone/locale. */
152
+ /** Format a kickoff like "Thu 19:00", or "Sat, Jul 4, 17:00" when `date` is set. */
151
153
  declare function formatKickoff(iso: string, opts?: FormatOpts): string;
152
154
  /** A short calendar date like "Jun 11" in the target timezone/locale. */
153
155
  declare function formatDate(iso: string, opts?: FormatOpts): string;
@@ -1051,8 +1053,8 @@ declare function parseTeamSlot(team: Team): SlotRef | null;
1051
1053
 
1052
1054
  /**
1053
1055
  * Resolve the bundled topology against merged knockout matches and standings.
1054
- * Group slots project from live standings once a group has started; winner/loser slots
1055
- * require a confirmed FT result on the source match.
1056
+ * Group slots project from live standings once a group has started; confirmed when
1057
+ * the group is fully played. Winner/loser slots require a confirmed FT result.
1056
1058
  */
1057
1059
  declare function buildBracketView(topology: BracketTopology, matches: Match[], tables: GroupStandings[], standingsDegraded: boolean, liveDegraded: boolean, filterStage?: string, lang?: string): BracketView;
1058
1060
 
package/dist/index.js CHANGED
@@ -451,6 +451,7 @@ function formatKickoff(iso, opts = {}) {
451
451
  const locale = safeLocale(opts.locale);
452
452
  return new Intl.DateTimeFormat(locale, {
453
453
  weekday: "short",
454
+ ...opts.date ? { month: "short", day: "numeric" } : {},
454
455
  hour: "2-digit",
455
456
  minute: "2-digit",
456
457
  hour12: false,
@@ -3352,6 +3353,18 @@ function hasGroupStarted(group, tables) {
3352
3353
  if (!table?.rows.length) return false;
3353
3354
  return table.rows.some((r) => r.played > 0);
3354
3355
  }
3356
+ function matchesPerTeamInGroup(teamCount) {
3357
+ return Math.max(0, teamCount - 1);
3358
+ }
3359
+ function isGroupStandingsComplete(table) {
3360
+ const n = table?.rows.length ?? 0;
3361
+ if (n < 2) return false;
3362
+ const required = matchesPerTeamInGroup(n);
3363
+ return table.rows.every((r) => r.played >= required);
3364
+ }
3365
+ function isGroupComplete(group, tables) {
3366
+ return isGroupStandingsComplete(tables.find((t2) => t2.group === group));
3367
+ }
3355
3368
  function resolveWinner(match) {
3356
3369
  if (!isFinished(match.status)) return void 0;
3357
3370
  if (match.winnerCode) {
@@ -3400,7 +3413,10 @@ function resolveSlot(ref, ctx) {
3400
3413
  case "group": {
3401
3414
  if (!ctx.standingsDegraded && hasGroupStarted(ref.group, ctx.tables)) {
3402
3415
  const team = teamFromStandings(ref.group, ref.position, ctx.tables);
3403
- if (team) return participant(team, "projected");
3416
+ if (team) {
3417
+ const status = isGroupComplete(ref.group, ctx.tables) ? "confirmed" : "projected";
3418
+ return participant(team, status);
3419
+ }
3404
3420
  }
3405
3421
  const label = ref.position === 1 ? t(ctx.lang, "bracket.slot.groupWinner", { group: ref.group }) : t(ctx.lang, "bracket.slot.groupSecond", { group: ref.group });
3406
3422
  return tbd(label);
@@ -4732,6 +4748,9 @@ function statusTail2(m) {
4732
4748
  if (isLive(m.status)) return " LIVE";
4733
4749
  return "";
4734
4750
  }
4751
+ function formatBracketKickoff(iso, opts) {
4752
+ return formatKickoff(iso, { tz: opts.tz, locale: opts.locale, date: true });
4753
+ }
4735
4754
  function formatBracketMatchLine(mv, opts = {}) {
4736
4755
  const flags = opts.flags !== false;
4737
4756
  const home = formatParticipant(mv.home, "home", flags, opts.locale);
@@ -4740,7 +4759,7 @@ function formatBracketMatchLine(mv, opts = {}) {
4740
4759
  if (isFinished(m.status) || isLive(m.status)) {
4741
4760
  return ` ${home} ${scoreline(m)} ${away}${statusTail2(m)}`;
4742
4761
  }
4743
- const kickoff = mv.kickoff ? formatKickoff(mv.kickoff, { tz: opts.tz, locale: opts.locale }) : "";
4762
+ const kickoff = mv.kickoff ? formatBracketKickoff(mv.kickoff, opts) : "";
4744
4763
  return ` ${home} vs ${away}${kickoff ? ` \xB7 ${kickoff}` : ""}`;
4745
4764
  }
4746
4765
  function formatBracketList(view, opts = {}) {
@@ -4837,7 +4856,7 @@ function formatBracketCompactLine(mv, opts = {}) {
4837
4856
  const away = formatParticipant(mv.away, "away", flags, opts.locale);
4838
4857
  const m = mv.match;
4839
4858
  const mid2 = isFinished(m.status) || isLive(m.status) ? scoreline(m) : "vs";
4840
- const tail = m.status === "SCHEDULED" && mv.kickoff ? ` \xB7 ${formatKickoff(mv.kickoff, { tz: opts.tz, locale: opts.locale })}` : statusTail2(m);
4859
+ const tail = m.status === "SCHEDULED" && mv.kickoff ? ` \xB7 ${formatBracketKickoff(mv.kickoff, opts)}` : statusTail2(m);
4841
4860
  return `${stageLabelI18n(opts.locale, mv.stage)} \xB7 ${home} ${mid2} ${away}${tail}`;
4842
4861
  }
4843
4862
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@claudinho/core",
3
- "version": "0.8.3",
3
+ "version": "0.8.5",
4
4
  "description": "Domain model, provider adapters (ESPN), standings, bundled schedule, and the read-only Polymarket market-signal sidecar powering Claudinho. Not affiliated with FIFA or Anthropic.",
5
5
  "type": "module",
6
6
  "license": "MIT",