Skip to content

Commit

Permalink
fix(strictMacroDefinition): moved from lineRules to fileRules
Browse files Browse the repository at this point in the history
  • Loading branch information
saadjutt01 committed May 21, 2021

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
1 parent af2d2c1 commit f793eb3
Showing 8 changed files with 351 additions and 232 deletions.
1 change: 1 addition & 0 deletions src/rules/file/index.ts
Original file line number Diff line number Diff line change
@@ -3,3 +3,4 @@ export { hasMacroNameInMend } from './hasMacroNameInMend'
export { hasMacroParentheses } from './hasMacroParentheses'
export { lineEndings } from './lineEndings'
export { noNestedMacros } from './noNestedMacros'
export { strictMacroDefinition } from './strictMacroDefinition'
204 changes: 204 additions & 0 deletions src/rules/file/strictMacroDefinition.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
import { LintConfig, Severity } from '../../types'
import { strictMacroDefinition } from './strictMacroDefinition'

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

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

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

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

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

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

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

const content8 =
'%macro macroName( arr, arr/* / store source */3 ) /* / store source */;/* / store source */'
expect(strictMacroDefinition.test(content8)).toEqual([])

const content9 = '%macro macroName(var1, var2=with space, var3=);'
expect(strictMacroDefinition.test(content9)).toEqual([])

const content10 = '%macro macroName()/ /* some comment */ store source;'
expect(strictMacroDefinition.test(content10)).toEqual([])

const content11 = '`%macro macroName() /* / store source */;'
expect(strictMacroDefinition.test(content11)).toEqual([])
})

it('should return an array with a single diagnostic when Macro definition has space in param', () => {
const content = '%macro somemacro(va r1);'
expect(strictMacroDefinition.test(content)).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 params', () => {
const content = '%macro somemacro(var1, var 2, v ar3, var4);'
expect(strictMacroDefinition.test(content)).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 two diagnostics when Macro definition has space in params - special case', () => {
const content =
'%macro macroName( arr, ar r/* / store source */ 3 ) /* / store source */;/* / store source */'
expect(strictMacroDefinition.test(content)).toEqual([
{
message: `Param 'ar r 3' cannot have space`,
lineNumber: 1,
startColumnNumber: 24,
endColumnNumber: 49,
severity: Severity.Warning
}
])
})

it('should return an array with a single diagnostic when Macro definition has invalid option', () => {
const content = '%macro somemacro(var1, var2)/minXoperator;'
expect(strictMacroDefinition.test(content)).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 content =
'%macro somemacro(var1, var2)/ store invalidoption secure ;'
expect(strictMacroDefinition.test(content)).toEqual([
{
message: `Option 'invalidoption' is not valid`,
lineNumber: 1,
startColumnNumber: 39,
endColumnNumber: 51,
severity: Severity.Warning
}
])
})

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

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

it('should return an array with a two diagnostics when Macro definition has space in params - special case', () => {
const content = `%macro macroName(
arr,
ar r/* / store source */ 3
) /* / store source */;/* / store source */`
expect(strictMacroDefinition.test(content)).toEqual([
{
message: `Param 'ar r 3' cannot have space`,
lineNumber: 3,
startColumnNumber: 7,
endColumnNumber: 32,
severity: Severity.Warning
}
])
})

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

it('should return an array with a two diagnostics when Macro definition has invalid options', () => {
const content = `%macro
somemacro(
var1, var2
)
/ store
invalidoption
secure ;`
expect(strictMacroDefinition.test(content)).toEqual([
{
message: `Option 'invalidoption' is not valid`,
lineNumber: 6,
startColumnNumber: 16,
endColumnNumber: 28,
severity: Severity.Warning
}
])
})
})
})
140 changes: 140 additions & 0 deletions src/rules/file/strictMacroDefinition.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import { Diagnostic } from '../../types/Diagnostic'
import { LintConfig } from '../../types'
import { FileLintRule } 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, config?: LintConfig) => {
const diagnostics: Diagnostic[] = []

const macros = parseMacros(value, config)

macros.forEach((macro) => {
const declaration = macro.declaration

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()

let paramLineNumber: number = 1,
paramStartIndex: number = 1,
paramEndIndex: number = value.length

if (
macro.declarationLines.findIndex(
(dl) => dl.indexOf(trimedParam) !== -1
) === -1
) {
const comment = '/\\*(.*?)\\*/'
for (let i = 1; i < trimedParam.length; i++) {
const paramWithComment =
trimedParam.slice(0, i) + comment + trimedParam.slice(i)
const regEx = new RegExp(paramWithComment)

const declarationLineIndex = macro.declarationLines.findIndex(
(dl) => !!regEx.exec(dl)
)

if (declarationLineIndex !== -1) {
const declarationLine =
macro.declarationLines[declarationLineIndex]
const partFound = regEx.exec(declarationLine)![0]

paramLineNumber = macro.startLineNumbers[declarationLineIndex]
paramStartIndex = declarationLine.indexOf(partFound)
paramEndIndex =
declarationLine.indexOf(partFound) + partFound.length
break
}
}
} else {
const declarationLineIndex = macro.declarationLines.findIndex(
(dl) => dl.indexOf(trimedParam) !== -1
)
const declarationLine = macro.declarationLines[declarationLineIndex]
paramLineNumber = macro.startLineNumbers[declarationLineIndex]

paramStartIndex = declarationLine.indexOf(trimedParam)
paramEndIndex =
declarationLine.indexOf(trimedParam) + trimedParam.length
}

if (trimedParam.includes(' ')) {
diagnostics.push({
message: `Param '${trimedParam}' cannot have space`,
lineNumber: paramLineNumber,
startColumnNumber: paramStartIndex + 1,
endColumnNumber: paramEndIndex,
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())) {
const declarationLineIndex = macro.declarationLines.findIndex(
(dl) => dl.indexOf(trimmedOption) !== -1
)
const declarationLine = macro.declarationLines[declarationLineIndex]

diagnostics.push({
message: `Option '${trimmedOption}' is not valid`,
lineNumber: macro.startLineNumbers[declarationLineIndex],
startColumnNumber: declarationLine.indexOf(trimmedOption) + 1,
endColumnNumber:
declarationLine.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: FileLintRule = {
type: LintRuleType.File,
name,
description,
message,
test
}
1 change: 0 additions & 1 deletion src/rules/line/index.ts
Original file line number Diff line number Diff line change
@@ -3,4 +3,3 @@ export { maxLineLength } from './maxLineLength'
export { noEncodedPasswords } from './noEncodedPasswords'
export { noTabIndentation } from './noTabIndentation'
export { noTrailingSpaces } from './noTrailingSpaces'
export { strictMacroDefinition } from './strictMacroDefinition'
Loading

0 comments on commit f793eb3

Please sign in to comment.