From 0cff87fe12787f6f38e4c6696a98460dd11523bf Mon Sep 17 00:00:00 2001 From: Sabir Hassan Date: Wed, 16 Nov 2022 22:40:17 +0500 Subject: [PATCH 1/3] feat: add new property severityLevel --- sasjslint-schema.json | 109 ++++++++++++++++++++++++ src/lint/shared.ts | 4 +- src/rules/file/hasDoxygenHeader.ts | 9 +- src/rules/file/hasMacroNameInMend.ts | 11 ++- src/rules/file/hasMacroParentheses.ts | 7 +- src/rules/file/lineEndings.ts | 7 +- src/rules/file/noNestedMacros.ts | 5 +- src/rules/file/strictMacroDefinition.ts | 16 ++-- src/rules/line/indentationMultiple.ts | 4 +- src/rules/line/maxLineLength.ts | 4 +- src/rules/line/noEncodedPasswords.ts | 7 +- src/rules/line/noTabIndentation.ts | 5 +- src/rules/line/noTrailingSpaces.ts | 12 ++- src/rules/path/lowerCaseFileNames.ts | 9 +- src/rules/path/noSpacesInFileNames.ts | 8 +- src/types/LintConfig.spec.ts | 18 ++++ src/types/LintConfig.ts | 9 ++ src/types/LintRule.ts | 2 +- 18 files changed, 213 insertions(+), 33 deletions(-) diff --git a/sasjslint-schema.json b/sasjslint-schema.json index 7e16ef9..7ed7f80 100644 --- a/sasjslint-schema.json +++ b/sasjslint-schema.json @@ -159,6 +159,115 @@ "description": "An array of paths or path patterns to ignore when linting. Any files or matching patterns in the .gitignore file will also be ignored.", "default": ["sasjsbuild/", "sasjsresults/"], "examples": ["sasjs/tests", "tmp/scratch.sas"] + }, + "severityLevel": { + "$id": "#/properties/severityLevel", + "type": "object", + "title": "severityLevel", + "description": "An object which specifies the severity level of each rule.", + "default": {}, + "examples": [{ + "hasDoxygenHeader": "warn", + "maxLineLength": "warn", + "noTrailingSpaces": "error" + }, { + "hasDoxygenHeader": "warn", + "maxLineLength": "error", + "noTrailingSpaces": "error" + }], + "properties": { + "noEncodedPasswords": { + "$id": "#/properties/severityLevel/noEncodedPasswords", + "title": "noEncodedPasswords", + "type": "string", + "enum": ["error", "warn"], + "default": "error" + }, + "hasDoxygenHeader": { + "$id": "#/properties/severityLevel/hasDoxygenHeader", + "title": "hasDoxygenHeader", + "type": "string", + "enum": ["error", "warn"], + "default": "warn" }, + "hasMacroNameInMend": { + "$id": "#/properties/severityLevel/hasMacroNameInMend", + "title": "hasMacroNameInMend", + "type": "string", + "enum": ["error", "warn"], + "default": "warn" + }, + "hasMacroParentheses": { + "$id": "#/properties/severityLevel/hasMacroParentheses", + "title": "hasMacroParentheses", + "type": "string", + "enum": ["error", "warn"], + "default": "warn" + }, + "indentationMultiple": { + "$id": "#/properties/severityLevel/indentationMultiple", + "title": "indentationMultiple", + "type": "string", + "enum": ["error", "warn"], + "default": "warn" + }, + "lowerCaseFileNames": { + "$id": "#/properties/severityLevel/lowerCaseFileNames", + "title": "lowerCaseFileNames", + "type": "string", + "enum": ["error", "warn"], + "default": "warn" + }, + "maxLineLength": { + "$id": "#/properties/severityLevel/maxLineLength", + "title": "maxLineLength", + "type": "string", + "enum": ["error", "warn"], + "default": "warn" + }, + "noNestedMacros": { + "$id": "#/properties/severityLevel/noNestedMacros", + "title": "noNestedMacros", + "type": "string", + "enum": ["error", "warn"], + "default": "warn" + }, + "noSpacesInFileNames": { + "$id": "#/properties/severityLevel/noSpacesInFileNames", + "title": "noSpacesInFileNames", + "type": "string", + "enum": ["error", "warn"], + "default": "warn" + }, + "noTabIndentation": { + "$id": "#/properties/severityLevel/noTabIndentation", + "title": "noTabIndentation", + "type": "string", + "enum": ["error", "warn"], + "default": "warn" + }, + "noTrailingSpaces": { + "$id": "#/properties/severityLevel/noTrailingSpaces", + "title": "noTrailingSpaces", + "type": "string", + "enum": ["error", "warn"], + "default": "warn" + }, + "lineEndings": { + "$id": "#/properties/severityLevel/lineEndings", + "title": "lineEndings", + "type": "string", + "enum": ["error", "warn"], + "default": "warn" + }, + "strictMacroDefinition": { + "$id": "#/properties/severityLevel/strictMacroDefinition", + "title": "strictMacroDefinition", + "type": "string", + "enum": ["error", "warn"], + "default": "warn" + } + } + } } } diff --git a/src/lint/shared.ts b/src/lint/shared.ts index 50ca081..556ba54 100644 --- a/src/lint/shared.ts +++ b/src/lint/shared.ts @@ -18,7 +18,7 @@ export const processFile = ( ): Diagnostic[] => { const diagnostics: Diagnostic[] = [] config.pathLintRules.forEach((rule) => { - diagnostics.push(...rule.test(filePath)) + diagnostics.push(...rule.test(filePath, config)) }) return diagnostics @@ -27,7 +27,7 @@ export const processFile = ( const processContent = (config: LintConfig, content: string): Diagnostic[] => { const diagnostics: Diagnostic[] = [] config.fileLintRules.forEach((rule) => { - diagnostics.push(...rule.test(content)) + diagnostics.push(...rule.test(content, config)) }) return diagnostics diff --git a/src/rules/file/hasDoxygenHeader.ts b/src/rules/file/hasDoxygenHeader.ts index 3cc347d..8960b20 100644 --- a/src/rules/file/hasDoxygenHeader.ts +++ b/src/rules/file/hasDoxygenHeader.ts @@ -11,8 +11,11 @@ const description = const message = 'File missing Doxygen header' const messageForSingleAsterisk = 'File not following Doxygen header style, use double asterisks' + const test = (value: string, config?: LintConfig) => { const lineEnding = config?.lineEndings === LineEndings.CRLF ? '\r\n' : '\n' + const severity = config?.severityLevel[name] || Severity.Warning + try { const hasFileHeader = value.trimStart().startsWith('/**') if (hasFileHeader) return [] @@ -27,7 +30,7 @@ const test = (value: string, config?: LintConfig) => { .length + 1, startColumnNumber: 1, endColumnNumber: 1, - severity: Severity.Warning + severity } ] @@ -37,7 +40,7 @@ const test = (value: string, config?: LintConfig) => { lineNumber: 1, startColumnNumber: 1, endColumnNumber: 1, - severity: Severity.Warning + severity } ] } catch (e) { @@ -47,7 +50,7 @@ const test = (value: string, config?: LintConfig) => { lineNumber: 1, startColumnNumber: 1, endColumnNumber: 1, - severity: Severity.Warning + severity } ] } diff --git a/src/rules/file/hasMacroNameInMend.ts b/src/rules/file/hasMacroNameInMend.ts index 0a37100..72f8d76 100644 --- a/src/rules/file/hasMacroNameInMend.ts +++ b/src/rules/file/hasMacroNameInMend.ts @@ -11,11 +11,14 @@ const name = 'hasMacroNameInMend' const description = 'Enforces the presence of the macro name in each %mend statement.' const message = '%mend statement has missing or incorrect macro name' + const test = (value: string, config?: LintConfig) => { const lineEnding = config?.lineEndings === LineEndings.CRLF ? '\r\n' : '\n' const lines: string[] = value ? value.split(lineEnding) : [] const macros = parseMacros(value, config) + const severity = config?.severityLevel[name] || Severity.Warning const diagnostics: Diagnostic[] = [] + macros.forEach((macro) => { if (macro.startLineNumbers.length === 0 && macro.endLineNumber !== null) { const endLine = lines[macro.endLineNumber - 1] @@ -25,7 +28,7 @@ const test = (value: string, config?: LintConfig) => { startColumnNumber: getColumnNumber(endLine, '%mend'), endColumnNumber: getColumnNumber(endLine, '%mend') + macro.termination.length, - severity: Severity.Warning + severity }) } else if ( macro.endLineNumber === null && @@ -36,7 +39,7 @@ const test = (value: string, config?: LintConfig) => { lineNumber: macro.startLineNumbers![0], startColumnNumber: 1, endColumnNumber: 1, - severity: Severity.Warning + severity }) } else if (macro.mismatchedMendMacroName) { const endLine = lines[(macro.endLineNumber as number) - 1] @@ -53,7 +56,7 @@ const test = (value: string, config?: LintConfig) => { getColumnNumber(endLine, macro.mismatchedMendMacroName) + macro.mismatchedMendMacroName.length - 1, - severity: Severity.Warning + severity }) } else if (!macro.hasMacroNameInMend) { const endLine = lines[(macro.endLineNumber as number) - 1] @@ -62,7 +65,7 @@ const test = (value: string, config?: LintConfig) => { lineNumber: macro.endLineNumber as number, startColumnNumber: getColumnNumber(endLine, '%mend'), endColumnNumber: getColumnNumber(endLine, '%mend') + 6, - severity: Severity.Warning + severity }) } }) diff --git a/src/rules/file/hasMacroParentheses.ts b/src/rules/file/hasMacroParentheses.ts index 435d98d..24c0bef 100644 --- a/src/rules/file/hasMacroParentheses.ts +++ b/src/rules/file/hasMacroParentheses.ts @@ -9,9 +9,12 @@ import { LintConfig } from '../../types' const name = 'hasMacroParentheses' const description = 'Enforces the presence of parentheses in macro definitions.' const message = 'Macro definition missing parentheses' + const test = (value: string, config?: LintConfig) => { const diagnostics: Diagnostic[] = [] const macros = parseMacros(value, config) + const severity = config?.severityLevel[name] || Severity.Warning + macros.forEach((macro) => { if (!macro.name) { diagnostics.push({ @@ -24,7 +27,7 @@ const test = (value: string, config?: LintConfig) => { endColumnNumber: getColumnNumber(macro.declarationLines![0], '%macro') + macro.declaration.length, - severity: Severity.Warning + severity }) } else if (!macro.declarationLines.find((dl) => dl.includes('('))) { const macroNameLineIndex = macro.declarationLines.findIndex((dl) => @@ -44,7 +47,7 @@ const test = (value: string, config?: LintConfig) => { ) + macro.name.length - 1, - severity: Severity.Warning + severity }) } }) diff --git a/src/rules/file/lineEndings.ts b/src/rules/file/lineEndings.ts index 77cf17a..f44513f 100644 --- a/src/rules/file/lineEndings.ts +++ b/src/rules/file/lineEndings.ts @@ -7,6 +7,7 @@ import { Severity } from '../../types/Severity' const name = 'lineEndings' const description = 'Ensures line endings conform to the configured type.' const message = 'Incorrect line ending - {actual} instead of {expected}' + const test = (value: string, config?: LintConfig) => { const lineEndingConfig = config?.lineEndings || LineEndings.LF const expectedLineEnding = @@ -18,8 +19,10 @@ const test = (value: string, config?: LintConfig) => { .replace(/\n/g, '{lf}') .split(new RegExp(`(?<=${expectedLineEnding})`)) const diagnostics: Diagnostic[] = [] + const severity = config?.severityLevel[name] || Severity.Warning let indexOffset = 0 + lines.forEach((line, index) => { if (line.endsWith(incorrectLineEnding)) { diagnostics.push({ @@ -29,7 +32,7 @@ const test = (value: string, config?: LintConfig) => { lineNumber: index + 1 + indexOffset, startColumnNumber: line.indexOf(incorrectLineEnding), endColumnNumber: line.indexOf(incorrectLineEnding) + 1, - severity: Severity.Warning + severity }) } else { const splitLine = line.split(new RegExp(`(?<=${incorrectLineEnding})`)) @@ -51,7 +54,7 @@ const test = (value: string, config?: LintConfig) => { lineNumber: index + i + 1, startColumnNumber: l.indexOf(incorrectLineEnding), endColumnNumber: l.indexOf(incorrectLineEnding) + 1, - severity: Severity.Warning + severity }) } }) diff --git a/src/rules/file/noNestedMacros.ts b/src/rules/file/noNestedMacros.ts index b255545..c3ab9b8 100644 --- a/src/rules/file/noNestedMacros.ts +++ b/src/rules/file/noNestedMacros.ts @@ -10,11 +10,14 @@ import { LineEndings } from '../../types/LineEndings' const name = 'noNestedMacros' const description = 'Enfoces the absence of nested macro definitions.' const message = `Macro definition for '{macro}' present in macro '{parent}'` + const test = (value: string, config?: LintConfig) => { const lineEnding = config?.lineEndings === LineEndings.CRLF ? '\r\n' : '\n' const lines: string[] = value ? value.split(lineEnding) : [] const diagnostics: Diagnostic[] = [] const macros = parseMacros(value, config) + const severity = config?.severityLevel[name] || Severity.Warning + macros .filter((m) => !!m.parentMacro) .forEach((macro) => { @@ -34,7 +37,7 @@ const test = (value: string, config?: LintConfig) => { ) + lines[(macro.startLineNumbers![0] as number) - 1].trim().length - 1, - severity: Severity.Warning + severity }) }) return diagnostics diff --git a/src/rules/file/strictMacroDefinition.ts b/src/rules/file/strictMacroDefinition.ts index fed6b85..5076ec6 100644 --- a/src/rules/file/strictMacroDefinition.ts +++ b/src/rules/file/strictMacroDefinition.ts @@ -25,9 +25,11 @@ const validOptions = [ const processParams = ( content: string, macro: Macro, - diagnostics: Diagnostic[] + diagnostics: Diagnostic[], + config?: LintConfig ): string => { const declaration = macro.declaration + const severity = config?.severityLevel[name] || Severity.Warning const regExpParams = new RegExp(/(?<=\().*(?=\))/) const regExpParamsResult = regExpParams.exec(declaration) @@ -88,7 +90,7 @@ const processParams = ( lineNumber: paramLineNumber, startColumnNumber: paramStartIndex + 1, endColumnNumber: paramEndIndex, - severity: Severity.Warning + severity }) } }) @@ -101,9 +103,11 @@ const processParams = ( const processOptions = ( _declaration: string, macro: Macro, - diagnostics: Diagnostic[] + diagnostics: Diagnostic[], + config?: LintConfig ): void => { let optionsPresent = _declaration.split('/')?.[1]?.trim() + const severity = config?.severityLevel[name] || Severity.Warning if (optionsPresent) { const regex = new RegExp(/="(.*?)"/, 'g') @@ -136,7 +140,7 @@ const processOptions = ( startColumnNumber: declarationLine.indexOf(trimmedOption) + 1, endColumnNumber: declarationLine.indexOf(trimmedOption) + trimmedOption.length, - severity: Severity.Warning + severity }) } }) @@ -149,9 +153,9 @@ const test = (value: string, config?: LintConfig) => { const macros = parseMacros(value, config) macros.forEach((macro) => { - const _declaration = processParams(value, macro, diagnostics) + const _declaration = processParams(value, macro, diagnostics, config) - processOptions(_declaration, macro, diagnostics) + processOptions(_declaration, macro, diagnostics, config) }) return diagnostics diff --git a/src/rules/line/indentationMultiple.ts b/src/rules/line/indentationMultiple.ts index a5345c4..5a2d4a8 100644 --- a/src/rules/line/indentationMultiple.ts +++ b/src/rules/line/indentationMultiple.ts @@ -6,9 +6,11 @@ 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 severity = config?.severityLevel[name] || Severity.Warning const indentationMultiple = isNaN(config?.indentationMultiple as number) ? 2 : config!.indentationMultiple @@ -24,7 +26,7 @@ const test = (value: string, lineNumber: number, config?: LintConfig) => { lineNumber, startColumnNumber: 1, endColumnNumber: 1, - severity: Severity.Warning + severity } ] } diff --git a/src/rules/line/maxLineLength.ts b/src/rules/line/maxLineLength.ts index 8cc6e8c..a3d9d7d 100644 --- a/src/rules/line/maxLineLength.ts +++ b/src/rules/line/maxLineLength.ts @@ -6,7 +6,9 @@ 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 severity = config?.severityLevel[name] || Severity.Warning const maxLineLength = config?.maxLineLength || 80 if (value.length <= maxLineLength) return [] return [ @@ -15,7 +17,7 @@ const test = (value: string, lineNumber: number, config?: LintConfig) => { lineNumber, startColumnNumber: 1, endColumnNumber: 1, - severity: Severity.Warning + severity } ] } diff --git a/src/rules/line/noEncodedPasswords.ts b/src/rules/line/noEncodedPasswords.ts index 35914aa..cc78822 100644 --- a/src/rules/line/noEncodedPasswords.ts +++ b/src/rules/line/noEncodedPasswords.ts @@ -1,3 +1,4 @@ +import { LintConfig } from '../../types' import { LineLintRule } from '../../types/LintRule' import { LintRuleType } from '../../types/LintRuleType' import { Severity } from '../../types/Severity' @@ -5,7 +6,9 @@ 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 test = (value: string, lineNumber: number, config?: LintConfig) => { + const severity = config?.severityLevel[name] || Severity.Error const regex = new RegExp(/{sas(\d{2,4}|enc)}[^;"'\s]*/, 'gi') const matches = value.match(regex) if (!matches || !matches.length) return [] @@ -14,7 +17,7 @@ const test = (value: string, lineNumber: number) => { lineNumber, startColumnNumber: value.indexOf(match) + 1, endColumnNumber: value.indexOf(match) + match.length + 1, - severity: Severity.Error + severity })) } diff --git a/src/rules/line/noTabIndentation.ts b/src/rules/line/noTabIndentation.ts index 1158bf7..578b074 100644 --- a/src/rules/line/noTabIndentation.ts +++ b/src/rules/line/noTabIndentation.ts @@ -1,3 +1,4 @@ +import { LintConfig } from '../../types' import { LineLintRule } from '../../types/LintRule' import { LintRuleType } from '../../types/LintRuleType' import { Severity } from '../../types/Severity' @@ -5,7 +6,9 @@ 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) => { + +const test = (value: string, lineNumber: number, config?: LintConfig) => { + const severity = config?.severityLevel[name] || Severity.Warning if (!value.startsWith('\t')) return [] return [ { diff --git a/src/rules/line/noTrailingSpaces.ts b/src/rules/line/noTrailingSpaces.ts index 2200a87..18fa7b1 100644 --- a/src/rules/line/noTrailingSpaces.ts +++ b/src/rules/line/noTrailingSpaces.ts @@ -1,3 +1,4 @@ +import { LintConfig } from '../../types' import { LineLintRule } from '../../types/LintRule' import { LintRuleType } from '../../types/LintRuleType' import { Severity } from '../../types/Severity' @@ -5,8 +6,11 @@ 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 + +const test = (value: string, lineNumber: number, config?: LintConfig) => { + const severity = config?.severityLevel[name] || Severity.Warning + + return value.trimEnd() === value ? [] : [ { @@ -14,9 +18,11 @@ const test = (value: string, lineNumber: number) => lineNumber, startColumnNumber: value.trimEnd().length + 1, endColumnNumber: value.length, - severity: Severity.Warning + severity } ] +} + const fix = (value: string) => value.trimEnd() /** diff --git a/src/rules/path/lowerCaseFileNames.ts b/src/rules/path/lowerCaseFileNames.ts index 0d6e53c..6e62860 100644 --- a/src/rules/path/lowerCaseFileNames.ts +++ b/src/rules/path/lowerCaseFileNames.ts @@ -2,20 +2,25 @@ import { PathLintRule } from '../../types/LintRule' import { LintRuleType } from '../../types/LintRuleType' import { Severity } from '../../types/Severity' import path from 'path' +import { LintConfig } from '../../types' const name = 'lowerCaseFileNames' const description = 'Enforce the use of lower case file names.' const message = 'File name contains uppercase characters' -const test = (value: string) => { + +const test = (value: string, config?: LintConfig) => { + const severity = config?.severityLevel[name] || Severity.Warning const fileName = path.basename(value) + if (fileName.toLocaleLowerCase() === fileName) return [] + return [ { message, lineNumber: 1, startColumnNumber: 1, endColumnNumber: 1, - severity: Severity.Warning + severity } ] } diff --git a/src/rules/path/noSpacesInFileNames.ts b/src/rules/path/noSpacesInFileNames.ts index 403f536..1ec0b9c 100644 --- a/src/rules/path/noSpacesInFileNames.ts +++ b/src/rules/path/noSpacesInFileNames.ts @@ -2,12 +2,16 @@ import { PathLintRule } from '../../types/LintRule' import { LintRuleType } from '../../types/LintRuleType' import { Severity } from '../../types/Severity' import path from 'path' +import { LintConfig } from '../../types' const name = 'noSpacesInFileNames' const description = 'Enforce the absence of spaces within file names.' const message = 'File name contains spaces' -const test = (value: string) => { + +const test = (value: string, config?: LintConfig) => { + const severity = config?.severityLevel[name] || Severity.Warning const fileName = path.basename(value) + if (fileName.includes(' ')) { return [ { @@ -15,7 +19,7 @@ const test = (value: string) => { lineNumber: 1, startColumnNumber: 1, endColumnNumber: 1, - severity: Severity.Warning + severity } ] } diff --git a/src/types/LintConfig.spec.ts b/src/types/LintConfig.spec.ts index 67ac80f..48b6b09 100644 --- a/src/types/LintConfig.spec.ts +++ b/src/types/LintConfig.spec.ts @@ -1,6 +1,7 @@ import { LineEndings } from './LineEndings' import { LintConfig } from './LintConfig' import { LintRuleType } from './LintRuleType' +import { Severity } from './Severity' describe('LintConfig', () => { it('should create an empty instance', () => { @@ -123,6 +124,23 @@ describe('LintConfig', () => { expect(config.lineEndings).toEqual(LineEndings.CRLF) }) + it('should create an instance with the severityLevel config', () => { + const config = new LintConfig({ + severityLevel: { + hasDoxygenHeader: 'warn', + maxLineLength: 'error', + noTrailingSpaces: 'error' + } + }) + + expect(config).toBeTruthy() + expect(config.severityLevel).toEqual({ + hasDoxygenHeader: Severity.Warning, + maxLineLength: Severity.Error, + noTrailingSpaces: Severity.Error + }) + }) + it('should create an instance with the line endings set to LF by default', () => { const config = new LintConfig({}) diff --git a/src/types/LintConfig.ts b/src/types/LintConfig.ts index 93c1b45..1882693 100644 --- a/src/types/LintConfig.ts +++ b/src/types/LintConfig.ts @@ -17,6 +17,7 @@ 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. @@ -34,6 +35,7 @@ export class LintConfig { readonly indentationMultiple: number = 2 readonly lineEndings: LineEndings = LineEndings.LF readonly defaultHeader: string = getDefaultHeader() + readonly severityLevel: { [key: string]: Severity } = {} constructor(json?: any) { if (json?.ignoreList) { @@ -116,5 +118,12 @@ export class LintConfig { if (json?.strictMacroDefinition) { this.fileLintRules.push(strictMacroDefinition) } + + 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 + } + } } } diff --git a/src/types/LintRule.ts b/src/types/LintRule.ts index f32a58c..e2f7b90 100644 --- a/src/types/LintRule.ts +++ b/src/types/LintRule.ts @@ -36,5 +36,5 @@ export interface FileLintRule extends LintRule { */ export interface PathLintRule extends LintRule { type: LintRuleType.Path - test: (value: string) => Diagnostic[] + test: (value: string, config?: LintConfig) => Diagnostic[] } From 75b103003cdd1dc5f32dee436a2064a496e70828 Mon Sep 17 00:00:00 2001 From: Sabir Hassan Date: Wed, 16 Nov 2022 22:52:15 +0500 Subject: [PATCH 2/3] chore: quick fix --- src/rules/line/noTabIndentation.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rules/line/noTabIndentation.ts b/src/rules/line/noTabIndentation.ts index 578b074..cff6515 100644 --- a/src/rules/line/noTabIndentation.ts +++ b/src/rules/line/noTabIndentation.ts @@ -16,7 +16,7 @@ const test = (value: string, lineNumber: number, config?: LintConfig) => { lineNumber, startColumnNumber: 1, endColumnNumber: 1, - severity: Severity.Warning + severity } ] } From c6a70a1d1af66533ed5eb6594ab1972ed5c3ab15 Mon Sep 17 00:00:00 2001 From: Allan Bowe Date: Wed, 16 Nov 2022 22:12:43 +0000 Subject: [PATCH 3/3] chore: docs for severityLevel --- README.md | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index c73390f..99981b8 100644 --- a/README.md +++ b/README.md @@ -40,9 +40,19 @@ Configuration is via a `.sasjslint` file with the following structure (these are ### SAS Lint Settings +Each setting can have three states: + +* OFF - usually by setting the value to `false` or 0. In this case, the rule won't be executed. +* WARN - a warning is written to the log, but the return code will be 0 +* ERROR - an error is written to the log, and the return code is 1 + +For more details, and the default state, see the description of each rule below. It is also possible to change whether a rule returns ERROR or WARN using the `severityLevels` object. + #### defaultHeader -This sets the default program header - applies when a SAS program does NOT begin with `/**`. The default header is as follows: +This isn't actually a rule - but rather a formatting setting, which applies to SAS program that do NOT begin with `/**`. It can be triggered by running `sasjs lint fix` in the SASjs CLI, or by hitting "save" when using the SASjs VS Code extension (with "formatOnSave" in place) + +The default header is as follows: ```sas /** @@ -51,8 +61,7 @@ This sets the default program header - applies when a SAS program does NOT begin

SAS Macros

**/ ``` - -The default header is automatically applied when running `sasjs lint fix` in the SASjs CLI, or by hitting "save" when using the SASjs VS Code extension. If creating a new value, use `{lineEnding}` instead of `\n`, eg as follows: +If creating a new value, use `{lineEnding}` instead of `\n`, eg as follows: ```json { @@ -62,7 +71,7 @@ The default header is automatically applied when running `sasjs lint fix` in the #### noEncodedPasswords -This will highlight any rows that contain a `{sas00X}` type password, or `{sasenc}`. These passwords (especially 001 and 002) are NOT secure, and should NEVER be pushed to source control or saved to the filesystem without special permissions applied. +This rule will highlight any rows that contain a `{sas00X}` type password, or `{sasenc}`. These passwords (especially 001 and 002) are NOT secure, and should NEVER be pushed to source control or saved to the filesystem without special permissions applied. * Default: true * Severity: ERROR @@ -139,6 +148,26 @@ This will highlight lines with trailing spaces. Trailing spaces serve no useful * Default: true * severity: WARNING +### severityLevel + +This setting allows the default severity to be adjusted. This is helpful when running the lint in a pipeline or git hook. Simply list the rules you would like to adjust along with the desired setting ("warn" or "error"), eg as follows: + +```json +{ + "noTrailingSpaces": true, + "hasDoxygenHeader": true, + "maxLineLength": 100, + "severityLevel": { + "hasDoxygenHeader": "warn", + "maxLineLength": "error", + "noTrailingSpaces": "error" + } +} +``` + +* "warn" - show warning in the log (doesn’t affect exit code) +* "error" - show error in the log (exit code is 1 when triggered) + ### Upcoming Linting Rules: * `noTabs` -> does what it says on the tin