Ctrl K
ComunidadGuías…

scripts/check-dependency-catalog.test.mjs

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
import assert from "node:assert/strict";
import { spawnSync } from "node:child_process";
import { copyFileSync, mkdirSync, mkdtempSync, rmSync, symlinkSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import test from "node:test";
import { fileURLToPath } from "node:url";

import { catalogViolations, parseWorkspaceManifest } from "./check-dependency-catalog.mjs";

const workspace = (dir, manifest) => ({ dir, manifest });

test("parses packages and the default catalog, ignoring comments", () => {
  const { packages, catalog } = parseWorkspaceManifest(`packages:
  - apps/*
  - "packages/*"

catalog:
  '@scope/pkg': ^1.2.0
  # Comment about the next entry.
  typescript: npm:@typescript/typescript6@6.0.2
  react: 19.2.3 # trailing comment

onlyBuiltDependencies:
  - esbuild
`);
  assert.deepEqual(packages, ["apps/*", "packages/*"]);
  assert.deepEqual(
    [...catalog],
    [
      ["@scope/pkg", "^1.2.0"],
      ["typescript", "npm:@typescript/typescript6@6.0.2"],
      ["react", "19.2.3"],
    ],
  );
});

test("rejects a dependency shared by two workspaces without catalog:", () => {
  const violations = catalogViolations({
    catalog: new Map(),
    workspaces: [
      workspace("packages/ui", { dependencies: { sonner: "^2.0.7" } }),
      workspace("packages/views", { dependencies: { sonner: "catalog:" } }),
    ],
  });
  assert.equal(violations.length, 1);
  assert.match(violations[0], /^sonner: declared by 2 workspaces.*packages\/ui dependencies \^2\.0\.7$/);
});

test("rejects a plain range for a dependency the catalog defines, even in one workspace", () => {
  const violations = catalogViolations({
    catalog: new Map([["tailwindcss", "^4"]]),
    workspaces: [workspace("apps/desktop", { devDependencies: { tailwindcss: "^4" } })],
  });
  assert.equal(violations.length, 1);
  assert.match(violations[0], /^tailwindcss: catalog defines \^4/);
});

test("accepts catalog:, workspace:, single-workspace deps, peers, and mobile pins", () => {
  const violations = catalogViolations({
    catalog: new Map([["react", "19.2.3"]]),
    workspaces: [
      workspace("apps/web", {
        dependencies: { react: "catalog:", "@multica/core": "workspace:*", "web-only": "^1.0.0" },
      }),
      workspace("packages/views", {
        peerDependencies: { react: "^19", eslint: "^9.0.0" },
        devDependencies: { eslint: "^9.0.0" },
      }),
      workspace("packages/eslint-config", { peerDependencies: { eslint: "^9.0.0" } }),
      workspace("apps/mobile", { dependencies: { react: "19.2.3", "web-only": "^0.9.0" } }),
    ],
  });
  assert.deepEqual(violations, []);
});

test("allowlisted drift passes until it is gone, then must be removed", () => {
  const allowlist = new Map([["fumadocs-core", "pending upgrade"]]);
  const drifted = [
    workspace("apps/web", { dependencies: { "fumadocs-core": "^15.5.2" } }),
    workspace("apps/docs", { dependencies: { "fumadocs-core": "^16.17.8" } }),
  ];
  assert.deepEqual(catalogViolations({ catalog: new Map(), workspaces: drifted, allowlist }), []);
  assert.deepEqual(
    catalogViolations({
      catalog: new Map([["fumadocs-core", "^16.17.8"]]),
      workspaces: drifted,
      allowlist,
    }),
    [],
  );

  const aligned = catalogViolations({
    catalog: new Map([["fumadocs-core", "^16.17.8"]]),
    workspaces: drifted.map(({ dir }) => workspace(dir, { dependencies: { "fumadocs-core": "catalog:" } })),
    allowlist,
  });
  assert.equal(aligned.length, 1);
  assert.match(aligned[0], /^fumadocs-core: allowlisted but no longer/);
});

test("still checks when run through a symlinked path", (t) => {
  // Node gives the main module its real path but keeps argv[1] as typed, so a
  // guard comparing the two unresolved would skip main() and exit 0 silently.
  const root = mkdtempSync(join(tmpdir(), "dependency-catalog-entry-"));
  t.after(() => rmSync(root, { recursive: true, force: true }));
  const repo = join(root, "repo");
  mkdirSync(join(repo, "scripts"), { recursive: true });
  copyFileSync(
    fileURLToPath(new URL("./check-dependency-catalog.mjs", import.meta.url)),
    join(repo, "scripts", "check-dependency-catalog.mjs"),
  );
  writeFileSync(join(repo, "pnpm-workspace.yaml"), "packages:\n  - packages/*\n");
  writeFileSync(join(repo, "package.json"), "{}");
  for (const name of ["a", "b"]) {
    mkdirSync(join(repo, "packages", name), { recursive: true });
    writeFileSync(join(repo, "packages", name, "package.json"), JSON.stringify({ dependencies: { sonner: "^2.0.7" } }));
  }
  symlinkSync(repo, join(root, "link"), "dir");

  const run = (dir) =>
    spawnSync(process.execPath, [join(root, dir, "scripts", "check-dependency-catalog.mjs")], { encoding: "utf8" });
  const linked = run("link");
  assert.equal(linked.status, 1);
  assert.match(linked.stderr, /sonner: declared by 2 workspaces/);
  const direct = run("repo");
  assert.deepEqual([linked.status, linked.stdout, linked.stderr], [direct.status, direct.stdout, direct.stderr]);
});