mirror of
https://github.com/sasjs/lint.git
synced 2026-01-17 09:10:06 +00:00
feat(format): rules for hasMacroNameInMend
This commit is contained in:
@@ -339,6 +339,7 @@ describe('hasMacroNameInMend', () => {
|
|||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should add macro name to the mend statement if not present', () => {
|
it('should add macro name to the mend statement if not present', () => {
|
||||||
const content = ` %macro somemacro;\n %put &sysmacroname;\n %mend;`
|
const content = ` %macro somemacro;\n %put &sysmacroname;\n %mend;`
|
||||||
const expectedContent = ` %macro somemacro;\n %put &sysmacroname;\n %mend somemacro;`
|
const expectedContent = ` %macro somemacro;\n %put &sysmacroname;\n %mend somemacro;`
|
||||||
@@ -349,8 +350,8 @@ describe('hasMacroNameInMend', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('should add macro name to the mend statement if not present ( code in single line )', () => {
|
it('should add macro name to the mend statement if not present ( code in single line )', () => {
|
||||||
const content = `%macro somemacro; %put &sysmacroname; %mend;`
|
const content = `%macro somemacro; %put &sysmacroname; %mend; some code;`
|
||||||
const expectedContent = `%macro somemacro; %put &sysmacroname; %mend somemacro;`
|
const expectedContent = `%macro somemacro; %put &sysmacroname; %mend somemacro; some code;`
|
||||||
|
|
||||||
const formattedContent = hasMacroNameInMend.fix!(content, new LintConfig())
|
const formattedContent = hasMacroNameInMend.fix!(content, new LintConfig())
|
||||||
|
|
||||||
@@ -380,9 +381,77 @@ describe('hasMacroNameInMend', () => {
|
|||||||
expect(formattedContent).toEqual(expectedContent)
|
expect(formattedContent).toEqual(expectedContent)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should remove redundant %mend statement', () => {
|
||||||
|
const content = `
|
||||||
|
%macro somemacro;
|
||||||
|
%put &sysmacroname;
|
||||||
|
%mend somemacro;
|
||||||
|
%mend something;`
|
||||||
|
const expectedContent = `
|
||||||
|
%macro somemacro;
|
||||||
|
%put &sysmacroname;
|
||||||
|
%mend somemacro;
|
||||||
|
`
|
||||||
|
|
||||||
|
const formattedContent = hasMacroNameInMend.fix!(content, new LintConfig())
|
||||||
|
expect(formattedContent).toEqual(expectedContent)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should remove redundant %mend statement with comments', () => {
|
||||||
|
const content = `
|
||||||
|
%macro somemacro;
|
||||||
|
%put &sysmacroname;
|
||||||
|
%mend somemacro;
|
||||||
|
/* some comment */
|
||||||
|
/* some comment */ %mend something; some code;
|
||||||
|
/* some comment */`
|
||||||
|
const expectedContent = `
|
||||||
|
%macro somemacro;
|
||||||
|
%put &sysmacroname;
|
||||||
|
%mend somemacro;
|
||||||
|
/* some comment */
|
||||||
|
/* some comment */ some code;
|
||||||
|
/* some comment */`
|
||||||
|
|
||||||
|
const formattedContent = hasMacroNameInMend.fix!(content, new LintConfig())
|
||||||
|
expect(formattedContent).toEqual(expectedContent)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should correct mismatched macro name', () => {
|
||||||
|
const content = `
|
||||||
|
%macro somemacro;
|
||||||
|
%put &sysmacroname;
|
||||||
|
%mend someanothermacro;`
|
||||||
|
const expectedContent = `
|
||||||
|
%macro somemacro;
|
||||||
|
%put &sysmacroname;
|
||||||
|
%mend somemacro;`
|
||||||
|
|
||||||
|
const formattedContent = hasMacroNameInMend.fix!(content, new LintConfig())
|
||||||
|
expect(formattedContent).toEqual(expectedContent)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should correct mismatched macro name with comments', () => {
|
||||||
|
const content = `
|
||||||
|
%macro somemacro;
|
||||||
|
/* some comments */
|
||||||
|
%put &sysmacroname;
|
||||||
|
/* some comments */
|
||||||
|
%mend someanothermacro ;`
|
||||||
|
const expectedContent = `
|
||||||
|
%macro somemacro;
|
||||||
|
/* some comments */
|
||||||
|
%put &sysmacroname;
|
||||||
|
/* some comments */
|
||||||
|
%mend somemacro ;`
|
||||||
|
|
||||||
|
const formattedContent = hasMacroNameInMend.fix!(content, new LintConfig())
|
||||||
|
expect(formattedContent).toEqual(expectedContent)
|
||||||
|
})
|
||||||
|
|
||||||
it('should use the configured line ending while applying the fix', () => {
|
it('should use the configured line ending while applying the fix', () => {
|
||||||
const content = `%macro somemacro();\r\n%put &sysmacroname;\r\n%mend;`
|
const content = `%macro somemacro();\r\n%put &sysmacroname;\r\n%mend ;`
|
||||||
const expectedContent = `%macro somemacro();\r\n%put &sysmacroname;\r\n%mend somemacro;\r\n`
|
const expectedContent = `%macro somemacro();\r\n%put &sysmacroname;\r\n%mend somemacro ;`
|
||||||
|
|
||||||
const formattedContent = hasMacroNameInMend.fix!(
|
const formattedContent = hasMacroNameInMend.fix!(
|
||||||
content,
|
content,
|
||||||
|
|||||||
@@ -18,17 +18,14 @@ const test = (value: string, config?: LintConfig) => {
|
|||||||
const diagnostics: Diagnostic[] = []
|
const diagnostics: Diagnostic[] = []
|
||||||
macros.forEach((macro) => {
|
macros.forEach((macro) => {
|
||||||
if (macro.startLineNumber === null && macro.endLineNumber !== null) {
|
if (macro.startLineNumber === null && macro.endLineNumber !== null) {
|
||||||
|
const endLine = lines[macro.endLineNumber - 1]
|
||||||
diagnostics.push({
|
diagnostics.push({
|
||||||
message: `%mend statement is redundant`,
|
message: `%mend statement is redundant`,
|
||||||
lineNumber: macro.endLineNumber,
|
lineNumber: macro.endLineNumber,
|
||||||
startColumnNumber: getColumnNumber(
|
startColumnNumber: getColumnNumber(endLine, '%mend'),
|
||||||
lines[macro.endLineNumber - 1],
|
|
||||||
'%mend'
|
|
||||||
),
|
|
||||||
endColumnNumber:
|
endColumnNumber:
|
||||||
getColumnNumber(lines[macro.endLineNumber - 1], '%mend') +
|
getColumnNumber(endLine, '%mend') +
|
||||||
lines[macro.endLineNumber - 1].trim().length -
|
macro.terminationTrimmedStatement.length,
|
||||||
1,
|
|
||||||
severity: Severity.Warning
|
severity: Severity.Warning
|
||||||
})
|
})
|
||||||
} else if (macro.endLineNumber === null && macro.startLineNumber !== null) {
|
} else if (macro.endLineNumber === null && macro.startLineNumber !== null) {
|
||||||
@@ -40,35 +37,29 @@ const test = (value: string, config?: LintConfig) => {
|
|||||||
severity: Severity.Warning
|
severity: Severity.Warning
|
||||||
})
|
})
|
||||||
} else if (macro.mismatchedMendMacroName) {
|
} else if (macro.mismatchedMendMacroName) {
|
||||||
|
const endLine = lines[(macro.endLineNumber as number) - 1]
|
||||||
diagnostics.push({
|
diagnostics.push({
|
||||||
message: `%mend statement has mismatched macro name, it should be '${
|
message: `%mend statement has mismatched macro name, it should be '${
|
||||||
macro!.name
|
macro!.name
|
||||||
}'`,
|
}'`,
|
||||||
lineNumber: macro.endLineNumber as number,
|
lineNumber: macro.endLineNumber as number,
|
||||||
startColumnNumber: getColumnNumber(
|
startColumnNumber: getColumnNumber(
|
||||||
lines[(macro.endLineNumber as number) - 1],
|
endLine,
|
||||||
macro.mismatchedMendMacroName
|
macro.mismatchedMendMacroName
|
||||||
),
|
),
|
||||||
endColumnNumber:
|
endColumnNumber:
|
||||||
getColumnNumber(
|
getColumnNumber(endLine, macro.mismatchedMendMacroName) +
|
||||||
lines[(macro.endLineNumber as number) - 1],
|
|
||||||
macro.mismatchedMendMacroName
|
|
||||||
) +
|
|
||||||
macro.mismatchedMendMacroName.length -
|
macro.mismatchedMendMacroName.length -
|
||||||
1,
|
1,
|
||||||
severity: Severity.Warning
|
severity: Severity.Warning
|
||||||
})
|
})
|
||||||
} else if (!macro.hasMacroNameInMend) {
|
} else if (!macro.hasMacroNameInMend) {
|
||||||
|
const endLine = lines[(macro.endLineNumber as number) - 1]
|
||||||
diagnostics.push({
|
diagnostics.push({
|
||||||
message: `%mend statement is missing macro name - ${macro.name}`,
|
message: `%mend statement is missing macro name - ${macro.name}`,
|
||||||
lineNumber: macro.endLineNumber as number,
|
lineNumber: macro.endLineNumber as number,
|
||||||
startColumnNumber: getColumnNumber(
|
startColumnNumber: getColumnNumber(endLine, '%mend'),
|
||||||
lines[(macro.endLineNumber as number) - 1],
|
endColumnNumber: getColumnNumber(endLine, '%mend') + 6,
|
||||||
'%mend'
|
|
||||||
),
|
|
||||||
endColumnNumber:
|
|
||||||
getColumnNumber(lines[(macro.endLineNumber as number) - 1], '%mend') +
|
|
||||||
6,
|
|
||||||
severity: Severity.Warning
|
severity: Severity.Warning
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -79,16 +70,53 @@ const test = (value: string, config?: LintConfig) => {
|
|||||||
|
|
||||||
const fix = (value: string, config?: LintConfig): string => {
|
const fix = (value: string, config?: LintConfig): string => {
|
||||||
const lineEnding = config?.lineEndings === LineEndings.CRLF ? '\r\n' : '\n'
|
const lineEnding = config?.lineEndings === LineEndings.CRLF ? '\r\n' : '\n'
|
||||||
let formattedText = value
|
const lines: string[] = value ? value.split(lineEnding) : []
|
||||||
const macros = parseMacros(value, config)
|
const macros = parseMacros(value, config)
|
||||||
macros
|
|
||||||
.filter((macro) => !macro.hasMacroNameInMend)
|
macros.forEach((macro) => {
|
||||||
.forEach((macro) => {
|
if (macro.startLineNumber === null && macro.endLineNumber !== null) {
|
||||||
formattedText = formattedText.replace(
|
// %mend statement is redundant
|
||||||
macro.termination,
|
const endLine = lines[macro.endLineNumber - 1]
|
||||||
`%mend ${macro.name};${lineEnding}`
|
const startColumnNumber = getColumnNumber(endLine, '%mend')
|
||||||
|
const endColumnNumber =
|
||||||
|
getColumnNumber(endLine, '%mend') +
|
||||||
|
macro.terminationTrimmedStatement.length
|
||||||
|
|
||||||
|
const beforeStatement = endLine.slice(0, startColumnNumber - 1)
|
||||||
|
const afterStatement = endLine.slice(endColumnNumber)
|
||||||
|
lines[macro.endLineNumber - 1] = beforeStatement + afterStatement
|
||||||
|
} else if (macro.endLineNumber === null && macro.startLineNumber !== null) {
|
||||||
|
// missing %mend statement
|
||||||
|
} else if (macro.mismatchedMendMacroName) {
|
||||||
|
// mismatched macro name
|
||||||
|
const endLine = lines[(macro.endLineNumber as number) - 1]
|
||||||
|
const startColumnNumber = getColumnNumber(
|
||||||
|
endLine,
|
||||||
|
macro.mismatchedMendMacroName
|
||||||
)
|
)
|
||||||
})
|
const endColumnNumber =
|
||||||
|
getColumnNumber(endLine, macro.mismatchedMendMacroName) +
|
||||||
|
macro.mismatchedMendMacroName.length -
|
||||||
|
1
|
||||||
|
|
||||||
|
const beforeMacroName = endLine.slice(0, startColumnNumber - 1)
|
||||||
|
const afterMacroName = endLine.slice(endColumnNumber)
|
||||||
|
|
||||||
|
lines[(macro.endLineNumber as number) - 1] =
|
||||||
|
beforeMacroName + macro.name + afterMacroName
|
||||||
|
} else if (!macro.hasMacroNameInMend) {
|
||||||
|
// %mend statement is missing macro name
|
||||||
|
const endLine = lines[(macro.endLineNumber as number) - 1]
|
||||||
|
const startColumnNumber = getColumnNumber(endLine, '%mend')
|
||||||
|
const endColumnNumber = getColumnNumber(endLine, '%mend') + 4
|
||||||
|
|
||||||
|
const beforeStatement = endLine.slice(0, startColumnNumber - 1)
|
||||||
|
const afterStatement = endLine.slice(endColumnNumber)
|
||||||
|
lines[(macro.endLineNumber as number) - 1] =
|
||||||
|
beforeStatement + `%mend ${macro.name}` + afterStatement
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const formattedText = lines.join(lineEnding)
|
||||||
|
|
||||||
return formattedText
|
return formattedText
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ interface Macro {
|
|||||||
endLineNumber: number | null
|
endLineNumber: number | null
|
||||||
declaration: string
|
declaration: string
|
||||||
termination: string
|
termination: string
|
||||||
|
declarationTrimmedStatement: string
|
||||||
|
terminationTrimmedStatement: string
|
||||||
parentMacro: string
|
parentMacro: string
|
||||||
hasMacroNameInMend: boolean
|
hasMacroNameInMend: boolean
|
||||||
hasParentheses: boolean
|
hasParentheses: boolean
|
||||||
@@ -53,7 +55,9 @@ export const parseMacros = (text: string, config?: LintConfig): Macro[] => {
|
|||||||
hasMacroNameInMend: false,
|
hasMacroNameInMend: false,
|
||||||
mismatchedMendMacroName: '',
|
mismatchedMendMacroName: '',
|
||||||
declaration: line,
|
declaration: line,
|
||||||
termination: ''
|
termination: '',
|
||||||
|
declarationTrimmedStatement: trimmedStatement,
|
||||||
|
terminationTrimmedStatement: ''
|
||||||
})
|
})
|
||||||
} else if (trimmedStatement.startsWith('%mend')) {
|
} else if (trimmedStatement.startsWith('%mend')) {
|
||||||
if (macroStack.length) {
|
if (macroStack.length) {
|
||||||
@@ -66,6 +70,7 @@ export const parseMacros = (text: string, config?: LintConfig): Macro[] => {
|
|||||||
? ''
|
? ''
|
||||||
: mendMacroName
|
: mendMacroName
|
||||||
macro.termination = line
|
macro.termination = line
|
||||||
|
macro.terminationTrimmedStatement = trimmedStatement
|
||||||
macros.push(macro)
|
macros.push(macro)
|
||||||
} else {
|
} else {
|
||||||
macros.push({
|
macros.push({
|
||||||
@@ -77,7 +82,9 @@ export const parseMacros = (text: string, config?: LintConfig): Macro[] => {
|
|||||||
hasMacroNameInMend: false,
|
hasMacroNameInMend: false,
|
||||||
mismatchedMendMacroName: '',
|
mismatchedMendMacroName: '',
|
||||||
declaration: '',
|
declaration: '',
|
||||||
termination: line
|
termination: line,
|
||||||
|
declarationTrimmedStatement: '',
|
||||||
|
terminationTrimmedStatement: trimmedStatement
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user