SinceRelease

tcmts.studio.SinceRelease · #kij2szix · term · runs on the server

uses tcmts.share.shareNow, which uses process

What changed under namespace since the history entry since (a package's last release), as the history has it: each entry that edited, added, removed or renamed something there, newest first (of the latest 400), each a link to its page with what it changed there; and how many definitions that is in all. Why a release waits, its API the same or not.

import { historyList } from "#codebase/tcmts/cli/changes";
import { ago, at, entrySummary, Fold, shareNow } from "#codebase/tcmts/share";
import { entryTitle } from "#codebase/tcmts/store";

export function SinceRelease({ namespace, since, version }: { namespace: string; since: string; version: string }) {
  const s = shareNow();
  const under = (n: string) => !namespace || n === namespace || n.startsWith(`${namespace}.`);
  const entries: { hash: string; title: string; ts: number; edited: number; added: number; removed: number }[] = [];
  const edited = new Set<string>();
  const added = new Set<string>();
  for (const h of historyList(s.cb, 400)) {
    if (h.hash === since) break;
    const e = entrySummary(s, h.hash);
    const ed = e.edited.filter(under);
    const ad = e.added.filter(under);
    const rm = e.removed.filter(under);
    if (!ed.length && !ad.length && !rm.length && !e.renamed.some((r) => under(r.to))) continue;
    for (const n of ed) edited.add(n);
    for (const n of ad) added.add(n);
    entries.push({ hash: h.hash, title: entryTitle(h), ts: h.ts, edited: ed.length, added: ad.length, removed: rm.length });
  }
  if (!entries.length) return null;
  const row = (e: (typeof entries)[number]) => (
    <a className="lrow tracerow" key={e.hash} href={at(`/history/${e.hash}`)}>
      <div>
        {e.title}
        <div className="muted" style={{ fontSize: 12.5, marginTop: 2 }}>
          {[e.edited && `${e.edited} edited`, e.added && `${e.added} added`, e.removed && `${e.removed} removed`]
            .filter(Boolean)
            .join(" · ") || "renamed"}
        </div>
      </div>
      <span className="muted">{ago(e.ts)}</span>
    </a>
  );
  return (
    <div className="box">
      <div className="boxhead">
        <b>Since {version}</b>
        <span className="muted">
          {edited.size} definition{edited.size === 1 ? "" : "s"} edited and {added.size} added under {namespace}, in{" "}
          {entries.length} entr{entries.length === 1 ? "y" : "ies"}
        </span>
      </div>
      {entries.slice(0, 6).map(row)}
      {entries.length > 6 && (
        <div className="tracerest">
          <Fold head={<span className="muted">{entries.length - 6} more</span>}>{entries.slice(6).map(row)}</Fold>
        </div>
      )}
    </div>
  );
}

uses

used by