Skip to content

Commit

Permalink
feat: new rule added 'strictMacroDefinition'
Browse files Browse the repository at this point in the history
  • Loading branch information
saadjutt01 committed May 20, 2021
1 parent e5780cd commit dcfeb7a
Show file tree
Hide file tree
Showing 7 changed files with 190 additions and 4 deletions.
1 change: 1 addition & 0 deletions src/rules/line/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export { maxLineLength } from './maxLineLength'
export { noEncodedPasswords } from './noEncodedPasswords'
export { noTabIndentation } from './noTabIndentation'
export { noTrailingSpaces } from './noTrailingSpaces'
export { strictMacroDefinition } from './strictMacroDefinition'
88 changes: 88 additions & 0 deletions src/rules/line/strictMacroDefinition.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { LintConfig, Severity } from '../../types'
import { strictMacroDefinition } from './strictMacroDefinition'

describe('strictMacroDefinition', () => {
it('should return an empty array when the line has correct macro definition syntax', () => {
const line = '%macro somemacro;'
expect(strictMacroDefinition.test(line, 1)).toEqual([])

const line2 = '%macro somemacro();'
expect(strictMacroDefinition.test(line2, 1)).toEqual([])

const line3 = '%macro somemacro(var1);'
expect(strictMacroDefinition.test(line3, 1)).toEqual([])

const line4 = '%macro somemacro/minoperator;'
expect(strictMacroDefinition.test(line4, 1)).toEqual([])

const line5 = '%macro somemacro /minoperator;'
expect(strictMacroDefinition.test(line5, 1)).toEqual([])

const line6 = '%macro somemacro(var1, var2)/minoperator;'
expect(strictMacroDefinition.test(line6, 1)).toEqual([])

const line7 =
' /* Some Comment */ %macro somemacro(var1, var2) /minoperator ; /* Some Comment */'
expect(strictMacroDefinition.test(line7, 1)).toEqual([])
})

it('should return an array with a single diagnostic when Macro definition has space in param', () => {
const line = '%macro somemacro(va r1);'
expect(strictMacroDefinition.test(line, 1)).toEqual([
{
message: `Param 'va r1' cannot have space`,
lineNumber: 1,
startColumnNumber: 18,
endColumnNumber: 22,
severity: Severity.Warning
}
])
})

it('should return an array with a two diagnostics when Macro definition has space in param', () => {
const line = '%macro somemacro(var1, var 2, v ar3, var4);'
expect(strictMacroDefinition.test(line, 1)).toEqual([
{
message: `Param 'var 2' cannot have space`,
lineNumber: 1,
startColumnNumber: 24,
endColumnNumber: 28,
severity: Severity.Warning
},
{
message: `Param 'v ar3' cannot have space`,
lineNumber: 1,
startColumnNumber: 31,
endColumnNumber: 35,
severity: Severity.Warning
}
])
})

it('should return an array with a single diagnostic when Macro definition has invalid option', () => {
const line = '%macro somemacro(var1, var2)/minXoperator;'
expect(strictMacroDefinition.test(line, 1)).toEqual([
{
message: `Option 'minXoperator' is not valid`,
lineNumber: 1,
startColumnNumber: 30,
endColumnNumber: 41,
severity: Severity.Warning
}
])
})

it('should return an array with a two diagnostics when Macro definition has invalid options', () => {
const line =
'%macro somemacro(var1, var2)/ store invalidoption secure ;'
expect(strictMacroDefinition.test(line, 1)).toEqual([
{
message: `Option 'invalidoption' is not valid`,
lineNumber: 1,
startColumnNumber: 39,
endColumnNumber: 51,
severity: Severity.Warning
}
])
})
})
88 changes: 88 additions & 0 deletions src/rules/line/strictMacroDefinition.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { Diagnostic } from '../../types/Diagnostic'
import { LintConfig } from '../../types'
import { LineLintRule } from '../../types/LintRule'
import { LintRuleType } from '../../types/LintRuleType'
import { Severity } from '../../types/Severity'
import { parseMacros } from '../../utils/parseMacros'

const name = 'strictMacroDefinition'
const description = 'Enforce strictly rules of macro definition syntax.'
const message = 'Incorrent Macro Definition Syntax'

const validOptions = [
'CMD',
'DES',
'MINDELIMITER',
'MINOPERATOR',
'NOMINOPERATOR',
'PARMBUFF',
'SECURE',
'NOSECURE',
'STMT',
'SOURCE',
'SRC',
'STORE'
]

const test = (value: string, lineNumber: number) => {
const diagnostics: Diagnostic[] = []

const macros = parseMacros(value)
const declaration = macros[0]?.declaration
if (!declaration) return []

const regExpParams = new RegExp(/\((.*?)\)/)
const regExpParamsResult = regExpParams.exec(declaration)

let _declaration = declaration
if (regExpParamsResult) {
const paramsPresent = regExpParamsResult[1]

const paramsTrimmed = paramsPresent.trim()
const params = paramsTrimmed.split(',')
params.forEach((param) => {
const trimedParam = param.split('=')[0].trim()
if (trimedParam.includes(' ')) {
diagnostics.push({
message: `Param '${trimedParam}' cannot have space`,
lineNumber,
startColumnNumber: value.indexOf(trimedParam) + 1,
endColumnNumber: value.indexOf(trimedParam) + trimedParam.length,
severity: Severity.Warning
})
}
})

_declaration = declaration.split(`(${paramsPresent})`)[1]
}

const optionsPresent = _declaration.split('/')?.[1]?.trim().split(' ')

optionsPresent
?.filter((o) => !!o)
.forEach((option) => {
const trimmedOption = option.trim()
if (!validOptions.includes(trimmedOption.toUpperCase())) {
diagnostics.push({
message: `Option '${trimmedOption}' is not valid`,
lineNumber,
startColumnNumber: value.indexOf(trimmedOption) + 1,
endColumnNumber: value.indexOf(trimmedOption) + trimmedOption.length,
severity: Severity.Warning
})
}
})

return diagnostics
}

/**
* Lint rule that checks if a line has followed syntax for macro definition
*/
export const strictMacroDefinition: LineLintRule = {
type: LintRuleType.Line,
name,
description,
message,
test
}
7 changes: 6 additions & 1 deletion src/types/LintConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import {
maxLineLength,
noEncodedPasswords,
noTabIndentation,
noTrailingSpaces
noTrailingSpaces,
strictMacroDefinition
} from '../rules/line'
import { lowerCaseFileNames, noSpacesInFileNames } from '../rules/path'
import { LineEndings } from './LineEndings'
Expand Down Expand Up @@ -90,5 +91,9 @@ export class LintConfig {
if (json?.hasMacroParentheses) {
this.fileLintRules.push(hasMacroParentheses)
}

if (json?.strictMacroDefinition) {
this.lineLintRules.push(strictMacroDefinition)
}
}
}
2 changes: 1 addition & 1 deletion src/utils/getLintConfig.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { LintConfig } from '../types/LintConfig'
import { getLintConfig } from './getLintConfig'

const expectedFileLintRulesCount = 4
const expectedLineLintRulesCount = 5
const expectedLineLintRulesCount = 6
const expectedPathLintRulesCount = 2

describe('getLintConfig', () => {
Expand Down
3 changes: 2 additions & 1 deletion src/utils/getLintConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ export const DefaultLintConfiguration = {
indentationMultiple: 2,
hasMacroNameInMend: true,
noNestedMacros: true,
hasMacroParentheses: true
hasMacroParentheses: true,
strictMacroDefinition: true
}

/**
Expand Down
5 changes: 4 additions & 1 deletion src/utils/trimComments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ export const trimComments = (

if (commentStarted || trimmed.startsWith('/*')) {
const parts = trimmed.split('*/')
if (parts.length > 1) {
if (parts.length === 2) {
return {
statement: (parts.pop() as string).trim(),
commentStarted: false
}
} else if (parts.length > 2) {
parts.shift()
return trimComments(parts.join('*/'), false)
} else {
return { statement: '', commentStarted: true }
}
Expand Down

0 comments on commit dcfeb7a

Please sign in to comment.