declarationOrder

tcmts.cli.main.declarationOrder · #32gxs752 · term · runs anywhere

Definitions, in an order one file can declare them in: each after what it uses as it's initialized (a constant's value, a class it extends), as TypeScript wants it ("used before its declaration"), and otherwise as given. Each item is one or more definitions written together (a type and a value of one name); a cycle of such uses, which no order typechecks, is broken where it's come to.

import type { DefRecord } from "#codebase/tcmts/core/types";

export function declarationOrder<T>(items: T[], recsOf: (item: T) => DefRecord[]): T[] {
  const of = new Map<string, T>();
  for (const it of items) for (const r of recsOf(it)) of.set(r.hash, it);
  const out: T[] = [];
  const seen = new Set<T>();
  const visit = (it: T) => {
    if (seen.has(it)) return;
    seen.add(it);
    for (const r of recsOf(it))
      for (const d of r.deps) {
        const dep = d.strict && d.ref.startsWith("#") ? of.get(d.ref.slice(1)) : undefined;
        if (dep !== undefined && dep !== it) visit(dep);
      }
    out.push(it);
  };
  items.forEach(visit);
  return out;
}

uses

used by