Files
hapi/cli/bin/hapi.cjs
T
weishu 673e0c8aec refactor(cli): extract platform validation and error reporting from binary launcher
Refactor platform detection and error reporting logic into dedicated,
testable functions. This improves code organization and enables better
error handling for unsupported platforms and missing platform packages.

- Add SUPPORTED_PLATFORMS constant with platform labels
- Extract getPlatformKey() utility function
- Extract isSupportedPlatform() validation function
- Extract reportUnsupportedPlatform() error reporting function
- Extract reportMissingPlatformPackage() error reporting function
- Update main() to use new functions for clearer error handling
2026-03-02 11:58:08 +08:00

161 lines
4.4 KiB
JavaScript
Executable File

#!/usr/bin/env node
const { execFileSync } = require('child_process');
const path = require('path');
const platform = process.platform;
const arch = process.arch;
const RELEASE_URL = 'https://github.com/tiann/hapi/releases';
const OFFICIAL_NPM_REGISTRY = 'https://registry.npmjs.org';
const SUPPORTED_PLATFORMS = [
{
key: 'darwin-arm64',
label: 'darwin-arm64 (macOS Apple Silicon)',
},
{
key: 'darwin-x64',
label: 'darwin-x64 (macOS Intel)',
},
{
key: 'linux-arm64',
label: 'linux-arm64',
},
{
key: 'linux-x64',
label: 'linux-x64',
},
{
key: 'win32-x64',
label: 'win32-x64',
},
];
function getPlatformKey(platformName = platform, archName = arch) {
return `${platformName}-${archName}`;
}
function isSupportedPlatform(platformName = platform, archName = arch) {
return SUPPORTED_PLATFORMS.some((item) => item.key === getPlatformKey(platformName, archName));
}
function getBinaryPath(platformName = platform, archName = arch) {
const pkgName = `@twsxtd/hapi-${platformName}-${archName}`;
try {
// Try to find the platform-specific package
const pkgPath = require.resolve(`${pkgName}/package.json`);
const binName = platformName === 'win32' ? 'hapi.exe' : 'hapi';
return path.join(path.dirname(pkgPath), 'bin', binName);
} catch (e) {
return null;
}
}
function formatCommand(binPath, args) {
return [binPath, ...args].map((arg) => JSON.stringify(String(arg))).join(' ');
}
function normalizeExecError(error) {
return {
status: typeof error?.status === 'number' ? error.status : null,
signal: typeof error?.signal === 'string' ? error.signal : null,
message: error?.message ? String(error.message) : null,
};
}
function reportExecutionFailure(error, binPath, args, log = console.error) {
const { status, signal, message } = normalizeExecError(error);
log(`Failed to execute: ${formatCommand(binPath, args)}`);
if (signal) {
log(`Binary terminated by signal ${signal}.`);
}
if (status !== null) {
log(`Binary exited with status ${status}.`);
}
if (message) {
log(message);
}
return { status, signal };
}
function reportUnsupportedPlatform(platformName = platform, archName = arch, log = console.error) {
log(`Unsupported platform: ${platformName}-${archName}`);
log('');
log('Supported platforms:');
for (const item of SUPPORTED_PLATFORMS) {
log(` - ${item.label}`);
}
log('');
log('You can download the binary manually from:');
log(` ${RELEASE_URL}`);
}
function reportMissingPlatformPackage(platformName = platform, archName = arch, log = console.error) {
const platformPackage = `@twsxtd/hapi-${platformName}-${archName}`;
log(`Missing platform package: ${platformPackage}`);
log('');
log(`Detected platform ${platformName}-${archName} is supported, but the platform binary package was not installed.`);
log('This may happen when using a registry mirror that has not synced all optionalDependencies.');
log('');
log('Try reinstalling with the official npm registry:');
log(` npm install -g @twsxtd/hapi --registry=${OFFICIAL_NPM_REGISTRY}`);
log('');
log('Or download the binary manually from:');
log(` ${RELEASE_URL}`);
}
function main() {
if (!isSupportedPlatform()) {
reportUnsupportedPlatform();
process.exit(1);
}
const binPath = getBinaryPath();
if (!binPath) {
reportMissingPlatformPackage();
process.exit(1);
}
const args = process.argv.slice(2);
try {
execFileSync(binPath, args, { stdio: 'inherit' });
} catch (error) {
const { status, signal } = reportExecutionFailure(error, binPath, args);
if (status !== null) {
process.exit(status);
}
if (signal) {
try {
process.kill(process.pid, signal);
} catch {
// ignore unsupported/invalid signal names on this platform
}
}
process.exit(1);
}
}
if (require.main === module) {
main();
}
module.exports = {
formatCommand,
getPlatformKey,
getBinaryPath,
isSupportedPlatform,
normalizeExecError,
reportExecutionFailure,
reportMissingPlatformPackage,
reportUnsupportedPlatform,
};