linkedStylesheets

tcmts.cli.web.linkedStylesheets · #43gtk4yo · term · runs anywhere

The stylesheets of the codebase (.css files) the browser's code only links to: every place it uses one is a component whose package gives it the stylesheet role (roles, by hash: rolesIn; the react library's <Stylesheet css={…} />), given the file itself. The browser is sent those as files alone, without their text in its code (stylesheetStandIn); one it uses otherwise (its length, put in a string, passed on) keeps its text. Read from the code: every module the browser is sent, each member of it.

import type { AppPlan } from "#codebase/tcmts/cli/placement";
import type { Lookup } from "#codebase/tcmts/cli/web";

export function linkedStylesheets(
  plan: AppPlan,
  look: Lookup,
  roles: ReadonlyMap<string, string> = new Map(),
): Set<string> {
  const css = new Set<string>();
  const used = new Set<string>();
  const seen = new Set<string>();
  type Node = unknown[];
  const slot = (n: Node, name: string): Node | undefined => {
    const s = n.find((c) => Array.isArray(c) && c[0] === name) as Node | undefined;
    return Array.isArray(s?.[1]) ? (s[1] as Node) : undefined;
  };
  for (const h of plan.browser) {
    const rec = look.get(h);
    if (!rec) continue;
    if (rec.kind === "file") {
      if (rec.signature === "css") css.add(h);
      continue;
    }
    if (seen.has(rec.componentHash)) continue;
    seen.add(rec.componentHash);
    for (const m of look.members(rec.componentHash)) {
      if (m.kind === "file") continue;
      // (the references a `<Stylesheet css={…}>` is given: met before the element's children are)
      const linked = new Set<Node>();
      const walk = (n: unknown): void => {
        if (!Array.isArray(n)) return;
        if (n[0] === "Ref" && typeof n[1] === "string") {
          if (!linked.has(n)) used.add(n[1]);
          return;
        }
        const tag =
          (n[0] === "JsxSelfClosingElement" || n[0] === "JsxOpeningElement") && slot(n, "tagName");
        if (tag && tag[0] === "Ref" && roles.get(tag[1] as string) === "stylesheet") {
          const props = slot(slot(n, "attributes") ?? [], "properties") ?? [];
          for (const a of props) {
            if (!Array.isArray(a) || a[0] !== "JsxAttribute" || slot(a, "name")?.[1] !== "css")
              continue;
            const init = slot(a, "initializer");
            const e = init?.[0] === "JsxExpression" ? slot(init, "expression") : undefined;
            if (e?.[0] === "Ref") linked.add(e);
          }
        }
        for (const c of n) walk(c);
      };
      walk(JSON.parse(m.ir));
    }
  }
  return new Set([...css].filter((h) => !used.has(h)));
}

uses

used by