* 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 chalk from 'chalk';
import { DescriptiveError } from '../core';
import { getLoader, logger as LOGGER } from '@react-native-community/cli-tools';
import process from 'node:process';
export class Logger {
private loader = getLoader({
interval: process.stdout.isTTY ? undefined : 0,
});
private logger = LOGGER;
private isLoaderActive = false;
start(prepareMsg: (styles: typeof chalk) => string) {
this.loader.start(prepareMsg(chalk));
this.isLoaderActive = true;
return (options?: { persist?: boolean }) => {
this.isLoaderActive = false;
if (options?.persist) {
console.log({ loader: this.loader });
this.loader.stopAndPersist();
} else {
this.loader.stop();
}
};
}
info(prepareMsg: (styles: typeof chalk) => string) {
const info = (msg: string) => {
this.isLoaderActive ? this.loader.info(msg) : this.logger.info(msg);
};
info(prepareMsg(chalk));
}
succeed(prepareMsg: (styles: typeof chalk) => string) {
const succeed = (msg: string) =>
this.isLoaderActive ? this.loader.succeed(msg) : this.logger.success(msg);
succeed(prepareMsg(chalk));
}
warn(prepareMsg: (styles: typeof chalk) => string) {
const warn = (msg: string) =>
this.isLoaderActive ? this.loader.warn(msg) : this.logger.warn(msg);
warn(prepareMsg(chalk));
}
debug(prepareMsg: (styles: typeof chalk) => string) {
if (this.isLoaderActive) {
clearLine(process.stdout);
moveCursor(process.stdout, 0);
console.debug(prepareMsg(chalk));
this.loader.render();
} else {
console.debug(prepareMsg(chalk));
}
}
descriptiveError(error: DescriptiveError) {
const lines: string[] = [];
if (error.isUnexpected() && error.stack) {
lines.push('');
lines.push(chalk.bold('Stack'));
error.stack.split('\n').forEach((line) => lines.push(chalk.gray(line)));
}
const details = error.getDetails();
if (details) {
lines.push('');
lines.push(chalk.bold('Details'));
details.split('\n').forEach((line) => lines.push(line));
}
lines.push('');
lines.push(`${error.getMessage()}`);
const suggestions = error.getSuggestions();
if (suggestions.length > 0) {
lines.push('');
lines.push(chalk.bold(`Suggestions`));
suggestions.forEach((suggestion) => {
lines.push('• ' + suggestion);
});
}
if (this.isLoaderActive) {
this.loader.fail(lines.join('\n').trim());
} else {
this.logger.error(lines.join('\n').trim());
}
}
}
const clearLine = (stream: NodeJS.WriteStream): void => {
if (stream.clearLine) {
stream.clearLine(0);
} else {
process.stdout.write(
'\r' + ' '.repeat(process.stdout.columns || 80) + '\r'
);
}
};
const moveCursor = (stream: NodeJS.WriteStream, x: number): void => {
if (stream.cursorTo) {
stream.cursorTo(x);
} else {
process.stdout.write('\r');
}
};