diff --git a/Makefile b/Makefile index 7715d73..6001905 100644 --- a/Makefile +++ b/Makefile @@ -7,10 +7,10 @@ bash: -v ./bin:/usr/local/bin \ hexlet/languagetool-cli bash -run: +check: docker run --rm \ -v ./fixtures:/content \ - -v ./bin:/usr/local/bin \ + -v ./bin:/LanguageTool-6.3/bin \ -v ./src:/LanguageTool-6.3/src \ hexlet/languagetool-cli \ node ./bin/check.js diff --git a/bin/check.js b/bin/check.js index 7a92b83..47301b9 100644 --- a/bin/check.js +++ b/bin/check.js @@ -1,10 +1,14 @@ #!/usr/bin/env node import { exec } from 'child_process'; -import { runCheck } from '../src/index.js'; +import { getErrors, formatErrors } from '../src/index.js'; -exec('/LanguageTool-6.3/start.sh >/dev/null 2>&1 &', () => setTimeout(async () => { +exec('sh /LanguageTool-6.3/start.sh >/dev/null 2>&1 &', () => setTimeout(async () => { const rules = process.argv.slice(2); - - runCheck(rules); + const errors = await getErrors('/content', rules); + if (errors) { + const formattedErrors = formatErrors(errors); + console.log(formattedErrors.join('\n------------------------')); + process.exit(1); + } }, 5000)); diff --git a/bin/fix.js b/bin/fix.js index 81368ef..b677a41 100644 --- a/bin/fix.js +++ b/bin/fix.js @@ -3,7 +3,9 @@ import { exec } from 'child_process'; import { fix } from '../src/index.js'; -exec('/LanguageTool-6.3/start.sh >/dev/null 2>&1 &', () => setTimeout(() => { +exec('sh /LanguageTool-6.3/start.sh >/dev/null 2>&1 &', () => setTimeout(() => { const rules = process.argv.slice(2); - fix(rules); + fix(rules).then(() => { + console.log('------------------DONE-----------------'); + }); }, 5000)); diff --git a/bin/getWords.js b/bin/getWords.js index 0c9a796..c7cd329 100644 --- a/bin/getWords.js +++ b/bin/getWords.js @@ -3,7 +3,7 @@ import { exec } from 'child_process'; import { getWrongWords } from '../src/index.js'; -exec('/LanguageTool-6.3/start.sh >/dev/null 2>&1 &', () => setTimeout(async () => { +exec('sh /LanguageTool-6.3/start.sh >/dev/null 2>&1 &', () => setTimeout(async () => { const rules = process.argv.slice(2); getWrongWords(rules); }, 5000)); diff --git a/src/index.js b/src/index.js index 0605ec1..531c787 100644 --- a/src/index.js +++ b/src/index.js @@ -6,7 +6,7 @@ import { fromMarkdown } from 'mdast-util-from-markdown'; import { toMarkdown } from 'mdast-util-to-markdown' import { - getPaths, + getFilePaths, formatMessage, parseCheckedResult, printFixResult, @@ -35,53 +35,9 @@ const isFiltered = (word) => { return false; }; -const runCheck = async (rules = []) => { - - const filePaths = await getPaths(); - - const promises = filePaths.map(async (fullpath) => { - const sourceContent = fs.readFileSync(fullpath, 'utf-8'); - - const fileName = fullpath.split('/').slice(2).join('/'); - - const parser = new Checker(rules); - - const content = parser.filterContent(sourceContent); - - const checkResult = await check(content, rules); - - const result= checkResult.matches.map((match) => { - const { offset, length, replacements } = match; - const leftPart = content.slice(0, offset); - const lineCount = leftPart.split('\n').length; - const word = content.slice(offset, offset + length); - - if (isFiltered(word)) { - return null; - } - - const resultText = [ - formatMessage(`${fileName}#${lineCount}`, 'blue'), - formatMessage(`${match.message} в слове "${word}" => ${match.sentence}`, 'red'), - formatMessage('Предлагаемые варианты:', 'blue'), - formatMessage(replacements.map((replacement) => replacement.value).join('\n--\n'), 'green'), - ]; - - return resultText.join('\n'); - }); - - console.log(result.filter((item) => item).join('\n----------------------\n')); - console.log(`-------------------${fileName} done -----------------`); - }); - - Promise.all(promises).then(() => { - console.log('------------------DONE-----------------'); - }); -}; - const getWrongWords = async (rules = []) => { - const filePaths = await getPaths(); + const filePaths = await getFilePaths(); const promises = filePaths.map(async (fullpath) => { const content = fs.readFileSync(fullpath, 'utf-8'); @@ -108,7 +64,6 @@ const getWrongWords = async (rules = []) => { }; const checkContent = async (content, rules) => { - const checkResults = await check(content, rules); const results = checkResults.matches; @@ -158,7 +113,7 @@ const checkTree = (source, rules) => { } const fix = async (rules = []) => { - const filePaths = await getPaths(); + const filePaths = await getFilePaths(); const promises = filePaths.map(async (fullpath) => { const content = fs.readFileSync(fullpath, 'utf-8'); const fileName = fullpath.split('/').slice(2).join('/'); @@ -176,13 +131,93 @@ const fix = async (rules = []) => { printFixResult(content, finalResult, fileName); }); - Promise.all(promises).then(() => { - console.log('------------------DONE-----------------'); + return Promise.all(promises); +}; + +const getErrors = async (dirPath = '/content', rules = []) => { + const filePaths = await getFilePaths(dirPath); + + const promises = filePaths.map(async (fullpath) => { + const sourceContent = fs.readFileSync(fullpath, 'utf-8'); + + const fileName = fullpath.split('/').slice(2).join('/'); + + const parser = new Checker(rules); + + const content = parser.filterContent(sourceContent); + + const checkResult = await check(content, rules); + + const resultCheckFile = checkResult.matches.map((match) => { + const { offset, length, replacements } = match; + const leftPart = content.slice(0, offset); + const lineNumber = leftPart.split('\n').length; + const word = content.slice(offset, offset + length); + + if (isFiltered(word)) { + return null; + } + + const result = { + fileName, + lineNumber, + match, + replacements + }; + + return result; + }); + + return resultCheckFile; }); + + return Promise.all(promises).then((results) => results.flat()).catch((e) => console.log(e)); }; +const formatContextMessage = (context, offset, length) => { + const leftPart = context.slice(0, offset); + const errorPart = context.slice(offset, offset + length); + const rightPart = context.slice(offset + length); + + const formattedErrorPath = formatMessage(errorPart, 'red'); + + const result = `${leftPart}${formattedErrorPath}${rightPart}`; + + return result; +} + +const formatError = (error) => { + const { + fileName, + lineNumber, + match, + replacements, + } = error; + + const fileLineMessage = formatMessage(`${fileName}#${lineNumber}`, 'blue'); + const contextMessage = formatContextMessage(match.context.text, match.context.offset, match.context.length); + + const errorMessage = formatMessage(match.message, 'red'); + + const formattedReplacements = replacements.map((replacement) => formatMessage(replacement.value, 'green')).join(', '); + + const replacementsMessage = `${formatMessage('Предлагаемые варианты:\n', 'blue')}${formattedReplacements}`; + + const result = [ + fileLineMessage, + contextMessage, + errorMessage, + formattedReplacements ? replacementsMessage : null, + ].filter((item) => item !== null).join('\n'); + + return result; +}; + +const formatErrors = (errors) => errors.map(formatError); + export { - runCheck, fix, getWrongWords, + getErrors, + formatErrors, }; diff --git a/src/languageToolApi.js b/src/languageToolApi.js index d2f86e0..fb48e76 100644 --- a/src/languageToolApi.js +++ b/src/languageToolApi.js @@ -22,10 +22,7 @@ export const check = async (content, rules = []) => { return response.data; }; -const addWords = (words) => { - // const content = fs.readFileSync('ignore_dictionary.txt', 'utf-8'); - // const words = content.split(/\s/); - +export const addWords = (words) => { const url = new URL('/v2/add', baseUrl); const promises = words.map((word) => { diff --git a/src/markdownParser.js b/src/markdownParser.js index c861690..003ec98 100644 --- a/src/markdownParser.js +++ b/src/markdownParser.js @@ -3,9 +3,6 @@ import { toMarkdown } from 'mdast-util-to-markdown' import { v4 as uuidv4 } from 'uuid'; import _ from 'lodash'; import fs from 'fs'; -import path from 'path'; - -import { check } from './languageToolApi.js'; class Parser { // https://github.com/syntax-tree/mdast#nodes @@ -22,43 +19,19 @@ class Parser { } -isFiltered(word) { - if (this.dictionary.includes(word)) { - return true; - } - - if (word.includes(' ')) { - return true; - } - - return false; -}; - - async checkContent(content) { - const checkResult = await check(content, rules); - const result= checkResult.matches.map((match) => { - const { offset, length, replacements } = match; - const leftPart = content.slice(0, offset); - const lineCount = leftPart.split('\n').length; - const word = content.slice(offset, offset + length); - - if (isFiltered(word, filterWords)) { - return null; - } + isFiltered(word) { + if (this.dictionary.includes(word)) { + return true; + } - const resultText = [ - formatMessage(`${fileName}#${lineCount}`, 'blue'), - formatMessage(`${match.message} в слове "${word}" => ${match.sentence}`, 'red'), - formatMessage('Предлагаемые варианты:', 'blue'), - formatMessage(replacements.map((replacement) => replacement.value).join('\n--\n'), 'green'), - ]; + if (word.includes(' ')) { + return true; + } - return resultText.join('\n'); - }); - - return result.filter((item) => item).join('\n----------------------\n'); + return false; } + filterContent(content) { const mkTree = fromMarkdown(content); const iter = (tree) => { diff --git a/src/utils.js b/src/utils.js index d3a8022..c99967a 100644 --- a/src/utils.js +++ b/src/utils.js @@ -5,7 +5,7 @@ import fs from 'fs/promises'; import path from 'path'; import _ from 'lodash'; -const extensions = ['.md']; +const defaultExtensions = ['.md']; export const formatMessage = (msg, color = 'dark') => { if (!clc[color]) { @@ -16,7 +16,7 @@ export const formatMessage = (msg, color = 'dark') => { export const formatError = (err) => clc.red(err); -export const getPaths = async (dirpath = '/content') => { +export const getFilePaths = async (dirpath, extensions = defaultExtensions) => { const fileNames = await fs.readdir(dirpath, { recursive: true }); const filePaths = fileNames.filter((filename) => extensions.includes(path.extname(filename).toLowerCase()));