textlint
Version:
The pluggable linting tool for natural language.
194 lines (193 loc) • 9.34 kB
JavaScript
// LICENSE : MIT
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createLinter = exports.TextlintFileSearchError = void 0;
const kernel_1 = require("@textlint/kernel");
const find_util_js_1 = require("./util/find-util.js");
const execute_file_backer_manager_js_1 = require("./engine/execute-file-backer-manager.js");
const cache_backer_js_1 = require("./engine/execute-file-backers/cache-backer.js");
const node_path_1 = __importDefault(require("node:path"));
const node_crypto_1 = __importDefault(require("node:crypto"));
const promises_1 = __importDefault(require("node:fs/promises"));
const logger_js_1 = require("./util/logger.js");
const debug_1 = __importDefault(require("debug"));
const separate_by_availability_js_1 = require("./util/separate-by-availability.js");
const debug = (0, debug_1.default)("textlint:createTextlint");
// File Search Custom Error
class TextlintFileSearchError extends Error {
constructor({ errors, patterns }) {
super(`Not found target files.
Patterns: ${patterns.join(", ")}
Reason: ${errors.map((e) => e.type).join(", ") || "Unknown error"}`);
this.name = "TextlintFileSearchError";
this.errors = errors;
this.patterns = patterns;
}
}
exports.TextlintFileSearchError = TextlintFileSearchError;
const createHashForDescriptor = async (descriptor) => {
var _a, _b;
try {
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";
const toString = JSON.stringify(descriptor.toJSON());
const md5 = node_crypto_1.default.createHash("md5");
return md5.update(`${version}-${toString}`, "utf8").digest("hex");
}
catch (error) {
// Fallback for some env
// https://github.com/textlint/textlint/issues/597
logger_js_1.Logger.warn("Use random value as hash because calculating hash value throw error", error);
return node_crypto_1.default.randomBytes(20).toString("hex");
}
};
const createExecutor = async (options) => {
var _a, _b;
const executeFileBackerManager = new execute_file_backer_manager_js_1.ExecuteFileBackerManager();
if (options.cache) {
const cacheBaker = new cache_backer_js_1.CacheBacker({
cache: (_a = options.cache) !== null && _a !== void 0 ? _a : false,
cacheLocation: (_b = options.cacheLocation) !== null && _b !== void 0 ? _b : node_path_1.default.resolve(process.cwd(), ".textlintcache"),
hash: await createHashForDescriptor(options.descriptor)
});
executeFileBackerManager.add(cacheBaker);
}
return executeFileBackerManager;
};
const createLinter = (options) => {
var _a;
const cwd = (_a = options.cwd) !== null && _a !== void 0 ? _a : process.cwd();
const kernel = new kernel_1.TextlintKernel({
quiet: options.quiet
});
const baseOptions = options.descriptor.toKernelOptions();
return {
/**
* Lint files
* Note: lintFiles respect ignore file
* @param {String[]} filesOrGlobs An array of file path and directory names, or glob.
* @returns {Promise<TextlintResult[]>} The results for all files that were linted.
*/
async lintFiles(filesOrGlobs) {
const executeFileBackerManager = await createExecutor(options);
const patterns = (0, find_util_js_1.pathsToGlobPatterns)(filesOrGlobs, {
extensions: options.descriptor.availableExtensions
});
const searchResult = await (0, find_util_js_1.searchFiles)(patterns, {
cwd,
ignoreFilePath: options.ignoreFilePath
});
if (!searchResult.ok) {
debug("Failed to search files with patterns: %j. Reason: %s", patterns, searchResult.errors.map((e) => e.type).join(", ") || "Unknown error");
throw new TextlintFileSearchError({ errors: searchResult.errors, patterns });
}
const targetFiles = searchResult.items;
const { availableFiles, unAvailableFiles } = (0, separate_by_availability_js_1.separateByAvailability)(targetFiles, {
extensions: options.descriptor.availableExtensions
});
debug("Available extensions: %j", options.descriptor.availableExtensions);
debug("Process files: %j", availableFiles);
debug("No Process files that are un-support extensions: %j", unAvailableFiles);
const results = await executeFileBackerManager.process(availableFiles, async (filePath) => {
const absoluteFilePath = node_path_1.default.resolve(process.cwd(), filePath);
const fileContent = await promises_1.default.readFile(filePath, "utf-8");
const kernelOptions = {
ext: node_path_1.default.extname(filePath),
filePath: absoluteFilePath,
...baseOptions
};
return kernel.lintText(fileContent, kernelOptions);
});
return results;
},
/**
* Lint text
* Note: lintText does not respect ignore file
* You can detect the file path is ignored or not by `scanFilePath()`
* @param text
* @param filePath
*/
async lintText(text, filePath) {
const kernelOptions = {
ext: node_path_1.default.extname(filePath),
filePath,
...baseOptions
};
return kernel.lintText(text, kernelOptions);
},
/**
* Lint files and fix them
* Note: fixFiles respect ignore file
* @param fileOrGlobs An array of file path and directory names, or glob.
* @returns {Promise<TextlintFixResult[]>} The results for all files that were linted and fixed.
*/
async fixFiles(fileOrGlobs) {
const executeFileBackerManager = await createExecutor(options);
const patterns = (0, find_util_js_1.pathsToGlobPatterns)(fileOrGlobs, {
extensions: options.descriptor.availableExtensions
});
const searchResult = await (0, find_util_js_1.searchFiles)(patterns, {
cwd,
ignoreFilePath: options.ignoreFilePath
});
if (!searchResult.ok) {
debug("Failed to search files with patterns: %j. Reason: %s", patterns, searchResult.errors.map((e) => e.type).join(", ") || "Unknown error");
throw new TextlintFileSearchError({ errors: searchResult.errors, patterns });
}
const targetFiles = searchResult.items;
const { availableFiles, unAvailableFiles } = (0, separate_by_availability_js_1.separateByAvailability)(targetFiles, {
extensions: options.descriptor.availableExtensions
});
debug("Available extensions: %j", options.descriptor.availableExtensions);
debug("Process files: %j", availableFiles);
debug("No Process files that are un-support extensions: %j", unAvailableFiles);
const results = await executeFileBackerManager.process(availableFiles, async (filePath) => {
const absoluteFilePath = node_path_1.default.resolve(process.cwd(), filePath);
const fileContent = await promises_1.default.readFile(filePath, "utf-8");
const kernelOptions = {
ext: node_path_1.default.extname(filePath),
filePath: absoluteFilePath,
...baseOptions
};
return kernel.fixText(fileContent, kernelOptions);
});
return results;
},
/**
* Lint text and fix it
* Note: fixText does not respect ignore file
* You can detect the file path is ignored or not by `scanFilePath()`
* @param text
* @param filePath
*/
async fixText(text, filePath) {
const kernelOptions = {
ext: node_path_1.default.extname(filePath),
filePath,
...baseOptions
};
return kernel.fixText(text, kernelOptions);
},
/**
* Scan file path and return scan result
* If you want to know the file is ignored by ignore file, use this function
* Return { status "ok" | "ignored" | "error" } object:
* - ok: found file and allow to lint/fix
* - ignored: found file, and it is ignored by ignore file
* - error: not found file
* @param filePath
* @returns {Promise<ScanFilePathResult>}
*/
async scanFilePath(filePath) {
return (0, find_util_js_1.scanFilePath)(filePath, {
cwd,
ignoreFilePath: options.ignoreFilePath
});
}
};
};
exports.createLinter = createLinter;
//# sourceMappingURL=createLinter.js.map