From 398b8010280ad43b2cb1b771334b8cc9ba23ff28 Mon Sep 17 00:00:00 2001 From: Patrick Taylor Date: Wed, 24 Jul 2024 18:06:08 +0100 Subject: [PATCH] =?UTF-8?q?Moved=20process=20markdownlint=20results=20to?= =?UTF-8?q?=20a=20dedicated=20file=20=F0=9F=9A=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .markdownlint.json | 3 + .../markdownlint/__tests__/index.spec.ts | 165 +----------------- .../markdownlint/__tests__/loadConfig.spec.ts | 15 +- .../__tests__/processResults.spec.ts | 139 +++++++++++++++ src/linters/markdownlint/index.ts | 50 +----- src/linters/markdownlint/loadConfig.ts | 11 +- src/linters/markdownlint/processResults.ts | 52 ++++++ 7 files changed, 202 insertions(+), 233 deletions(-) create mode 100644 .markdownlint.json create mode 100644 src/linters/markdownlint/__tests__/processResults.spec.ts create mode 100644 src/linters/markdownlint/processResults.ts diff --git a/.markdownlint.json b/.markdownlint.json new file mode 100644 index 0000000..d7dd692 --- /dev/null +++ b/.markdownlint.json @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/lint-pilot/markdownlint.json" +} diff --git a/src/linters/markdownlint/__tests__/index.spec.ts b/src/linters/markdownlint/__tests__/index.spec.ts index 22d094b..139684a 100644 --- a/src/linters/markdownlint/__tests__/index.spec.ts +++ b/src/linters/markdownlint/__tests__/index.spec.ts @@ -70,166 +70,6 @@ describe('markdownlint', () => { } }) - it('resolves with results and a summary when markdownlint successfully lints (no files)', async () => { - jest.mocked(markdownlintAsync).mockResolvedValueOnce({}) - - expect(await markdownlintLib.lintFiles({ - files: [], - fix: false, - })).toStrictEqual({ - results: {}, - summary: { - deprecatedRules: [], - errorCount: 0, - fileCount: 0, - fixableErrorCount: 0, - fixableWarningCount: 0, - linter: 'MarkdownLint', - warningCount: 0, - }, - }) - }) - - it('resolves with results and a summary when markdownlint successfully lints (no errors)', async () => { - const lintResults: LintResults = { - 'README.md': [], - } - - jest.mocked(markdownlintAsync).mockResolvedValueOnce(lintResults) - - expect(await markdownlintLib.lintFiles({ - files: testFiles, - fix: false, - })).toStrictEqual({ - results: {}, - summary: { - deprecatedRules: [], - errorCount: 0, - fileCount: 1, - fixableErrorCount: 0, - fixableWarningCount: 0, - linter: 'MarkdownLint', - warningCount: 0, - }, - }) - }) - - it('resolves with results and a summary when markdownlint successfully lints (with errors)', async () => { - const commonResult = { - ruleNames: ['MD000', 'test-rule-name'], - ruleInformation: 'test-rule-information', - errorDetail: 'test-error-detail', - errorContext: 'test-error-context', - errorRange: [1, 2], - } - - const lintResults: LintResults = { - // No errors - 'CHANGELOG.md': [], - 'CONTRIBUTING.md': [{ - ...commonResult, - lineNumber: 1, - fixInfo: { - lineNumber: 1, - }, - ruleDescription: 'test-rule-description', - }], - // 5 errors - 'README.md': [{ - ...commonResult, - lineNumber: 7, - errorRange: [], - fixInfo: { - lineNumber: 7, - }, - ruleDescription: 'no-error-range', - }, { - ...commonResult, - errorDetail: '', - lineNumber: 9, - ruleDescription: 'no-error-detail', - }, { - ...commonResult, - lineNumber: 13, - ruleNames: ['MD000', 'test-rule-b'], - ruleDescription: 'sorted-by-name', - }, { - ...commonResult, - lineNumber: 13, - ruleNames: ['MD000', 'test-rule-a'], - ruleDescription: 'sorted-by-name', - }, { - ...commonResult, - errorDetail: '', - lineNumber: 3, - ruleDescription: 'sort-by-line-number', - }], - } - - const resultThemes = { - messageTheme: expect.any(Function), - positionTheme: expect.any(Function), - ruleTheme: expect.any(Function), - } - - jest.mocked(markdownlintAsync).mockResolvedValueOnce(lintResults) - - expect(await markdownlintLib.lintFiles({ - files: testFiles, - fix: false, - })).toStrictEqual({ - results: { - 'CONTRIBUTING.md': [{ - ...resultThemes, - message: 'test-rule-description: test-error-detail', - position: '1:1', - rule: 'test-rule-name', - severity: 'X', - }], - 'README.md': [{ - ...resultThemes, - message: 'sort-by-line-number', - position: '3:1', - rule: 'test-rule-name', - severity: 'X', - }, { - ...resultThemes, - message: 'no-error-range: test-error-detail', - position: '7', - rule: 'test-rule-name', - severity: 'X', - }, { - ...resultThemes, - message: 'no-error-detail', - position: '9:1', - rule: 'test-rule-name', - severity: 'X', - }, { - ...resultThemes, - message: 'sorted-by-name: test-error-detail', - position: '13:1', - rule: 'test-rule-a', - severity: 'X', - }, { - ...resultThemes, - message: 'sorted-by-name: test-error-detail', - position: '13:1', - rule: 'test-rule-b', - severity: 'X', - }], - }, - summary: { - deprecatedRules: [], - errorCount: 6, - fileCount: 3, - fixableErrorCount: 2, - fixableWarningCount: 0, - linter: 'MarkdownLint', - warningCount: 0, - }, - }) - }) - it('does not fix lint errors when the fix option is disabled', async () => { const lintResults: LintResults = { 'README.md': [], @@ -276,8 +116,9 @@ describe('markdownlint', () => { 'README.md': [], } - jest.mocked(markdownlintAsync).mockResolvedValueOnce(lintResultsWithError) - jest.mocked(markdownlintAsync).mockResolvedValueOnce(lintResultsWithoutError) + jest.mocked(markdownlintAsync) + .mockResolvedValueOnce(lintResultsWithError) + .mockResolvedValueOnce(lintResultsWithoutError) await markdownlintLib.lintFiles({ files: testFiles, diff --git a/src/linters/markdownlint/__tests__/loadConfig.spec.ts b/src/linters/markdownlint/__tests__/loadConfig.spec.ts index a7d2ac1..d3e9bbb 100644 --- a/src/linters/markdownlint/__tests__/loadConfig.spec.ts +++ b/src/linters/markdownlint/__tests__/loadConfig.spec.ts @@ -22,20 +22,7 @@ describe('loadConfig', () => { expect(markdownlint.readConfigSync).toHaveBeenCalledWith(`${process.cwd()}/.markdownlint.json`) }) - it('returns the development config when NODE_ENV is development', () => { - process.env.NODE_ENV = 'development' - - jest.mocked(fs.existsSync).mockReturnValueOnce(false) - - expect(loadConfig()).toStrictEqual(['development', { - default: true, - }]) - expect(markdownlint.readConfigSync).toHaveBeenCalledWith(expect.stringContaining('lint-pilot/config/markdownlint.json')) - }) - - it('returns the default config when NODE_ENV is production', () => { - process.env.NODE_ENV = 'production' - + it('returns the default config if no custom config exists', () => { jest.mocked(fs.existsSync).mockReturnValueOnce(false) expect(loadConfig()).toStrictEqual(['default', { diff --git a/src/linters/markdownlint/__tests__/processResults.spec.ts b/src/linters/markdownlint/__tests__/processResults.spec.ts new file mode 100644 index 0000000..fd2e7e4 --- /dev/null +++ b/src/linters/markdownlint/__tests__/processResults.spec.ts @@ -0,0 +1,139 @@ +import { expectedResultThemes, markdownlintError } from '@Jest/testData' + +import { type LintResults } from '../markdownlintAsync' +import processResults from '../processResults' + +describe('processResults', () => { + + it('returns results and a summary when there are no lint results', () => { + const report = processResults({}) + + expect(report).toStrictEqual({ + results: {}, + summary: { + deprecatedRules: [], + errorCount: 0, + fileCount: 0, + fixableErrorCount: 0, + fixableWarningCount: 0, + linter: 'MarkdownLint', + warningCount: 0, + }, + }) + }) + + it('returns results and a summary when there are no errors', () => { + const lintResults: LintResults = { + 'README.md': [], + } + + const report = processResults(lintResults) + + expect(report).toStrictEqual({ + results: {}, + summary: { + deprecatedRules: [], + errorCount: 0, + fileCount: 1, + fixableErrorCount: 0, + fixableWarningCount: 0, + linter: 'MarkdownLint', + warningCount: 0, + }, + }) + }) + + it('returns results sorted by lineNumber and a summary when there are errors', () => { + const lintResults: LintResults = { + // No errors + 'CHANGELOG.md': [], + 'CONTRIBUTING.md': [markdownlintError], + // 5 errors + 'README.md': [{ + ...markdownlintError, + lineNumber: 7, + errorRange: [], + ruleDescription: 'no-error-range', + }, { + ...markdownlintError, + errorDetail: '', + fixInfo: undefined, + lineNumber: 9, + ruleDescription: 'no-error-detail', + }, { + ...markdownlintError, + fixInfo: undefined, + lineNumber: 13, + ruleNames: ['MD000', 'test-rule-b'], + ruleDescription: 'sorted-by-name', + }, { + ...markdownlintError, + fixInfo: undefined, + lineNumber: 13, + ruleNames: ['MD000', 'test-rule-a'], + ruleDescription: 'sorted-by-name', + }, { + ...markdownlintError, + fixInfo: undefined, + errorDetail: '', + lineNumber: 3, + ruleDescription: 'sort-by-line-number', + }], + } + + const report = processResults(lintResults) + + expect(report).toStrictEqual({ + results: { + 'CONTRIBUTING.md': [{ + ...expectedResultThemes, + message: 'test-rule-description: test-error-detail', + position: '1:1', + rule: 'test-rule-name', + severity: 'X', + }], + 'README.md': [{ + ...expectedResultThemes, + message: 'sort-by-line-number', + position: '3:1', + rule: 'test-rule-name', + severity: 'X', + }, { + ...expectedResultThemes, + message: 'no-error-range: test-error-detail', + position: '7', + rule: 'test-rule-name', + severity: 'X', + }, { + ...expectedResultThemes, + message: 'no-error-detail', + position: '9:1', + rule: 'test-rule-name', + severity: 'X', + }, { + ...expectedResultThemes, + message: 'sorted-by-name: test-error-detail', + position: '13:1', + rule: 'test-rule-a', + severity: 'X', + }, { + ...expectedResultThemes, + message: 'sorted-by-name: test-error-detail', + position: '13:1', + rule: 'test-rule-b', + severity: 'X', + }], + }, + summary: { + deprecatedRules: [], + errorCount: 6, + fileCount: 3, + fixableErrorCount: 2, + fixableWarningCount: 0, + linter: 'MarkdownLint', + warningCount: 0, + }, + }) + }) + +}) diff --git a/src/linters/markdownlint/index.ts b/src/linters/markdownlint/index.ts index 6df315c..928c15a 100644 --- a/src/linters/markdownlint/index.ts +++ b/src/linters/markdownlint/index.ts @@ -1,57 +1,11 @@ -import { Linter, RuleSeverity } from '@Types' import colourLog from '@Utils/colourLog' -import { formatResult } from '@Utils/transform' -import type { LintFiles, LintReport, ReportResults, ReportSummary } from '@Types' +import type { LintFiles, LintReport } from '@Types' import fixFile from './fixFile' import loadConfig from './loadConfig' import markdownlintAsync, { type LintResults } from './markdownlintAsync' - -const processResults = (lintResults: LintResults): LintReport => { - const reportResults: ReportResults = {} - - const reportSummary: ReportSummary = { - deprecatedRules: [], - errorCount: 0, - fileCount: Object.keys(lintResults).length, - fixableErrorCount: 0, - fixableWarningCount: 0, - linter: Linter.Markdownlint, - warningCount: 0, - } - - Object.entries(lintResults).forEach(([file, errors]) => { - if (!errors.length) { - return - } - - reportResults[file] = [] - - reportSummary.errorCount += errors.length - - errors - .sort((a, b) => a.lineNumber - b.lineNumber || a.ruleNames[1].localeCompare(b.ruleNames[1])) - .forEach(({ errorDetail, errorRange, fixInfo, lineNumber, ruleDescription, ruleNames }) => { - reportResults[file].push(formatResult({ - column: errorRange?.length ? errorRange[0] : undefined, - lineNumber, - message: errorDetail?.length ? `${ruleDescription}: ${errorDetail}` : ruleDescription, - rule: ruleNames[1], - severity: RuleSeverity.ERROR, - })) - - if (fixInfo) { - reportSummary.fixableErrorCount += 1 - } - }) - }) - - return { - results: reportResults, - summary: reportSummary, - } -} +import processResults from './processResults' const lintFiles = async ({ files, fix }: LintFiles): Promise => { try { diff --git a/src/linters/markdownlint/loadConfig.ts b/src/linters/markdownlint/loadConfig.ts index fbf2642..011b98f 100644 --- a/src/linters/markdownlint/loadConfig.ts +++ b/src/linters/markdownlint/loadConfig.ts @@ -8,21 +8,14 @@ import colourLog from '@Utils/colourLog' const loadConfig = (): [string, Configuration] => { try { - // Custom Config + // Custom config const customConfigPath = `${process.cwd()}/.markdownlint.json` if (fs.existsSync(customConfigPath)) { return ['custom', markdownlint.readConfigSync(customConfigPath)] } + // Default config const __dirname = path.dirname(fileURLToPath(import.meta.url)) - - // Local config (if in development mode) - this block will be removed in production builds - if (process.env.NODE_ENV === 'development') { - const localConfigPath = path.resolve(__dirname, '../../../config/markdownlint.json') - return ['development', markdownlint.readConfigSync(localConfigPath)] - } - - // Local config (if in production mode) const localConfigPath = path.resolve(__dirname, './markdownlint.json') return ['default', markdownlint.readConfigSync(localConfigPath)] } catch (error) { diff --git a/src/linters/markdownlint/processResults.ts b/src/linters/markdownlint/processResults.ts new file mode 100644 index 0000000..61c51db --- /dev/null +++ b/src/linters/markdownlint/processResults.ts @@ -0,0 +1,52 @@ +import { Linter, RuleSeverity } from '@Types' +import { formatResult } from '@Utils/transform' + +import type { LintReport, ReportResults, ReportSummary } from '@Types' +import type { LintResults } from './markdownlintAsync' + +const processResults = (lintResults: LintResults): LintReport => { + const reportResults: ReportResults = {} + + const reportSummary: ReportSummary = { + deprecatedRules: [], + errorCount: 0, + fileCount: Object.keys(lintResults).length, + fixableErrorCount: 0, + fixableWarningCount: 0, + linter: Linter.Markdownlint, + warningCount: 0, + } + + Object.entries(lintResults).forEach(([file, errors]) => { + if (!errors.length) { + return + } + + reportResults[file] = [] + + reportSummary.errorCount += errors.length + + errors + .sort((a, b) => a.lineNumber - b.lineNumber || a.ruleNames[1].localeCompare(b.ruleNames[1])) + .forEach(({ errorDetail, errorRange, fixInfo, lineNumber, ruleDescription, ruleNames }) => { + reportResults[file].push(formatResult({ + column: errorRange?.length ? errorRange[0] : undefined, + lineNumber, + message: errorDetail?.length ? `${ruleDescription}: ${errorDetail}` : ruleDescription, + rule: ruleNames[1], + severity: RuleSeverity.ERROR, + })) + + if (fixInfo) { + reportSummary.fixableErrorCount += 1 + } + }) + }) + + return { + results: reportResults, + summary: reportSummary, + } +} + +export default processResults