From 09e2d051c485f5c1a499c6f93f1976b57cdf63ae Mon Sep 17 00:00:00 2001 From: Krishna Acondy Date: Fri, 2 Apr 2021 09:02:22 +0100 Subject: [PATCH] feat(*): group folder and project diagnostics by file path --- src/lint/lintFolder.spec.ts | 22 ++++++++++++--------- src/lint/lintFolder.ts | 15 ++++++++------- src/lint/lintProject.spec.ts | 37 +++++++++++++++++++++++++++--------- src/lint/lintProject.ts | 2 +- tsconfig.json | 1 + 5 files changed, 51 insertions(+), 26 deletions(-) diff --git a/src/lint/lintFolder.spec.ts b/src/lint/lintFolder.spec.ts index f33ee7d..7124d3e 100644 --- a/src/lint/lintFolder.spec.ts +++ b/src/lint/lintFolder.spec.ts @@ -6,57 +6,61 @@ describe('lintFolder', () => { it('should identify lint issues in a given folder', async () => { const results = await lintFolder(path.join(__dirname, '..')) - expect(results.length).toEqual(8) - expect(results).toContainEqual({ + expect(results.size).toEqual(1) + const diagnostics = results.get( + path.join(__dirname, '..', 'Example File.sas') + )! + expect(diagnostics.length).toEqual(8) + expect(diagnostics).toContainEqual({ message: 'Line contains trailing spaces', lineNumber: 1, startColumnNumber: 1, endColumnNumber: 2, severity: Severity.Warning }) - expect(results).toContainEqual({ + expect(diagnostics).toContainEqual({ message: 'Line contains trailing spaces', lineNumber: 2, startColumnNumber: 1, endColumnNumber: 2, severity: Severity.Warning }) - expect(results).toContainEqual({ + expect(diagnostics).toContainEqual({ message: 'File name contains spaces', lineNumber: 1, startColumnNumber: 1, endColumnNumber: 1, severity: Severity.Warning }) - expect(results).toContainEqual({ + expect(diagnostics).toContainEqual({ message: 'File name contains uppercase characters', lineNumber: 1, startColumnNumber: 1, endColumnNumber: 1, severity: Severity.Warning }) - expect(results).toContainEqual({ + expect(diagnostics).toContainEqual({ message: 'File missing Doxygen header', lineNumber: 1, startColumnNumber: 1, endColumnNumber: 1, severity: Severity.Warning }) - expect(results).toContainEqual({ + expect(diagnostics).toContainEqual({ message: 'Line contains encoded password', lineNumber: 5, startColumnNumber: 10, endColumnNumber: 18, severity: Severity.Error }) - expect(results).toContainEqual({ + expect(diagnostics).toContainEqual({ message: 'Line is indented with a tab', lineNumber: 7, startColumnNumber: 1, endColumnNumber: 1, severity: Severity.Warning }) - expect(results).toContainEqual({ + expect(diagnostics).toContainEqual({ message: 'Line has incorrect indentation - 3 spaces', lineNumber: 6, startColumnNumber: 1, diff --git a/src/lint/lintFolder.ts b/src/lint/lintFolder.ts index 7a2c164..22686ac 100644 --- a/src/lint/lintFolder.ts +++ b/src/lint/lintFolder.ts @@ -20,19 +20,18 @@ const excludeFolders = [ * Analyses and produces a set of diagnostics for the folder at the given path. * @param {string} folderPath - the path to the folder to be linted. * @param {LintConfig} configuration - an optional configuration. When not passed in, this is read from the .sasjslint file. - * @returns {Diagnostic[]} array of diagnostic objects, each containing a warning, line number and column number. + * @returns {Promise>} Resolves with a map with array of diagnostic objects, each containing a warning, line number and column number, and grouped by file path. */ export const lintFolder = async ( folderPath: string, configuration?: LintConfig ) => { const config = configuration || (await getLintConfig()) - const diagnostics: Diagnostic[] = [] + let diagnostics: Map = new Map() const fileNames = await listSasFiles(folderPath) await asyncForEach(fileNames, async (fileName) => { - diagnostics.push( - ...(await lintFile(path.join(folderPath, fileName), config)) - ) + const filePath = path.join(folderPath, fileName) + diagnostics.set(filePath, await lintFile(filePath, config)) }) const subFolders = (await listSubFoldersInFolder(folderPath)).filter( @@ -40,9 +39,11 @@ export const lintFolder = async ( ) await asyncForEach(subFolders, async (subFolder) => { - diagnostics.push( - ...(await lintFolder(path.join(folderPath, subFolder), config)) + const subFolderDiagnostics = await lintFolder( + path.join(folderPath, subFolder), + config ) + diagnostics = new Map([...diagnostics, ...subFolderDiagnostics]) }) return diagnostics diff --git a/src/lint/lintProject.spec.ts b/src/lint/lintProject.spec.ts index 635bf17..3a0b200 100644 --- a/src/lint/lintProject.spec.ts +++ b/src/lint/lintProject.spec.ts @@ -1,62 +1,71 @@ import { lintProject } from './lintProject' import { Severity } from '../types/Severity' +import * as utils from '../utils' import path from 'path' +jest.mock('../utils') describe('lintProject', () => { it('should identify lint issues in a given project', async () => { + jest + .spyOn(utils, 'getProjectRoot') + .mockImplementationOnce(() => Promise.resolve(path.join(__dirname, '..'))) const results = await lintProject() - expect(results.length).toEqual(8) - expect(results).toContainEqual({ + expect(results.size).toEqual(1) + const diagnostics = results.get( + path.join(__dirname, '..', 'Example File.sas') + )! + expect(diagnostics.length).toEqual(8) + expect(diagnostics).toContainEqual({ message: 'Line contains trailing spaces', lineNumber: 1, startColumnNumber: 1, endColumnNumber: 2, severity: Severity.Warning }) - expect(results).toContainEqual({ + expect(diagnostics).toContainEqual({ message: 'Line contains trailing spaces', lineNumber: 2, startColumnNumber: 1, endColumnNumber: 2, severity: Severity.Warning }) - expect(results).toContainEqual({ + expect(diagnostics).toContainEqual({ message: 'File name contains spaces', lineNumber: 1, startColumnNumber: 1, endColumnNumber: 1, severity: Severity.Warning }) - expect(results).toContainEqual({ + expect(diagnostics).toContainEqual({ message: 'File name contains uppercase characters', lineNumber: 1, startColumnNumber: 1, endColumnNumber: 1, severity: Severity.Warning }) - expect(results).toContainEqual({ + expect(diagnostics).toContainEqual({ message: 'File missing Doxygen header', lineNumber: 1, startColumnNumber: 1, endColumnNumber: 1, severity: Severity.Warning }) - expect(results).toContainEqual({ + expect(diagnostics).toContainEqual({ message: 'Line contains encoded password', lineNumber: 5, startColumnNumber: 10, endColumnNumber: 18, severity: Severity.Error }) - expect(results).toContainEqual({ + expect(diagnostics).toContainEqual({ message: 'Line is indented with a tab', lineNumber: 7, startColumnNumber: 1, endColumnNumber: 1, severity: Severity.Warning }) - expect(results).toContainEqual({ + expect(diagnostics).toContainEqual({ message: 'Line has incorrect indentation - 3 spaces', lineNumber: 6, startColumnNumber: 1, @@ -64,4 +73,14 @@ describe('lintProject', () => { severity: Severity.Warning }) }) + + it('should throw an error when a project root is not found', async () => { + jest + .spyOn(utils, 'getProjectRoot') + .mockImplementationOnce(() => Promise.resolve('')) + + await expect(lintProject()).rejects.toThrowError( + 'SASjs Project Root was not found.' + ) + }) }) diff --git a/src/lint/lintProject.ts b/src/lint/lintProject.ts index 9712ee9..2c9c524 100644 --- a/src/lint/lintProject.ts +++ b/src/lint/lintProject.ts @@ -3,7 +3,7 @@ import { lintFolder } from './lintFolder' /** * Analyses and produces a set of diagnostics for the current project. - * @returns {Diagnostic[]} array of diagnostic objects, each containing a warning, line number and column number. + * @returns {Promise>} Resolves with a map with array of diagnostic objects, each containing a warning, line number and column number, and grouped by file path. */ export const lintProject = async () => { const projectRoot = diff --git a/tsconfig.json b/tsconfig.json index 50fe783..45fe93b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,6 +7,7 @@ ], "target": "es5", "module": "commonjs", + "downlevelIteration": true, "moduleResolution": "node", "esModuleInterop": true, "declaration": true,