#!/usr/bin/env node

'use strict';

const path = require('path');
const npa = require('npm-package-arg');
const colorize = require('json-colorizer');
const yargs = require('yargs');
const fromEntries = require('object.fromentries');
const arrayFrom = require('array.from');

const listExports = require('list-exports');
const exportsTable = require('../exportsTable');
const getPackageJSONPath = require('../getPackageJSONPath');

const argv = yargs
	.option('json', {
		describe: 'output the results as JSON',
		default: false,
		type: 'boolean',
	})
	.command(
		'package <specifier>', 'list the exports for the given package (that matches the optionally given version)',
		(y) => y.positional('specifier', {
			coerce(arg) {
				npa(arg);
				return String(arg);
			},
			conflicts: 'path',
			describe: 'package specifier with optional version, ex `foo`, `@scope/foo`, `foo@^1`, etc',
			type: 'string',
		}),
	)
	.command(
		'path <path>', 'list the exports for the relative path to a directory containing a `package.json`',
		(y) => y.positional('path', {
			coerce(arg) {
				return path.join(path.resolve(arg), 'package.json');
			},
			describe: `a relative path to a directory containing a \`package.json\`
					Usage: $0 --path=./path/to/directory
				`,
			required: true,
			requiresArg: true,
		}),
	)
	.demandCommand(1, 'must specify a command: “path” or “package”')
	.strict()
	.help()
	.parse();

const packageDirP = argv.path ? Promise.resolve(argv.path) : getPackageJSONPath(argv.specifier);

function serializer(key, value) {
	if (value instanceof Set) {
		return arrayFrom(value);
	}
	if (value instanceof Map) {
		return fromEntries(arrayFrom(value));
	}
	return value;
}

const promise = packageDirP.then((packageDir) => (argv.json
	? listExports(packageDir).then((x) => console.log(colorize(JSON.stringify(x, serializer))))
	: exportsTable(packageDir, (x) => console.log(x))));

promise.catch((err) => {
	console.error(err);
	process.exitCode = 1;
});
