@textlint/kernel
Version:
textlint kernel is core logic by pure JavaScript.
233 lines (227 loc) • 9.82 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TextlintKernel = void 0;
// MIT © 2017- azu
// sequence
const fixer_processor_1 = __importDefault(require("./fixer/fixer-processor"));
// parallel
const linter_processor_1 = __importDefault(require("./linter/linter-processor"));
// message process manager
const MessageProcessManager_1 = __importDefault(require("./messages/MessageProcessManager"));
const filter_ignored_process_1 = __importDefault(require("./messages/filter-ignored-process"));
const filter_duplicated_process_1 = __importDefault(require("./messages/filter-duplicated-process"));
const filter_severity_process_1 = __importDefault(require("./messages/filter-severity-process"));
const sort_messages_process_1 = __importDefault(require("./messages/sort-messages-process"));
const descriptor_1 = require("./descriptor");
const TextlintSourceCodeImpl_1 = require("./context/TextlintSourceCodeImpl");
const isPluginParsedObject_1 = require("./util/isPluginParsedObject");
const invariant_1 = require("./util/invariant");
const feature_flag_1 = require("@textlint/feature-flag");
const ast_tester_1 = require("@textlint/ast-tester");
const debug_1 = __importDefault(require("debug"));
const parse_by_plugin_1 = require("./util/parse-by-plugin");
const createDummyTextLintResult_1 = require("./util/createDummyTextLintResult");
const debug = (0, debug_1.default)("textlint:kernel");
/**
* add fileName to trailing of error message
* @param {string|undefined} fileName
* @param {string} message
* @returns {string}
*/
function addingAtFileNameToError(fileName, message) {
if (!fileName) {
return message;
}
return `${message}
at ${fileName}`;
}
/**
* TextlintKernel is core logic written by pure JavaScript.
*
* Pass
*
* - config
* - plugins
* - rules
* - filterRules
* - messageProcessor
*
*/
class TextlintKernel {
/**
* @param config
*/
constructor(config = {}) {
// this.config often is undefined.
this.config = config;
// Initialize Message Processor
// Now, It is built-in process only
// filter `shouldIgnore()` results
this.messageProcessManager = new MessageProcessManager_1.default([filter_ignored_process_1.default]);
// filter duplicated messages
this.messageProcessManager.add(filter_duplicated_process_1.default);
// filter by severity
this.messageProcessManager.add((0, filter_severity_process_1.default)(this.config));
this.messageProcessManager.add(sort_messages_process_1.default);
}
/**
* lint text by registered rules.
* The result contains target filePath and error messages.
* @param {string} text
* @param {Object} options linting options
* @returns {Promise.<TextlintResult>}
*/
lintText(text, options) {
return Promise.resolve().then(() => {
const descriptor = new descriptor_1.TextlintKernelDescriptor({
rules: options.rules || [],
filterRules: options.filterRules || [],
plugins: options.plugins || []
});
return this._parallelProcess({
descriptor,
text,
options
});
});
}
/**
* fix texts and return fix result object
* @param {string} text
* @param {Object} options lint options
* @returns {Promise.<TextlintFixResult>}
*/
fixText(text, options) {
return Promise.resolve().then(() => {
const descriptor = new descriptor_1.TextlintKernelDescriptor({
rules: options.rules || [],
filterRules: options.filterRules || [],
plugins: options.plugins || []
});
return this._sequenceProcess({
descriptor,
options,
text
});
});
}
/**
* process text in parallel for Rules and return {Promise.<TextLintResult>}
* In other word, parallel flow process.
* @param {*} processor
* @param {string} text
* @param {Object} options
* @returns {Promise.<TextlintResult>}
* @private
*/
async _parallelProcess({ descriptor, text, options }) {
const { ext, filePath, configBaseDir } = options;
const plugin = descriptor.findPluginDescriptorWithExt(ext);
if (plugin === undefined) {
throw new Error(`Not found available plugin for ${ext}`);
}
debug("used plugin %j", plugin.id);
const processor = plugin.processor;
const { preProcess, postProcess } = processor.processor(ext);
(0, invariant_1.invariant)(typeof preProcess === "function" && typeof postProcess === "function", `${plugin.id} processor should implements {preProcess, postProcess}`);
const preProcessResult = await (0, parse_by_plugin_1.parseByPlugin)({
preProcess,
sourceText: text,
filePath
});
if (preProcessResult instanceof Error) {
return (0, createDummyTextLintResult_1.createDummyTextLintResult)(`Failed to parse text by plugin: ${plugin.id}
Please report this error with the content to plugin author.
${preProcessResult.stack}
`, filePath);
}
// { text, ast } or ast
const isParsedObject = (0, isPluginParsedObject_1.isPluginParsedObject)(preProcessResult);
const textForAST = isParsedObject ? preProcessResult.text : text;
const ast = isParsedObject ? preProcessResult.ast : preProcessResult;
(0, invariant_1.invariant)(typeof textForAST === "string", `${plugin.id} processor should return correct text`);
(0, invariant_1.invariant)(typeof ast === "object", `${plugin.id} processor should return correct AST object`);
if (feature_flag_1.coreFlags.runningTester) {
(0, invariant_1.invariant)((0, ast_tester_1.isTxtAST)(ast), `${plugin.id} processor return invalid AST object. Please check out @textlint/ast-tester.
You can check the validation result with "DEBUG=textlint*" env
See https://textlint.github.io/docs/plugin.html`);
}
const sourceCode = new TextlintSourceCodeImpl_1.TextlintSourceCodeImpl({
text: textForAST,
ast,
ext,
filePath
});
debug("process file %s", filePath);
const linterProcessor = new linter_processor_1.default(processor, this.messageProcessManager);
return await linterProcessor
.process({
config: this.config,
ruleDescriptors: descriptor.rule,
filterRuleDescriptors: descriptor.filterRule,
sourceCode,
configBaseDir
})
.catch((error) => {
error.message = addingAtFileNameToError(filePath, error.message);
return Promise.reject(error);
});
}
/**
* process text in series for Rules and return {Promise.<TextlintFixResult>}
* In other word, sequence flow process.
* @param {*} processor
* @param {string} text
* @param {TextlintKernelOptions} options
* @returns {Promise.<TextlintFixResult>}
* @private
*/
async _sequenceProcess({ descriptor, text, options }) {
const { ext, filePath, configBaseDir } = options;
const plugin = descriptor.findPluginDescriptorWithExt(ext);
if (plugin === undefined) {
throw new Error(`Not found available plugin for ${ext}`);
}
debug("used plugin %j", plugin.id);
const processor = plugin.processor;
const { preProcess, postProcess } = processor.processor(ext);
(0, invariant_1.invariant)(typeof preProcess === "function" && typeof postProcess === "function", `${plugin.id} processor should implements {preProcess, postProcess}`);
const preProcessResult = await Promise.resolve(preProcess(text, filePath));
// { text, ast } or ast
const isParsedObject = (0, isPluginParsedObject_1.isPluginParsedObject)(preProcessResult);
const textForAST = isParsedObject ? preProcessResult.text : text;
const ast = isParsedObject ? preProcessResult.ast : preProcessResult;
(0, invariant_1.invariant)(typeof textForAST === "string", `${plugin.id} processor should return correct text`);
(0, invariant_1.invariant)(typeof ast === "object", `${plugin.id} processor should return correct AST object`);
if (feature_flag_1.coreFlags.runningTester) {
(0, invariant_1.invariant)((0, ast_tester_1.isTxtAST)(ast), `${plugin.id} processor return invalid AST object. Please check out @textlint/ast-tester.
You can check the validation result with "DEBUG=textlint*" env
See https://textlint.github.io/docs/plugin.html`);
}
const sourceCode = new TextlintSourceCodeImpl_1.TextlintSourceCodeImpl({
text: textForAST,
ast,
ext,
filePath
});
debug("process file %s", filePath);
const fixerProcessor = new fixer_processor_1.default(processor, this.messageProcessManager);
return await fixerProcessor
.process({
config: this.config,
ruleDescriptors: descriptor.rule,
filterRules: descriptor.filterRule,
sourceCode,
configBaseDir
})
.catch((error) => {
error.message = addingAtFileNameToError(filePath, error.message);
return Promise.reject(error);
});
}
}
exports.TextlintKernel = TextlintKernel;
//# sourceMappingURL=textlint-kernel.js.map