resolvePackageSubpath

tcmts.cli.npm.resolvePackageSubpath · #ikyf7p7t · term · runs anywhere

The file a package's export map (exports) gives for a subpath (., ./utils), under the conditions a side resolves with (in order of what matters), as Node and bundlers read it: a string, conditions, arrays, * patterns. Without exports: browser (in the browser), module, main, index.js; a subpath is a path in it.

import type { PackageJson } from "#codebase/tcmts/cli/npm";

export function resolvePackageSubpath(
  pkg: PackageJson,
  subpath: string,
  conditions: string[],
): string | undefined {
  const pick = (target: unknown, star?: string): string | undefined => {
    if (typeof target === "string")
      return star === undefined ? target : target.replaceAll("*", star);
    if (Array.isArray(target)) {
      for (const t of target) {
        const r = pick(t, star);
        if (r) return r;
      }
      return undefined;
    }
    if (target && typeof target === "object")
      for (const [k, v] of Object.entries(target as Record<string, unknown>))
        if (k === "default" || conditions.includes(k)) {
          const r = pick(v, star);
          if (r) return r;
        }
    return undefined;
  };
  const exp = pkg.exports;
  if (exp !== undefined) {
    const map =
      typeof exp === "string" ||
      Array.isArray(exp) ||
      !Object.keys(exp as object).some((k) => k.startsWith("."))
        ? { ".": exp }
        : (exp as Record<string, unknown>);
    if (subpath in map) return pick(map[subpath]);
    for (const [k, v] of Object.entries(map)) {
      const at = k.indexOf("*");
      if (at < 0) continue;
      const [before, after] = [k.slice(0, at), k.slice(at + 1)];
      if (subpath.startsWith(before) && subpath.endsWith(after) && subpath.length >= k.length - 1)
        return pick(v, subpath.slice(before.length, subpath.length - after.length));
    }
    return undefined;
  }
  if (subpath !== ".") return subpath;
  if (conditions.includes("browser") && typeof pkg.browser === "string") return pkg.browser;
  return pkg.module ?? pkg.main ?? "index.js";
}

uses

used by