UNPKG

@knighted/duel

Version:
286 lines (285 loc) 10.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.init = void 0; const node_util_1 = require("node:util"); const node_path_1 = require("node:path"); const promises_1 = require("node:fs/promises"); const get_tsconfig_1 = require("get-tsconfig"); const read_package_up_1 = require("read-package-up"); const util_js_1 = require("./util.cjs"); const cliOptions = [ { long: 'project', short: 'p', value: '[path]', desc: "Compile the project given the path to its configuration file, or to a folder with a 'tsconfig.json'.", }, { long: 'pkg-dir', short: 'k', value: '[path]', desc: 'Directory to start looking for package.json; defaults to --project.', }, { long: 'dirs', short: 'd', desc: 'Output both builds to directories inside of outDir. [esm, cjs].', }, { long: 'exports', short: 'e', value: '[mode]', desc: 'Generate package.json exports. Values: wildcard | dir | name.', }, { long: 'exports-config', value: '[path]', desc: 'Provide explicit exports config file.', }, { long: 'exports-validate', desc: 'Validate exports without writing.', }, { long: 'mode', value: '[none|globals|full]', desc: 'Optional shorthand for module transforms and syntax lowering.', }, { long: 'rewrite-policy', value: '[safe|warn|skip]', desc: 'Control specifier rewriting behavior.', }, { long: 'detect-dual-package-hazard', short: 'H', value: '[off|warn|error]', desc: 'Detect mixed import/require use of dual packages.', }, { long: 'dual-package-hazard-allowlist', value: '[pkg1,pkg2]', desc: 'Comma-separated packages to ignore for dual package hazard checks.', }, { long: 'dual-package-hazard-scope', value: '[file|project]', desc: 'Scope for dual package hazard detection.', }, { long: 'verbose', short: 'V', desc: 'Enable verbose logging.', }, { long: 'copy-mode', value: '[sources|full]', desc: 'Control temp copy strategy (sources only vs full project).', }, { long: 'help', short: 'h', desc: 'Print this message.', }, ]; const printHelp = () => { const bare = { bare: true }; const flags = cliOptions.map(opt => { const value = opt.value ? ` ${opt.value}` : ''; const short = opt.short ? `-${opt.short}, ` : ' '; const long = `--${opt.long}${value}`; return { flag: `${short}${long}`, desc: opt.desc }; }); const maxFlag = Math.max(...flags.map(f => f.flag.length)); (0, util_js_1.log)('Usage: duel [options]\n', 'info', bare); (0, util_js_1.log)('Options:', 'info', bare); for (const { flag, desc } of flags) { const pad = ' '.repeat(Math.max(2, maxFlag - flag.length + 2)); (0, util_js_1.log)(`${flag}${pad}${desc}`, 'info', bare); } }; const init = async (args) => { let parsed; try { const { values } = (0, node_util_1.parseArgs)({ args, options: { project: { type: 'string', short: 'p', default: 'tsconfig.json', }, 'pkg-dir': { type: 'string', short: 'k', }, dirs: { type: 'boolean', short: 'd', default: false, }, exports: { type: 'string', short: 'e', }, 'exports-config': { type: 'string', }, 'exports-validate': { type: 'boolean', default: false, }, 'rewrite-policy': { type: 'string', default: 'safe', }, 'detect-dual-package-hazard': { type: 'string', short: 'H', default: 'warn', }, 'dual-package-hazard-allowlist': { type: 'string', }, 'dual-package-hazard-scope': { type: 'string', default: 'file', }, verbose: { type: 'boolean', short: 'V', default: false, }, 'copy-mode': { type: 'string', default: 'sources', }, mode: { type: 'string', }, help: { type: 'boolean', short: 'h', default: false, }, }, }); parsed = values; } catch (err) { (0, util_js_1.logError)(err.message); return false; } if (parsed.help) { printHelp(); } else { const { project, 'pkg-dir': pkgDir, dirs, exports: exportsOpt, 'exports-config': exportsConfig, 'exports-validate': exportsValidate, 'rewrite-policy': rewritePolicy, 'detect-dual-package-hazard': detectDualPackageHazard, 'dual-package-hazard-allowlist': dualPackageHazardAllowlist, 'dual-package-hazard-scope': dualPackageHazardScope, verbose, mode, 'copy-mode': copyMode, } = parsed; let configPath = (0, node_path_1.resolve)(project); let stats; let pkg; if (mode && !['none', 'globals', 'full'].includes(mode)) { (0, util_js_1.logError)('--mode expects one of: none | globals | full'); return false; } try { stats = await (0, promises_1.stat)(configPath); } catch { (0, util_js_1.logError)(`Provided --project '${project}' resolves to ${configPath} which is not a file or directory.`); return false; } const pkgSearchCwd = pkgDir ?? (stats.isDirectory() ? configPath : (0, node_path_1.dirname)(configPath)); pkg = await (0, read_package_up_1.readPackageUp)({ cwd: pkgSearchCwd }); if (!pkg) { (0, util_js_1.logError)('No package.json file found.'); return false; } if (stats.isDirectory()) { configPath = (0, node_path_1.join)(configPath, 'tsconfig.json'); try { stats = await (0, promises_1.stat)(configPath); } catch { (0, util_js_1.logError)(`Provided --project '${project}' resolves to a directory ${(0, node_path_1.dirname)(configPath)} with no tsconfig.json.`); return false; } } if (stats.isFile()) { const tsconfig = (0, get_tsconfig_1.parseTsconfig)(configPath); const projectDir = (0, node_path_1.dirname)(configPath); if (!tsconfig.compilerOptions?.outDir) { (0, util_js_1.log)('No outDir defined in tsconfig.json. Build output will be in "dist".'); } if (exportsOpt && !['wildcard', 'dir', 'name'].includes(exportsOpt)) { (0, util_js_1.logError)('--exports expects one of: wildcard | dir | name'); return false; } if (!['safe', 'warn', 'skip'].includes(rewritePolicy)) { (0, util_js_1.logError)('--rewrite-policy expects one of: safe | warn | skip'); return false; } if (!['off', 'warn', 'error'].includes(detectDualPackageHazard)) { (0, util_js_1.logError)('--detect-dual-package-hazard expects one of: off | warn | error'); return false; } const hazardAllowlistProvided = dualPackageHazardAllowlist !== undefined; const hazardAllowlistRaw = dualPackageHazardAllowlist ?? ''; const hasAllowlistContent = /[^,\s]/.test(hazardAllowlistRaw); if (hazardAllowlistProvided && !hasAllowlistContent) { (0, util_js_1.logError)('--dual-package-hazard-allowlist expects a comma-separated list of package names'); return false; } const hazardAllowlist = hasAllowlistContent ? hazardAllowlistRaw .split(',') .map(item => item.trim()) .filter(Boolean) : []; if (!['file', 'project'].includes(dualPackageHazardScope)) { (0, util_js_1.logError)('--dual-package-hazard-scope expects one of: file | project'); return false; } if (!['sources', 'full'].includes(copyMode)) { (0, util_js_1.logError)('--copy-mode expects one of: sources | full'); return false; } let modulesFinal = false; let transformSyntaxFinal = false; if (mode) { if (mode === 'none') { modulesFinal = false; transformSyntaxFinal = false; } else if (mode === 'globals') { modulesFinal = true; transformSyntaxFinal = false; } else if (mode === 'full') { modulesFinal = true; transformSyntaxFinal = true; } } return { pkg, dirs, modules: modulesFinal, transformSyntax: transformSyntaxFinal, exports: exportsOpt, exportsConfig, exportsValidate, rewritePolicy, detectDualPackageHazard, dualPackageHazardAllowlist: hazardAllowlist, dualPackageHazardScope, verbose, copyMode, tsconfig, projectDir, configPath, }; } } return false; }; exports.init = init;