resolvePackageSubpath
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"; }