UNPKG

textlint-rule-ja-no-redundant-expression

Version:
232 lines (190 loc) 6.76 kB
// 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