mirror of
https://github.com/sasjs/lint.git
synced 2025-12-10 17:34:36 +00:00
191 lines
5.7 KiB
TypeScript
191 lines
5.7 KiB
TypeScript
import {
|
|
hasDoxygenHeader,
|
|
hasMacroNameInMend,
|
|
noNestedMacros,
|
|
hasMacroParentheses,
|
|
lineEndings,
|
|
strictMacroDefinition,
|
|
hasRequiredMacroOptions
|
|
} from '../rules/file'
|
|
import {
|
|
indentationMultiple,
|
|
maxLineLength,
|
|
noEncodedPasswords,
|
|
noTabs,
|
|
noTrailingSpaces,
|
|
noGremlins
|
|
} from '../rules/line'
|
|
import { lowerCaseFileNames, noSpacesInFileNames } from '../rules/path'
|
|
import { LineEndings } from './LineEndings'
|
|
import { FileLintRule, LineLintRule, PathLintRule } from './LintRule'
|
|
import { getDefaultHeader } from '../utils'
|
|
import { Severity } from './Severity'
|
|
|
|
/**
|
|
* LintConfig is the logical representation of the .sasjslint file.
|
|
* It exposes two sets of rules - one to be run against each line in a file,
|
|
* and one to be run once per file.
|
|
*
|
|
* More types of rules, when available, will be added here.
|
|
*/
|
|
export class LintConfig {
|
|
readonly ignoreList: string[] = []
|
|
readonly allowedGremlins: string[] = []
|
|
readonly lineLintRules: LineLintRule[] = []
|
|
readonly fileLintRules: FileLintRule[] = []
|
|
readonly pathLintRules: PathLintRule[] = []
|
|
readonly maxLineLength: number = 80
|
|
readonly maxHeaderLineLength: number = 80
|
|
readonly maxDataLineLength: number = 80
|
|
readonly indentationMultiple: number = 2
|
|
readonly lineEndings: LineEndings = LineEndings.LF
|
|
readonly defaultHeader: string = getDefaultHeader()
|
|
readonly severityLevel: { [key: string]: Severity } = {}
|
|
readonly requiredMacroOptions: string[] = []
|
|
|
|
constructor(json?: any) {
|
|
if (json?.ignoreList) {
|
|
if (Array.isArray(json.ignoreList)) {
|
|
json.ignoreList.forEach((item: any) => {
|
|
if (typeof item === 'string') this.ignoreList.push(item)
|
|
else
|
|
throw new Error(
|
|
`Property "ignoreList" has invalid type of values. It can contain only strings.`
|
|
)
|
|
})
|
|
} else {
|
|
throw new Error(`Property "ignoreList" can only be an array of strings`)
|
|
}
|
|
}
|
|
|
|
if (json?.noTrailingSpaces !== false) {
|
|
this.lineLintRules.push(noTrailingSpaces)
|
|
}
|
|
|
|
if (json?.noEncodedPasswords !== false) {
|
|
this.lineLintRules.push(noEncodedPasswords)
|
|
}
|
|
|
|
this.lineLintRules.push(noTabs)
|
|
if (json?.noTabs === false || json?.noTabIndentation === false) {
|
|
this.lineLintRules.pop()
|
|
}
|
|
|
|
if (json?.maxLineLength > 0) {
|
|
this.lineLintRules.push(maxLineLength)
|
|
this.maxLineLength = json.maxLineLength
|
|
|
|
if (!isNaN(json?.maxHeaderLineLength)) {
|
|
this.maxHeaderLineLength = json.maxHeaderLineLength
|
|
}
|
|
|
|
if (!isNaN(json?.maxDataLineLength)) {
|
|
this.maxDataLineLength = json.maxDataLineLength
|
|
}
|
|
}
|
|
|
|
if (json?.lineEndings && json.lineEndings !== LineEndings.OFF) {
|
|
if (
|
|
json.lineEndings !== LineEndings.LF &&
|
|
json.lineEndings !== LineEndings.CRLF
|
|
) {
|
|
throw new Error(
|
|
`Invalid value for lineEndings: can be ${LineEndings.LF} or ${LineEndings.CRLF}`
|
|
)
|
|
}
|
|
this.fileLintRules.push(lineEndings)
|
|
this.lineEndings = json.lineEndings
|
|
}
|
|
|
|
this.lineLintRules.push(indentationMultiple)
|
|
if (!isNaN(json?.indentationMultiple)) {
|
|
this.indentationMultiple = json.indentationMultiple as number
|
|
}
|
|
|
|
if (json?.hasDoxygenHeader !== false) {
|
|
this.fileLintRules.push(hasDoxygenHeader)
|
|
}
|
|
|
|
if (json?.defaultHeader) {
|
|
this.defaultHeader = json.defaultHeader
|
|
}
|
|
|
|
if (json?.noSpacesInFileNames !== false) {
|
|
this.pathLintRules.push(noSpacesInFileNames)
|
|
}
|
|
|
|
if (json?.lowerCaseFileNames !== false) {
|
|
this.pathLintRules.push(lowerCaseFileNames)
|
|
}
|
|
|
|
if (json?.hasMacroNameInMend) {
|
|
this.fileLintRules.push(hasMacroNameInMend)
|
|
}
|
|
|
|
if (json?.noNestedMacros !== false) {
|
|
this.fileLintRules.push(noNestedMacros)
|
|
}
|
|
|
|
if (json?.hasMacroParentheses !== false) {
|
|
this.fileLintRules.push(hasMacroParentheses)
|
|
}
|
|
|
|
if (json?.strictMacroDefinition !== false) {
|
|
this.fileLintRules.push(strictMacroDefinition)
|
|
}
|
|
|
|
if (json?.hasRequiredMacroOptions) {
|
|
this.fileLintRules.push(hasRequiredMacroOptions)
|
|
|
|
if (json?.requiredMacroOptions) {
|
|
if (
|
|
Array.isArray(json.requiredMacroOptions) &&
|
|
json.requiredMacroOptions.length > 0
|
|
) {
|
|
json.requiredMacroOptions.forEach((item: any) => {
|
|
if (typeof item === 'string') {
|
|
this.requiredMacroOptions.push(item)
|
|
} else {
|
|
throw new Error(
|
|
`Property "requiredMacroOptions" has invalid type of values. It can only contain strings.`
|
|
)
|
|
}
|
|
})
|
|
} else {
|
|
throw new Error(
|
|
`Property "requiredMacroOptions" can only be an array of strings.`
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
if (json?.noGremlins !== false) {
|
|
this.lineLintRules.push(noGremlins)
|
|
|
|
if (json?.allowedGremlins) {
|
|
if (Array.isArray(json.allowedGremlins)) {
|
|
json.allowedGremlins.forEach((item: any) => {
|
|
if (typeof item === 'string' && /^0x[0-9a-f]{4}$/i.test(item))
|
|
this.allowedGremlins.push(item)
|
|
else
|
|
throw new Error(
|
|
`Property "allowedGremlins" has invalid type of values. It can contain only strings of form hexcode like '["0x0080", "0x3000"]'`
|
|
)
|
|
})
|
|
} else {
|
|
throw new Error(
|
|
`Property "allowedGremlins" can only be an array of strings of form hexcode like '["0x0080", "0x3000"]'`
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
if (json?.severityLevel) {
|
|
for (const [rule, severity] of Object.entries(json.severityLevel)) {
|
|
if (severity === 'warn') this.severityLevel[rule] = Severity.Warning
|
|
if (severity === 'error') this.severityLevel[rule] = Severity.Error
|
|
}
|
|
}
|
|
}
|
|
}
|