* Copyright (c) 2025 Huawei Technologies Co., Ltd.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import { Command } from './types';
import { getLoader, Loader } from '@react-native-community/cli-tools';
import chalk from 'chalk';
import { DescriptiveError, AbsolutePath } from '../core';
import { Logger } from '../io';
import { CheckResult, verifyRNOHPackage } from '../package-verifier';
export const commandVerifyPackageHarmony: Command = {
name: 'verify-package-harmony',
description: 'Validates that a package is compliant with guidelines',
options: [
{
name: '--package-path <path>',
description: 'Path to the npm package',
},
{
name: '--no-harmony-code [boolean]',
description: 'Disable har verification',
},
{
name: '--skip-checks <string...>',
description: 'Disable certain checks by their names',
parse: (val, prev) => (prev ? [...prev, val] : [val]),
},
],
func: async (argv, config, rawArgs: any) => {
const loader = getLoader();
try {
const args = validateArgs(rawArgs);
loader.info(`Verifying RNOH package: ${args.packagePath.getValue()}`);
const checkResults: CheckResult[] = [];
for await (const checkResult of verifyRNOHPackage({
npmPackagePath: args.packagePath,
hasHarmonyCode: args.hasHarmonyCode,
checkNamesToSkip: args.checkNamesToSkip,
})) {
if (checkResult.type === 'START_PROCESS') {
loader.start(chalk.gray(checkResult.name));
} else if (checkResult.type === 'FINISHED_CHECKING') {
checkResults.push(checkResult);
logCheckResult(loader, checkResult);
}
}
if (
checkResults.every(
(checkResult) =>
checkResult.status === 'pass' || checkResult.status === 'skip'
)
) {
loader.info(chalk.bold('OK'));
} else {
loader.info(
chalk.red(
'Package verification failed. Please fix those checks before publishing your package.'
)
);
process.exit(1);
}
} catch (err) {
if (err instanceof DescriptiveError) {
new Logger().descriptiveError(err);
process.exit(1);
}
throw err;
}
},
};
type Args = {
packagePath: AbsolutePath;
hasHarmonyCode: boolean;
checkNamesToSkip: string[];
};
function validateArgs(args: any): Args {
if (!args.packagePath) {
throw new DescriptiveError({
whatHappened: 'package-path is undefined',
whatCanUserDo: ['Please provide --package-path'],
});
}
return {
packagePath: new AbsolutePath(args.packagePath),
hasHarmonyCode: args.harmonyCode,
checkNamesToSkip:
args.skipChecks.length === 1
? args.skipChecks[0].split(';')
: args.skipChecks,
};
}
function logCheckResult(loader: Loader, checkResult: CheckResult) {
const prefix = (() => {
switch (checkResult.status) {
case 'pass':
return `${chalk.green('PASS')}`;
case 'fail':
return `${chalk.red('FAIL')}`;
case 'skip':
return `${chalk.yellow('SKIP')}`;
}
})();
loader.info(
checkResult.message
? `[${chalk.bold(prefix)}] ${chalk.bold(checkResult.name)}\n${
checkResult.message
}`
: `[${chalk.bold(prefix)}] ${chalk.bold(checkResult.name)}`
);
}