textlint-rule-ja-no-redundant-expression
Version:
232 lines (190 loc) • 6.76 kB
JavaScript
// MIT © 2016 azu
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _regexpStringMatcher = require("@textlint/regexp-string-matcher");
var _textlintRuleHelper = require("textlint-rule-helper");
var _textlintUtilToString = require("textlint-util-to-string");
var _dictionary = require("./dictionary");
var _kuromojin = require("kuromojin");
var _morphemeMatchAll = require("morpheme-match-all");
/**
* textの中身をすべて置換する
* @param {string} text
* @param {string|undefined} from
* @param {string} to
* @returns {string}
*/
var replaceAll = (text, from, to) => {
if (!from) {
return text;
}
return text.split(from).join(to);
};
var replaceTokenWith = (matcherToken, actualToken, specialTo) => {
if (matcherToken[specialTo]) {
return matcherToken[specialTo](actualToken);
}
return actualToken.surface_form;
};
/**
* tokensのsurface_formをつなげた文字列を返す
* @param tokens
* @returns {string}
*/
var tokensToString = tokens => {
return tokens.map(token => token.surface_form).join("");
};
/**
* "allows" オプションで許可されているかどうか
* @param {*[]} tokens
* @param {string[]} allows
*/
var isTokensAllowed = (tokens, allows) => {
if (allows.length === 0) {
return false;
}
var matchedText = tokensToString(tokens);
var allowsMatchResults = (0, _regexpStringMatcher.matchPatterns)(matchedText, allows);
return allowsMatchResults.length > 0;
};
/**
* マッチしたtokensを置換した結果の文字列を返す
* 置換できなかった場合はnullを返す
* @param {string} expected
* @param {*[]} matcherTokens
* @param {boolean[]} skipped
* @param {*[]} actualTokens
* @returns {null|string}
*/
var createExpected = _ref => {
var {
expected,
matcherTokens,
skipped,
actualTokens
} = _ref;
if (!expected) {
return null;
}
var resultText = expected;
var actualTokenIndex = 0;
for (var _index = 0; _index < matcherTokens.length; _index++) {
var token = matcherTokens[_index];
if (skipped[_index]) {
resultText = replaceAll(resultText, token._capture, "");
continue;
}
if (token._capture) {
var to = replaceTokenWith(token, actualTokens[actualTokenIndex], "_capture_to_expected"); // _capture_to_expectedが"STOP_REPLACE"を返した場合は置換を取りやめる
if (to === _dictionary.ExpectedType.STOP_REPLACE) {
return null;
}
resultText = replaceAll(resultText, token._capture, to);
}
++actualTokenIndex;
}
return resultText;
};
var createMessage = _ref2 => {
var {
id,
text,
matcherTokens,
skipped,
actualTokens
} = _ref2;
var resultText = text;
var actualTokenIndex = 0;
matcherTokens.forEach((token, index) => {
if (skipped[index]) {
resultText = replaceAll(resultText, token._capture, "");
return;
}
if (token._capture) {
var to = replaceTokenWith(token, actualTokens[actualTokenIndex], "_capture_to_message");
resultText = replaceAll(resultText, token._capture, to);
}
++actualTokenIndex;
});
return "\u3010".concat(id, "\u3011 ").concat(resultText, "\n\u89E3\u8AAC: https://github.com/textlint-ja/textlint-rule-ja-no-redundant-expression#").concat(id);
};
var reporter = function reporter(context) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var {
Syntax,
RuleError,
fixer
} = context;
var DefaultOptions = {
// https://textlint.github.io/docs/txtnode.html#type
allowNodeTypes: [Syntax.BlockQuote, Syntax.Link, Syntax.ReferenceDef, Syntax.Code],
dictOptions: {}
};
var dictOptions = options.dictOptions || DefaultOptions.dictOptions; // "disabled": trueな辞書は取り除く
var enabledDictionaryList = _dictionary.Dictionary.filter(dict => {
var dictOption = dictOptions[dict.id] || {};
var disabled = typeof dictOption.disabled === "boolean" ? dictOption.disabled : dict.disabled;
return !disabled;
});
var matchAll = (0, _morphemeMatchAll.createMatcher)(enabledDictionaryList);
var skipNodeTypes = options.allowNodeTypes || DefaultOptions.allowNodeTypes;
return (0, _textlintRuleHelper.wrapReportHandler)(context, {
ignoreNodeTypes: skipNodeTypes
}, report => {
return {
[Syntax.Paragraph](node) {
var source = new _textlintUtilToString.StringSource(node);
var text = source.toString();
return (0, _kuromojin.tokenize)(text).then(currentTokens => {
var matchResults = matchAll(currentTokens);
matchResults.forEach(matchResult => {
var dictOption = dictOptions[matchResult.dict.id] || {}; // "allows" オプションにマッチした場合はエラーを報告しない
var allows = dictOption.allows || matchResult.dict.allows;
var isAllowed = isTokensAllowed(matchResult.tokens, allows);
if (isAllowed) {
return;
} // エラー報告
var firstToken = matchResult.tokens[0];
var lastToken = matchResult.tokens[matchResult.tokens.length - 1];
var firstWordIndex = source.originalIndexFromIndex(Math.max(firstToken.word_position - 1, 0)) || 0;
var lastWordIndex = source.originalIndexFromIndex(Math.max(lastToken.word_position - 1, 0)) || 0; // エラーメッセージ
var message = createMessage({
id: matchResult.dict.id,
text: matchResult.dict.message,
matcherTokens: matchResult.dict.tokens,
skipped: matchResult.skipped,
actualTokens: matchResult.tokens
}); // 置換結果
var expected = createExpected({
expected: matchResult.dict.expected,
matcherTokens: matchResult.dict.tokens,
skipped: matchResult.skipped,
actualTokens: matchResult.tokens
});
var hasFixableResult = expected && tokensToString(matchResult.tokens) !== expected;
if (expected && hasFixableResult) {
var wordLength = lastToken.surface_form.length;
report(node, new RuleError(message, {
index: firstWordIndex,
fix: fixer.replaceTextRange([firstWordIndex, lastWordIndex + wordLength], expected)
}));
} else {
report(node, new RuleError(message, {
index: firstWordIndex
}));
}
});
});
}
};
});
};
var _default = {
linter: reporter,
fixer: reporter
};
exports.default = _default;
//# sourceMappingURL=index.js.map