248 lines · 8.0 KB
import { parse as parseYaml } from "yaml";

export type Dependency = {
  name: string;
  requirement: string | null;
  scope: "runtime" | "development";
  direct: boolean;
};

type JsonObject = Record<string, unknown>;
const MAX_LOCK_DEPTH = 8;

function isObject(value: unknown): value is JsonObject {
  return typeof value === "object" && value !== null && !Array.isArray(value);
}

function stringMap(value: unknown): Array<[string, string]> {
  if (!isObject(value)) return [];
  return Object.entries(value).flatMap(([key, item]) => (typeof item === "string" ? [[key, item]] : []));
}

function parseJson(text: string): JsonObject | null {
  try {
    const value: unknown = JSON.parse(text);
    return isObject(value) ? value : null;
  } catch {
    return null;
  }
}

/** Parses JSON with comments and trailing commas, as used by bun.lock. */
function parseJsonc(text: string): JsonObject | null {
  let out = "";
  let inString = false;
  for (let index = 0; index < text.length; index++) {
    const char = text[index];
    if (inString) {
      out += char;
      if (char === "\\") out += text[++index] ?? "";
      else if (char === '"') inString = false;