1
0
mirror of https://github.com/sasjs/lint.git synced 2025-12-11 01:44:36 +00:00

Compare commits

...

2 Commits

Author SHA1 Message Date
Krishna Acondy
fb4cc2dd20 Merge pull request #18 from sasjs/lint-file-paths
feat(*): group folder and project diagnostics by file path
2021-04-02 09:13:30 +01:00
Krishna Acondy
09e2d051c4 feat(*): group folder and project diagnostics by file path 2021-04-02 09:02:22 +01:00
5 changed files with 51 additions and 26 deletions

View File

@@ -6,57 +6,61 @@ describe('lintFolder', () => {
it('should identify lint issues in a given folder', async () => { it('should identify lint issues in a given folder', async () => {
const results = await lintFolder(path.join(__dirname, '..')) const results = await lintFolder(path.join(__dirname, '..'))
expect(results.length).toEqual(8) expect(results.size).toEqual(1)
expect(results).toContainEqual({ const diagnostics = results.get(
path.join(__dirname, '..', 'Example File.sas')
)!
expect(diagnostics.length).toEqual(8)
expect(diagnostics).toContainEqual({
message: 'Line contains trailing spaces', message: 'Line contains trailing spaces',
lineNumber: 1, lineNumber: 1,
startColumnNumber: 1, startColumnNumber: 1,
endColumnNumber: 2, endColumnNumber: 2,
severity: Severity.Warning severity: Severity.Warning
}) })
expect(results).toContainEqual({ expect(diagnostics).toContainEqual({
message: 'Line contains trailing spaces', message: 'Line contains trailing spaces',
lineNumber: 2, lineNumber: 2,
startColumnNumber: 1, startColumnNumber: 1,
endColumnNumber: 2, endColumnNumber: 2,
severity: Severity.Warning severity: Severity.Warning
}) })
expect(results).toContainEqual({ expect(diagnostics).toContainEqual({
message: 'File name contains spaces', message: 'File name contains spaces',
lineNumber: 1, lineNumber: 1,
startColumnNumber: 1, startColumnNumber: 1,
endColumnNumber: 1, endColumnNumber: 1,
severity: Severity.Warning severity: Severity.Warning
}) })
expect(results).toContainEqual({ expect(diagnostics).toContainEqual({
message: 'File name contains uppercase characters', message: 'File name contains uppercase characters',
lineNumber: 1, lineNumber: 1,
startColumnNumber: 1, startColumnNumber: 1,
endColumnNumber: 1, endColumnNumber: 1,
severity: Severity.Warning severity: Severity.Warning
}) })
expect(results).toContainEqual({ expect(diagnostics).toContainEqual({
message: 'File missing Doxygen header', message: 'File missing Doxygen header',
lineNumber: 1, lineNumber: 1,
startColumnNumber: 1, startColumnNumber: 1,
endColumnNumber: 1, endColumnNumber: 1,
severity: Severity.Warning severity: Severity.Warning
}) })
expect(results).toContainEqual({ expect(diagnostics).toContainEqual({
message: 'Line contains encoded password', message: 'Line contains encoded password',
lineNumber: 5, lineNumber: 5,
startColumnNumber: 10, startColumnNumber: 10,
endColumnNumber: 18, endColumnNumber: 18,
severity: Severity.Error severity: Severity.Error
}) })
expect(results).toContainEqual({ expect(diagnostics).toContainEqual({
message: 'Line is indented with a tab', message: 'Line is indented with a tab',
lineNumber: 7, lineNumber: 7,
startColumnNumber: 1, startColumnNumber: 1,
endColumnNumber: 1, endColumnNumber: 1,
severity: Severity.Warning severity: Severity.Warning
}) })
expect(results).toContainEqual({ expect(diagnostics).toContainEqual({
message: 'Line has incorrect indentation - 3 spaces', message: 'Line has incorrect indentation - 3 spaces',
lineNumber: 6, lineNumber: 6,
startColumnNumber: 1, startColumnNumber: 1,

View File

@@ -20,19 +20,18 @@ const excludeFolders = [
* Analyses and produces a set of diagnostics for the folder at the given path. * 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 {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. * @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<Map<string, Diagnostic[]>>} 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 ( export const lintFolder = async (
folderPath: string, folderPath: string,
configuration?: LintConfig configuration?: LintConfig
) => { ) => {
const config = configuration || (await getLintConfig()) const config = configuration || (await getLintConfig())
const diagnostics: Diagnostic[] = [] let diagnostics: Map<string, Diagnostic[]> = new Map<string, Diagnostic[]>()
const fileNames = await listSasFiles(folderPath) const fileNames = await listSasFiles(folderPath)
await asyncForEach(fileNames, async (fileName) => { await asyncForEach(fileNames, async (fileName) => {
diagnostics.push( const filePath = path.join(folderPath, fileName)
...(await lintFile(path.join(folderPath, fileName), config)) diagnostics.set(filePath, await lintFile(filePath, config))
)
}) })
const subFolders = (await listSubFoldersInFolder(folderPath)).filter( const subFolders = (await listSubFoldersInFolder(folderPath)).filter(
@@ -40,9 +39,11 @@ export const lintFolder = async (
) )
await asyncForEach(subFolders, async (subFolder) => { await asyncForEach(subFolders, async (subFolder) => {
diagnostics.push( const subFolderDiagnostics = await lintFolder(
...(await lintFolder(path.join(folderPath, subFolder), config)) path.join(folderPath, subFolder),
config
) )
diagnostics = new Map([...diagnostics, ...subFolderDiagnostics])
}) })
return diagnostics return diagnostics

View File

@@ -1,62 +1,71 @@
import { lintProject } from './lintProject' import { lintProject } from './lintProject'
import { Severity } from '../types/Severity' import { Severity } from '../types/Severity'
import * as utils from '../utils'
import path from 'path' import path from 'path'
jest.mock('../utils')
describe('lintProject', () => { describe('lintProject', () => {
it('should identify lint issues in a given project', async () => { it('should identify lint issues in a given project', async () => {
jest
.spyOn(utils, 'getProjectRoot')
.mockImplementationOnce(() => Promise.resolve(path.join(__dirname, '..')))
const results = await lintProject() const results = await lintProject()
expect(results.length).toEqual(8) expect(results.size).toEqual(1)
expect(results).toContainEqual({ const diagnostics = results.get(
path.join(__dirname, '..', 'Example File.sas')
)!
expect(diagnostics.length).toEqual(8)
expect(diagnostics).toContainEqual({
message: 'Line contains trailing spaces', message: 'Line contains trailing spaces',
lineNumber: 1, lineNumber: 1,
startColumnNumber: 1, startColumnNumber: 1,
endColumnNumber: 2, endColumnNumber: 2,
severity: Severity.Warning severity: Severity.Warning
}) })
expect(results).toContainEqual({ expect(diagnostics).toContainEqual({
message: 'Line contains trailing spaces', message: 'Line contains trailing spaces',
lineNumber: 2, lineNumber: 2,
startColumnNumber: 1, startColumnNumber: 1,
endColumnNumber: 2, endColumnNumber: 2,
severity: Severity.Warning severity: Severity.Warning
}) })
expect(results).toContainEqual({ expect(diagnostics).toContainEqual({
message: 'File name contains spaces', message: 'File name contains spaces',
lineNumber: 1, lineNumber: 1,
startColumnNumber: 1, startColumnNumber: 1,
endColumnNumber: 1, endColumnNumber: 1,
severity: Severity.Warning severity: Severity.Warning
}) })
expect(results).toContainEqual({ expect(diagnostics).toContainEqual({
message: 'File name contains uppercase characters', message: 'File name contains uppercase characters',
lineNumber: 1, lineNumber: 1,
startColumnNumber: 1, startColumnNumber: 1,
endColumnNumber: 1, endColumnNumber: 1,
severity: Severity.Warning severity: Severity.Warning
}) })
expect(results).toContainEqual({ expect(diagnostics).toContainEqual({
message: 'File missing Doxygen header', message: 'File missing Doxygen header',
lineNumber: 1, lineNumber: 1,
startColumnNumber: 1, startColumnNumber: 1,
endColumnNumber: 1, endColumnNumber: 1,
severity: Severity.Warning severity: Severity.Warning
}) })
expect(results).toContainEqual({ expect(diagnostics).toContainEqual({
message: 'Line contains encoded password', message: 'Line contains encoded password',
lineNumber: 5, lineNumber: 5,
startColumnNumber: 10, startColumnNumber: 10,
endColumnNumber: 18, endColumnNumber: 18,
severity: Severity.Error severity: Severity.Error
}) })
expect(results).toContainEqual({ expect(diagnostics).toContainEqual({
message: 'Line is indented with a tab', message: 'Line is indented with a tab',
lineNumber: 7, lineNumber: 7,
startColumnNumber: 1, startColumnNumber: 1,
endColumnNumber: 1, endColumnNumber: 1,
severity: Severity.Warning severity: Severity.Warning
}) })
expect(results).toContainEqual({ expect(diagnostics).toContainEqual({
message: 'Line has incorrect indentation - 3 spaces', message: 'Line has incorrect indentation - 3 spaces',
lineNumber: 6, lineNumber: 6,
startColumnNumber: 1, startColumnNumber: 1,
@@ -64,4 +73,14 @@ describe('lintProject', () => {
severity: Severity.Warning 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.'
)
})
}) })

View File

@@ -3,7 +3,7 @@ import { lintFolder } from './lintFolder'
/** /**
* Analyses and produces a set of diagnostics for the current project. * 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<Map<string, Diagnostic[]>>} 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 () => { export const lintProject = async () => {
const projectRoot = const projectRoot =

View File

@@ -7,6 +7,7 @@
], ],
"target": "es5", "target": "es5",
"module": "commonjs", "module": "commonjs",
"downlevelIteration": true,
"moduleResolution": "node", "moduleResolution": "node",
"esModuleInterop": true, "esModuleInterop": true,
"declaration": true, "declaration": true,