#!/usr/bin/env node
/**
 * Publishability is a directory property (ADR 242): every package under
 * `packages/9-public/` is publishable, and no package anywhere else is.
 *
 * Both directions are enforced. A publishable package outside `9-public`
 * would ship an internal module the moment the publish workflow iterates
 * publishable packages; a `private: true` package inside `9-public` would
 * silently drop part of the published surface. Neither failure announces
 * itself at build time, which is why this is a lint.
 *
 * Exits 1 listing every violation; exits 0 otherwise.
 */

import { execFileSync } from 'node:child_process';
import { readFileSync } from 'node:fs';
import { resolve } from 'node:path';
import { fileURLToPath } from 'node:url';

const repoRoot = resolve(fileURLToPath(import.meta.url), '../..');

export function findPublishabilityViolations(root = repoRoot) {
  const manifests = execFileSync(
    'git',
    [
      'ls-files',
      'packages/*/package.json',
      'packages/*/*/package.json',
      'packages/*/*/*/package.json',
      'packages/*/*/*/*/package.json',
    ],
    {
      cwd: root,
      encoding: 'utf8',
    },
  )
    .split('\n')
    .filter(Boolean);

  const violations = [];
  for (const file of manifests) {
    const manifest = JSON.parse(readFileSync(resolve(root, file), 'utf8'));
    const isPublic = file.startsWith('packages/9-public/');
    const isPrivate = manifest.private === true;
    if (isPublic && isPrivate) {
      violations.push({ file, name: manifest.name, rule: 'private-inside-9-public' });
    }
    if (!isPublic && !isPrivate) {
      violations.push({ file, name: manifest.name, rule: 'publishable-outside-9-public' });
    }
  }
  return violations;
}

function main() {
  const violations = findPublishabilityViolations();
  if (violations.length === 0) {
    console.log(
      'Publishability matches the directory layout: packages/9-public/ and nothing else.',
    );
    return 0;
  }
  for (const v of violations) {
    console.error(`${v.file}: ${v.name} — ${v.rule}`);
  }
  console.error(`\nlint-publishability: ${violations.length} violation(s).`);
  return 1;
}

if (process.argv[1] === fileURLToPath(import.meta.url)) {
  process.exit(main());
}