npmFacts

tcmts.cli.npm.npmFacts · #aww3lr6s · term · runs on the server

uses node:path

What an npm package's export (as code refers to it: npm:<name>@<range>, a subpath, an export) reaches on a side (exportFacts), from the package as the codebase has it installed; undefined if it isn't, or its export map names no file for it there. Kept for this process (factsKept) while the package's package.json is the same file: placing a codebase asks of each package many times over.

import { exportFacts, factsKept, moduleFile, resolvePackageSubpath, SIDE_CONDITIONS } from "#codebase/tcmts/cli/npm";
import type { NpmFacts, PackageJson } from "#codebase/tcmts/cli/npm";
import type { ExtRef } from "#codebase/tcmts/core/types";
import { npmAlias } from "#codebase/tcmts/loader/packages";
import fs from "node:fs";
import path from "node:path";

export function npmFacts(
  cacheDir: string,
  ext: ExtRef,
  side: keyof typeof SIDE_CONDITIONS,
): NpmFacts | undefined {
  if (!ext.module.startsWith("npm:")) return undefined;
  const dir = path.join(cacheDir, "node_modules", npmAlias(ext.module));
  const manifest = path.join(dir, "package.json");
  // (one stat a time, not a realpath, two reads and a parse; what isn't installed isn't kept: it may be installed next)
  let stamp: number;
  try {
    stamp = fs.statSync(manifest).mtimeMs;
  } catch {
    return undefined;
  }
  const key = `${dir}\n${ext.subpath}\n${ext.export}\n${side}`;
  const had = factsKept.get(key);
  if (had && had.stamp === stamp) return had.facts;
  try {
    const pkg = JSON.parse(fs.readFileSync(manifest, "utf8")) as PackageJson;
    const rel = resolvePackageSubpath(pkg, ext.subpath ? `./${ext.subpath}` : ".", [
      ...SIDE_CONDITIONS[side],
    ]);
    if (!rel) return undefined;
    // (as Node finds it: `"main": "./index"` is index.js)
    const file = moduleFile(path.join(fs.realpathSync(dir), rel));
    if (!file) return undefined;
    const facts = exportFacts(file, ext.export, side, cacheDir);
    factsKept.set(key, { stamp, facts });
    return facts;
  } catch {
    return undefined;
  }
}

uses

used by