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:
74
src/rules/line/indentationMultiple.spec.ts
Normal file
74
src/rules/line/indentationMultiple.spec.ts
Normal 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([])
|
||||
})
|
||||
})
|
||||
41
src/rules/line/indentationMultiple.ts
Normal file
41
src/rules/line/indentationMultiple.ts
Normal 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
5
src/rules/line/index.ts
Normal 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'
|
||||
44
src/rules/line/maxLineLength.spec.ts
Normal file
44
src/rules/line/maxLineLength.spec.ts
Normal 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([])
|
||||
})
|
||||
})
|
||||
32
src/rules/line/maxLineLength.ts
Normal file
32
src/rules/line/maxLineLength.ts
Normal 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
|
||||
}
|
||||
55
src/rules/line/noEncodedPasswords.spec.ts
Normal file
55
src/rules/line/noEncodedPasswords.spec.ts
Normal 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
|
||||
}
|
||||
])
|
||||
})
|
||||
})
|
||||
30
src/rules/line/noEncodedPasswords.ts
Normal file
30
src/rules/line/noEncodedPasswords.ts
Normal 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
|
||||
}
|
||||
22
src/rules/line/noTabIndentation.spec.ts
Normal file
22
src/rules/line/noTabIndentation.spec.ts
Normal 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
|
||||
}
|
||||
])
|
||||
})
|
||||
})
|
||||
30
src/rules/line/noTabIndentation.ts
Normal file
30
src/rules/line/noTabIndentation.ts
Normal 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
|
||||
}
|
||||
22
src/rules/line/noTrailingSpaces.spec.ts
Normal file
22
src/rules/line/noTrailingSpaces.spec.ts
Normal 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
|
||||
}
|
||||
])
|
||||
})
|
||||
})
|
||||
30
src/rules/line/noTrailingSpaces.ts
Normal file
30
src/rules/line/noTrailingSpaces.ts
Normal 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
|
||||
}
|
||||
Reference in New Issue
Block a user