1
0
mirror of https://github.com/sasjs/lint.git synced 2026-01-09 21:40:06 +00:00

chore(*): organise rules into folders by type

This commit is contained in:
Krishna Acondy
2021-04-07 16:34:33 +01:00
parent cc33ebb6e6
commit c9b6c3af95
26 changed files with 80 additions and 66 deletions

View File

@@ -0,0 +1,74 @@
import { LintConfig, Severity } from '../../types'
import { indentationMultiple } from './indentationMultiple'
describe('indentationMultiple', () => {
it('should return an empty array when the line is indented by two spaces', () => {
const line = " %put 'hello';"
const config = new LintConfig({ indentationMultiple: 2 })
expect(indentationMultiple.test(line, 1, config)).toEqual([])
})
it('should return an empty array when the line is indented by a multiple of 2 spaces', () => {
const line = " %put 'hello';"
const config = new LintConfig({ indentationMultiple: 2 })
expect(indentationMultiple.test(line, 1, config)).toEqual([])
})
it('should ignore indentation when the multiple is set to 0', () => {
const line = " %put 'hello';"
const config = new LintConfig({ indentationMultiple: 0 })
expect(indentationMultiple.test(line, 1, config)).toEqual([])
})
it('should return an empty array when the line is not indented', () => {
const line = "%put 'hello';"
const config = new LintConfig({ indentationMultiple: 2 })
expect(indentationMultiple.test(line, 1, config)).toEqual([])
})
it('should return an array with a single diagnostic when the line is indented incorrectly', () => {
const line = " %put 'hello';"
const config = new LintConfig({ indentationMultiple: 2 })
expect(indentationMultiple.test(line, 1, config)).toEqual([
{
message: `Line has incorrect indentation - 3 spaces`,
lineNumber: 1,
startColumnNumber: 1,
endColumnNumber: 1,
severity: Severity.Warning
}
])
})
it('should return an array with a single diagnostic when the line is indented incorrectly', () => {
const line = " %put 'hello';"
const config = new LintConfig({ indentationMultiple: 3 })
expect(indentationMultiple.test(line, 1, config)).toEqual([
{
message: `Line has incorrect indentation - 2 spaces`,
lineNumber: 1,
startColumnNumber: 1,
endColumnNumber: 1,
severity: Severity.Warning
}
])
})
it('should fall back to a default of 2 spaces', () => {
const line = " %put 'hello';"
expect(indentationMultiple.test(line, 1)).toEqual([
{
message: `Line has incorrect indentation - 1 space`,
lineNumber: 1,
startColumnNumber: 1,
endColumnNumber: 1,
severity: Severity.Warning
}
])
})
it('should return an empty array for lines within the default indentation', () => {
const line = " %put 'hello';"
expect(indentationMultiple.test(line, 1)).toEqual([])
})
})

View File

@@ -0,0 +1,41 @@
import { LintConfig } from '../../types'
import { LineLintRule } from '../../types/LintRule'
import { LintRuleType } from '../../types/LintRuleType'
import { Severity } from '../../types/Severity'
const name = 'indentationMultiple'
const description = 'Ensure indentation by a multiple of the configured number.'
const message = 'Line has incorrect indentation'
const test = (value: string, lineNumber: number, config?: LintConfig) => {
if (!value.startsWith(' ')) return []
const indentationMultiple = isNaN(config?.indentationMultiple as number)
? 2
: config!.indentationMultiple
if (indentationMultiple === 0) return []
const numberOfSpaces = value.search(/\S|$/)
if (numberOfSpaces % indentationMultiple! === 0) return []
return [
{
message: `${message} - ${numberOfSpaces} ${
numberOfSpaces === 1 ? 'space' : 'spaces'
}`,
lineNumber,
startColumnNumber: 1,
endColumnNumber: 1,
severity: Severity.Warning
}
]
}
/**
* Lint rule that checks if a line is indented by a multiple of the configured indentation multiple.
*/
export const indentationMultiple: LineLintRule = {
type: LintRuleType.Line,
name,
description,
message,
test
}

5
src/rules/line/index.ts Normal file
View File

@@ -0,0 +1,5 @@
export { indentationMultiple } from './indentationMultiple'
export { maxLineLength } from './maxLineLength'
export { noEncodedPasswords } from './noEncodedPasswords'
export { noTabIndentation } from './noTabIndentation'
export { noTrailingSpaces } from './noTrailingSpaces'

View File

@@ -0,0 +1,44 @@
import { LintConfig, Severity } from '../../types'
import { maxLineLength } from './maxLineLength'
describe('maxLineLength', () => {
it('should return an empty array when the line is within the specified length', () => {
const line = "%put 'hello';"
const config = new LintConfig({ maxLineLength: 60 })
expect(maxLineLength.test(line, 1, config)).toEqual([])
})
it('should return an array with a single diagnostic when the line exceeds the specified length', () => {
const line = "%put 'hello';"
const config = new LintConfig({ maxLineLength: 10 })
expect(maxLineLength.test(line, 1, config)).toEqual([
{
message: `Line exceeds maximum length by 3 characters`,
lineNumber: 1,
startColumnNumber: 1,
endColumnNumber: 1,
severity: Severity.Warning
}
])
})
it('should fall back to a default of 80 characters', () => {
const line =
'Prow scuttle parrel provost Sail ho shrouds spirits boom mizzenmast yardarm. Pinnace holystone.'
expect(maxLineLength.test(line, 1)).toEqual([
{
message: `Line exceeds maximum length by 15 characters`,
lineNumber: 1,
startColumnNumber: 1,
endColumnNumber: 1,
severity: Severity.Warning
}
])
})
it('should return an empty array for lines within the default length', () => {
const line =
'Prow scuttle parrel provost Sail ho shrouds spirits boom mizzenmast yard'
expect(maxLineLength.test(line, 1)).toEqual([])
})
})

View File

@@ -0,0 +1,32 @@
import { LintConfig } from '../../types'
import { LineLintRule } from '../../types/LintRule'
import { LintRuleType } from '../../types/LintRuleType'
import { Severity } from '../../types/Severity'
const name = 'maxLineLength'
const description = 'Restrict lines to the specified length.'
const message = 'Line exceeds maximum length'
const test = (value: string, lineNumber: number, config?: LintConfig) => {
const maxLineLength = config?.maxLineLength || 80
if (value.length <= maxLineLength) return []
return [
{
message: `${message} by ${value.length - maxLineLength} characters`,
lineNumber,
startColumnNumber: 1,
endColumnNumber: 1,
severity: Severity.Warning
}
]
}
/**
* Lint rule that checks if a line has exceeded the configured maximum length.
*/
export const maxLineLength: LineLintRule = {
type: LintRuleType.Line,
name,
description,
message,
test
}

View File

@@ -0,0 +1,55 @@
import { Severity } from '../../types/Severity'
import { noEncodedPasswords } from './noEncodedPasswords'
describe('noEncodedPasswords', () => {
it('should return an empty array when the line has no encoded passwords', () => {
const line = "%put 'hello';"
expect(noEncodedPasswords.test(line, 1)).toEqual([])
})
it('should return an array with a single diagnostic when the line has a SASENC password', () => {
const line = "%put '{SASENC}'; "
expect(noEncodedPasswords.test(line, 1)).toEqual([
{
message: 'Line contains encoded password',
lineNumber: 1,
startColumnNumber: 7,
endColumnNumber: 15,
severity: Severity.Error
}
])
})
it('should return an array with a single diagnostic when the line has an encoded password', () => {
const line = "%put '{SAS001}'; "
expect(noEncodedPasswords.test(line, 1)).toEqual([
{
message: 'Line contains encoded password',
lineNumber: 1,
startColumnNumber: 7,
endColumnNumber: 15,
severity: Severity.Error
}
])
})
it('should return an array with multiple diagnostics when the line has encoded passwords', () => {
const line = "%put '{SAS001} {SAS002}'; "
expect(noEncodedPasswords.test(line, 1)).toEqual([
{
message: 'Line contains encoded password',
lineNumber: 1,
startColumnNumber: 7,
endColumnNumber: 15,
severity: Severity.Error
},
{
message: 'Line contains encoded password',
lineNumber: 1,
startColumnNumber: 16,
endColumnNumber: 24,
severity: Severity.Error
}
])
})
})

View File

@@ -0,0 +1,30 @@
import { LineLintRule } from '../../types/LintRule'
import { LintRuleType } from '../../types/LintRuleType'
import { Severity } from '../../types/Severity'
const name = 'noEncodedPasswords'
const description = 'Disallow encoded passwords in SAS code.'
const message = 'Line contains encoded password'
const test = (value: string, lineNumber: number) => {
const regex = new RegExp(/{sas(\d{2,4}|enc)}[^;"'\s]*/, 'gi')
const matches = value.match(regex)
if (!matches || !matches.length) return []
return matches.map((match) => ({
message,
lineNumber,
startColumnNumber: value.indexOf(match) + 1,
endColumnNumber: value.indexOf(match) + match.length + 1,
severity: Severity.Error
}))
}
/**
* Lint rule that checks for the presence of encoded password(s) in a given line of text.
*/
export const noEncodedPasswords: LineLintRule = {
type: LintRuleType.Line,
name,
description,
message,
test
}

View File

@@ -0,0 +1,22 @@
import { Severity } from '../../types/Severity'
import { noTabIndentation } from './noTabIndentation'
describe('noTabs', () => {
it('should return an empty array when the line is not indented with a tab', () => {
const line = "%put 'hello';"
expect(noTabIndentation.test(line, 1)).toEqual([])
})
it('should return an array with a single diagnostic when the line is indented with a tab', () => {
const line = "\t%put 'hello';"
expect(noTabIndentation.test(line, 1)).toEqual([
{
message: 'Line is indented with a tab',
lineNumber: 1,
startColumnNumber: 1,
endColumnNumber: 1,
severity: Severity.Warning
}
])
})
})

View File

@@ -0,0 +1,30 @@
import { LineLintRule } from '../../types/LintRule'
import { LintRuleType } from '../../types/LintRuleType'
import { Severity } from '../../types/Severity'
const name = 'noTabs'
const description = 'Disallow indenting with tabs.'
const message = 'Line is indented with a tab'
const test = (value: string, lineNumber: number) => {
if (!value.startsWith('\t')) return []
return [
{
message,
lineNumber,
startColumnNumber: 1,
endColumnNumber: 1,
severity: Severity.Warning
}
]
}
/**
* Lint rule that checks if a given line of text is indented with a tab.
*/
export const noTabIndentation: LineLintRule = {
type: LintRuleType.Line,
name,
description,
message,
test
}

View File

@@ -0,0 +1,22 @@
import { Severity } from '../../types/Severity'
import { noTrailingSpaces } from './noTrailingSpaces'
describe('noTrailingSpaces', () => {
it('should return an empty array when the line has no trailing spaces', () => {
const line = "%put 'hello';"
expect(noTrailingSpaces.test(line, 1)).toEqual([])
})
it('should return an array with a single diagnostic when the line has trailing spaces', () => {
const line = "%put 'hello'; "
expect(noTrailingSpaces.test(line, 1)).toEqual([
{
message: 'Line contains trailing spaces',
lineNumber: 1,
startColumnNumber: 14,
endColumnNumber: 15,
severity: Severity.Warning
}
])
})
})

View File

@@ -0,0 +1,30 @@
import { LineLintRule } from '../../types/LintRule'
import { LintRuleType } from '../../types/LintRuleType'
import { Severity } from '../../types/Severity'
const name = 'noTrailingSpaces'
const description = 'Disallow trailing spaces on lines.'
const message = 'Line contains trailing spaces'
const test = (value: string, lineNumber: number) =>
value.trimEnd() === value
? []
: [
{
message,
lineNumber,
startColumnNumber: value.trimEnd().length + 1,
endColumnNumber: value.length,
severity: Severity.Warning
}
]
/**
* Lint rule that checks for the presence of trailing space(s) in a given line of text.
*/
export const noTrailingSpaces: LineLintRule = {
type: LintRuleType.Line,
name,
description,
message,
test
}