mirror of
https://github.com/sasjs/lint.git
synced 2025-12-10 17:34:36 +00:00
feat: add a new config maxHeaderLineLength
This commit is contained in:
@@ -13,6 +13,7 @@
|
||||
"indentationMultiple": 2,
|
||||
"lowerCaseFileNames": true,
|
||||
"maxLineLength": 80,
|
||||
"maxHeaderLineLength": 80,
|
||||
"noGremlins": true,
|
||||
"noNestedMacros": true,
|
||||
"noSpacesInFileNames": true,
|
||||
@@ -30,6 +31,7 @@
|
||||
"noSpacesInFileNames": true,
|
||||
"lowerCaseFileNames": true,
|
||||
"maxLineLength": 80,
|
||||
"maxHeaderLineLength": 80,
|
||||
"noGremlins": true,
|
||||
"allowedGremlins": ["0x0080", "0x3000"],
|
||||
"noTabs": true,
|
||||
@@ -127,6 +129,14 @@
|
||||
"default": 80,
|
||||
"examples": [60, 80, 120]
|
||||
},
|
||||
"maxHeaderLineLength": {
|
||||
"$id": "#/properties/maxHeaderLineLength",
|
||||
"type": "number",
|
||||
"title": "maxLineLength",
|
||||
"description": "Enforces a configurable maximum line length for header section. Shows a warning for lines exceeding this length.",
|
||||
"default": 80,
|
||||
"examples": [60, 80, 120]
|
||||
},
|
||||
"noNestedMacros": {
|
||||
"$id": "#/properties/noNestedMacros",
|
||||
"type": "boolean",
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
import { LintConfig, Diagnostic } from '../types'
|
||||
import { splitText } from '../utils'
|
||||
import { getHeaderLinesCount, splitText } from '../utils'
|
||||
|
||||
export const processText = (text: string, config: LintConfig) => {
|
||||
const lines = splitText(text, config)
|
||||
const headerLinesCount = getHeaderLinesCount(text, config)
|
||||
const diagnostics: Diagnostic[] = []
|
||||
diagnostics.push(...processContent(config, text))
|
||||
lines.forEach((line, index) => {
|
||||
diagnostics.push(...processLine(config, line, index + 1))
|
||||
index += 1
|
||||
diagnostics.push(
|
||||
...processLine(config, line, index, index <= headerLinesCount)
|
||||
)
|
||||
})
|
||||
|
||||
return diagnostics
|
||||
@@ -36,11 +40,12 @@ const processContent = (config: LintConfig, content: string): Diagnostic[] => {
|
||||
export const processLine = (
|
||||
config: LintConfig,
|
||||
line: string,
|
||||
lineNumber: number
|
||||
lineNumber: number,
|
||||
isHeaderLine: boolean
|
||||
): Diagnostic[] => {
|
||||
const diagnostics: Diagnostic[] = []
|
||||
config.lineLintRules.forEach((rule) => {
|
||||
diagnostics.push(...rule.test(line, lineNumber, config))
|
||||
diagnostics.push(...rule.test(line, lineNumber, config, isHeaderLine))
|
||||
})
|
||||
|
||||
return diagnostics
|
||||
|
||||
@@ -7,9 +7,19 @@ 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 test = (
|
||||
value: string,
|
||||
lineNumber: number,
|
||||
config?: LintConfig,
|
||||
isHeaderLine?: boolean
|
||||
) => {
|
||||
const severity = config?.severityLevel[name] || Severity.Warning
|
||||
const maxLineLength = config?.maxLineLength || 80
|
||||
let maxLineLength = config?.maxLineLength || 80
|
||||
|
||||
if (isHeaderLine && config) {
|
||||
maxLineLength = Math.max(config.maxLineLength, config.maxHeaderLineLength)
|
||||
}
|
||||
|
||||
if (value.length <= maxLineLength) return []
|
||||
return [
|
||||
{
|
||||
|
||||
@@ -31,6 +31,17 @@ describe('LintConfig', () => {
|
||||
).toBeUndefined()
|
||||
})
|
||||
|
||||
it('should create an instance with the maxLineLength flag off', () => {
|
||||
const config = new LintConfig({ maxLineLength: 0 })
|
||||
|
||||
expect(config).toBeTruthy()
|
||||
expect(config.lineLintRules.length).toBeGreaterThan(0)
|
||||
expect(config.fileLintRules.length).toBeGreaterThan(0)
|
||||
expect(
|
||||
config.lineLintRules.find((rule) => rule.name === 'maxLineLength')
|
||||
).toBeUndefined()
|
||||
})
|
||||
|
||||
it('should create an instance with the hasDoxygenHeader flag off', () => {
|
||||
const config = new LintConfig({ hasDoxygenHeader: false })
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ export class LintConfig {
|
||||
readonly fileLintRules: FileLintRule[] = []
|
||||
readonly pathLintRules: PathLintRule[] = []
|
||||
readonly maxLineLength: number = 80
|
||||
readonly maxHeaderLineLength: number = 80
|
||||
readonly indentationMultiple: number = 2
|
||||
readonly lineEndings: LineEndings = LineEndings.LF
|
||||
readonly defaultHeader: string = getDefaultHeader()
|
||||
@@ -67,9 +68,16 @@ export class LintConfig {
|
||||
this.lineLintRules.pop()
|
||||
}
|
||||
|
||||
this.lineLintRules.push(maxLineLength)
|
||||
if (!isNaN(json?.maxLineLength)) {
|
||||
this.maxLineLength = json.maxLineLength
|
||||
if (json?.maxLineLength) {
|
||||
this.lineLintRules.push(maxLineLength)
|
||||
|
||||
if (!isNaN(json?.maxLineLength)) {
|
||||
this.maxLineLength = json.maxLineLength
|
||||
}
|
||||
|
||||
if (!isNaN(json?.maxHeaderLineLength)) {
|
||||
this.maxHeaderLineLength = json.maxHeaderLineLength
|
||||
}
|
||||
}
|
||||
|
||||
this.fileLintRules.push(lineEndings)
|
||||
|
||||
@@ -18,7 +18,12 @@ export interface LintRule {
|
||||
*/
|
||||
export interface LineLintRule extends LintRule {
|
||||
type: LintRuleType.Line
|
||||
test: (value: string, lineNumber: number, config?: LintConfig) => Diagnostic[]
|
||||
test: (
|
||||
value: string,
|
||||
lineNumber: number,
|
||||
config?: LintConfig,
|
||||
isHeaderLine?: boolean
|
||||
) => Diagnostic[]
|
||||
fix?: (value: string, config?: LintConfig) => string
|
||||
}
|
||||
|
||||
|
||||
21
src/utils/getHeaderLinesCount.spec.ts
Normal file
21
src/utils/getHeaderLinesCount.spec.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { LintConfig } from '../types'
|
||||
import { getHeaderLinesCount } from './getHeaderLinesCount'
|
||||
import { DefaultLintConfiguration } from './getLintConfig'
|
||||
|
||||
const sasCodeWithHeader = `/**
|
||||
@file
|
||||
@brief <Your brief here>
|
||||
<h4> SAS Macros </h4>
|
||||
**/
|
||||
%put hello world;
|
||||
`
|
||||
|
||||
const sasCodeWithoutHeader = `%put hello world;`
|
||||
|
||||
describe('getHeaderLinesCount', () => {
|
||||
it('should return the number of line header spans upon', () => {
|
||||
const config = new LintConfig(DefaultLintConfiguration)
|
||||
expect(getHeaderLinesCount(sasCodeWithHeader, config)).toEqual(5)
|
||||
expect(getHeaderLinesCount(sasCodeWithoutHeader, config)).toEqual(0)
|
||||
})
|
||||
})
|
||||
25
src/utils/getHeaderLinesCount.ts
Normal file
25
src/utils/getHeaderLinesCount.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { LintConfig } from '../types'
|
||||
import { splitText } from './splitText'
|
||||
|
||||
/**
|
||||
* This funtion returns the number of lines header spans upon.
|
||||
*/
|
||||
export const getHeaderLinesCount = (text: string, config: LintConfig) => {
|
||||
text = text.replace('/*', '/**')
|
||||
text = text.replace('*/', '**/')
|
||||
|
||||
let count = 0
|
||||
|
||||
if (text.trimStart().startsWith('/**')) {
|
||||
const lines = splitText(text, config)
|
||||
|
||||
for (const line of lines) {
|
||||
count++
|
||||
if (line.match(/\*\*\//)) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count
|
||||
}
|
||||
@@ -16,6 +16,7 @@ export const DefaultLintConfiguration = {
|
||||
noSpacesInFileNames: true,
|
||||
lowerCaseFileNames: true,
|
||||
maxLineLength: 80,
|
||||
maxHeaderLineLength: 80,
|
||||
noTabIndentation: true,
|
||||
indentationMultiple: 2,
|
||||
hasMacroNameInMend: true,
|
||||
|
||||
@@ -6,3 +6,4 @@ export * from './isIgnored'
|
||||
export * from './listSasFiles'
|
||||
export * from './splitText'
|
||||
export * from './getIndicesOf'
|
||||
export * from './getHeaderLinesCount'
|
||||
|
||||
Reference in New Issue
Block a user