testInitOrderFollowsFunctionsCalledAtInit

tcmts.loader.testInitOrderFollowsFunctionsCalledAtInit · #sjh5ukjy · term

A member initialized by calling a function of its component comes after what that function uses, which may come after it in the component (Effect's yieldNow = makePrimitive(…), whose body reads makePrimitiveProto).

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

export const testInitOrderFollowsFunctionsCalledAtInit = () => {
  const rec = (
    hash: string,
    initKind: "strict" | "hoisted",
    nominal: boolean,
    deps: [string, boolean, boolean][],
  ) =>
    ({
      hash,
      initKind,
      nominal,
      sourceText: hash === "fn" ? "function makePrimitive() {}" : `const ${hash} = 1`,
      deps: deps.map(([ref, strict, called]) => ({
        ref: `#${ref}`,
        strict,
        ...(called ? { called } : {}),
      })),
    }) as unknown as DefRecord;
  const order = initOrder([
    // `alias = Service` reads Service, which doesn't run what Service's body uses (`late`, which uses `alias`)
    rec("alias", "strict", false, [["Service", true, false]]),
    rec("Service", "strict", true, [["late", false, false]]),
    rec("late", "strict", false, [["alias", true, true]]),
    rec("yieldNow", "strict", false, [["fn", true, true]]),
    rec("fn", "hoisted", true, [
      ["proto", false, false],
      ["helper", false, true],
    ]),
    rec("helper", "strict", true, [["table", false, false]]),
    rec("table", "strict", false, []),
    rec("proto", "strict", false, []),
    rec("unrelated", "strict", false, []),
    // calling `Reference = Service as any` calls Service, whose body uses `ServiceProto`
    rec("frame", "strict", false, [["Reference", true, true]]),
    rec("Reference", "strict", false, [["Service2", true, false]]),
    rec("Service2", "strict", true, [["ServiceProto", false, false]]),
    rec("ServiceProto", "strict", false, []),
  ]).map((m) => m.hash);
  const before = (a: string, b: string) => {
    if (order.indexOf(a) > order.indexOf(b))
      throw new Error(`${a} should come before ${b}: ${order.join(", ")}`);
  };
  before("fn", "yieldNow");
  before("proto", "yieldNow");
  before("helper", "yieldNow");
  before("table", "yieldNow");
  before("Service", "alias");
  before("alias", "late");
  before("ServiceProto", "frame");
  before("Reference", "frame");
  if (order.length !== 13) throw new Error(`every member once: ${order.join(", ")}`);
}

uses