textlint
Version:
The pluggable linting tool for natural language.
208 lines • 9.24 kB
JavaScript
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.cli = void 0;
// LICENSE : MIT
const debug_1 = __importDefault(require("debug"));
const options_js_1 = require("./options.js");
const config_initializer_js_1 = require("./config/config-initializer.js");
const textlint_fixer_js_1 = require("./fixer/textlint-fixer.js");
const logger_js_1 = require("./util/logger.js");
const TextlintrcLoader_js_1 = require("./loader/TextlintrcLoader.js");
const CliLoader_js_1 = require("./loader/CliLoader.js");
const createLinter_js_1 = require("./createLinter.js");
const SeverityLevel_js_1 = require("./shared/type/SeverityLevel.js");
const cli_util_js_1 = require("./cli-util.js");
const formatter_js_1 = require("./formatter.js");
const server_js_1 = require("./mcp/server.js");
const debug = (0, debug_1.default)("textlint:cli");
const isStdinExecution = (executeOptions) => {
return "text" in executeOptions;
};
const loadDescriptor = async (cliOptions) => {
const cliDescriptor = await (0, CliLoader_js_1.loadCliDescriptor)(cliOptions);
debug("cliDescriptor: %j", cliDescriptor);
const textlintrcDescriptor = cliOptions.textlintrc
? await (0, TextlintrcLoader_js_1.loadTextlintrc)({
configFilePath: cliOptions.config,
node_modulesDir: cliOptions.rulesBaseDirectory
})
: await (0, TextlintrcLoader_js_1.loadBuiltinPlugins)();
debug("textlintrcDescriptor: %j", textlintrcDescriptor);
const mergedDescriptor = cliDescriptor.concat(textlintrcDescriptor);
debug("mergedDescriptor: %j", mergedDescriptor);
return mergedDescriptor;
};
/**
* Encapsulates all CLI behavior for eslint. Makes it easier to test as well as
* for other Node.js programs to effectively run the CLI.
*/
exports.cli = {
/**
* Executes the CLI based on an array of arguments that is passed in.
* @param {string|string[]} args The arguments to process.
* @param {string} [text] The text to lint (used for TTY).
* @returns {Promise<number>} The exit code for the operation.
*/
async execute(args, text) {
var _a, _b;
let currentOptions;
// version from package.json
const { readPackageUpSync } = await import("read-package-up");
const version = (_b = (_a = readPackageUpSync({ cwd: __dirname })) === null || _a === void 0 ? void 0 : _a.packageJson.version) !== null && _b !== void 0 ? _b : "unknown";
try {
currentOptions = options_js_1.options.parse(args);
}
catch (error) {
logger_js_1.Logger.error(error);
return Promise.resolve(1);
}
const files = currentOptions._;
debug("cliOptions: %j", currentOptions);
if (currentOptions.version) {
logger_js_1.Logger.log(`v${version}`);
}
else if (currentOptions.init) {
return (0, config_initializer_js_1.createConfigFile)({
dir: process.cwd(),
verbose: !currentOptions.quiet
});
}
else if (currentOptions.printConfig) {
const descriptor = await loadDescriptor(currentOptions);
logger_js_1.Logger.log(JSON.stringify(descriptor, null, 4));
return Promise.resolve(0);
}
else if (currentOptions.mcp) {
const mcpServer = await (0, server_js_1.connectStdioMcpServer)();
process.on("SIGINT", () => {
mcpServer.close();
process.exitCode = 0;
});
return 0;
}
else if (currentOptions.help || (!files.length && !text)) {
logger_js_1.Logger.log(options_js_1.options.generateHelp());
}
else {
// specify file name of stdin content
const stdinFilename = currentOptions.stdinFilename;
debug(`textlint --version: ${version}`);
debug(`Running on ${text ? "text" : "files"}, stdin-filename: ${stdinFilename}`);
if (text) {
if (!stdinFilename) {
throw new Error("Please specify --stdin-filename option");
}
return this.executeWithOptions({
cliOptions: currentOptions,
text,
stdinFilename
});
}
else {
return this.executeWithOptions({
cliOptions: currentOptions,
files
});
}
}
return Promise.resolve(0);
},
/**
* execute with cli options
* @returns {Promise<number>} exit status
* - 0: Success (no lint errors, or files ignored/not found when mixed with existing files)
* - 1: Lint errors found or unexpected errors
* - 2: File search errors (no files found matching the specified patterns) or fatal errors
*/
async executeWithOptions(executeOptions) {
const cliOptions = executeOptions.cliOptions;
// cli > textlintrc
// if cli and textlintrc have same option, cli option is prior.
const descriptor = await loadDescriptor(cliOptions);
const hasRuleAtLeastOne = descriptor.rule.lintableDescriptors.length > 0;
if (!hasRuleAtLeastOne) {
(0, cli_util_js_1.showEmptyRuleWarning)();
return Promise.resolve(1);
}
const linter = (0, createLinter_js_1.createLinter)({
cache: cliOptions.cache,
cacheLocation: cliOptions.cacheLocation,
quiet: cliOptions.quiet,
ignoreFilePath: cliOptions.ignorePath,
descriptor
});
try {
if (cliOptions.fix) {
// --fix
const results = isStdinExecution(executeOptions)
? [await linter.fixText(executeOptions.text, executeOptions.stdinFilename)]
: await linter.fixFiles(executeOptions.files);
debug("fix results: %j", results);
const fixer = new textlint_fixer_js_1.TextLintFixer();
const formatter = await (0, formatter_js_1.loadFixerFormatter)({
formatterName: cliOptions.format,
color: cliOptions.color
});
const output = formatter.format(results);
// --dry-run
if (cliOptions.dryRun) {
debug("Enable dry-run mode");
return (0, cli_util_js_1.printResults)(output, cliOptions) ? Promise.resolve(0) : Promise.resolve(2);
}
// modify file and return exit status
await fixer.write(results);
if ((0, cli_util_js_1.printResults)(output, cliOptions)) {
if (cliOptions.outputFile) {
return 0; // if --output-file option is specified, exit status is always 0
}
// --fix result has remaining errors, return 1
const hasErrorMessage = results.some((result) => {
return result.remainingMessages.some((message) => message.severity === SeverityLevel_js_1.SeverityLevel.error);
});
return hasErrorMessage ? 1 : 0;
}
else {
return 2;
}
}
else {
// lint as default
const results = isStdinExecution(executeOptions)
? [await linter.lintText(executeOptions.text, executeOptions.stdinFilename)]
: await linter.lintFiles(executeOptions.files);
debug("lint results: %j", results);
const formatter = await (0, formatter_js_1.loadLinterFormatter)({
formatterName: cliOptions.format,
color: cliOptions.color
});
const output = formatter.format(results);
if ((0, cli_util_js_1.printResults)(output, cliOptions)) {
if (cliOptions.outputFile) {
return 0; // if --output-file option is specified, exit status is always 0
}
const hasErrorMessage = results.some((result) => {
return result.messages.some((message) => message.severity === SeverityLevel_js_1.SeverityLevel.error);
});
return hasErrorMessage ? 1 : 0;
}
else {
return 2;
}
}
}
catch (error) {
// Handle file search errors with exit status 2
if (error instanceof createLinter_js_1.TextlintFileSearchError) {
logger_js_1.Logger.error(error);
return 2;
}
// Handle other unexpected errors
logger_js_1.Logger.error("Unexpected error during file processing:", error);
return 1;
}
}
};
//# sourceMappingURL=cli.js.map
;