mirror of
https://github.com/sasjs/lint.git
synced 2025-12-10 17:34:36 +00:00
feat: mult-line macro declarations
This commit is contained in:
@@ -12,14 +12,14 @@ describe('formatText', () => {
|
||||
new LintConfig(getLintConfigModule.DefaultLintConfiguration)
|
||||
)
|
||||
)
|
||||
const text = `%macro test
|
||||
const text = `%macro test;
|
||||
%put 'hello';\r\n%mend; `
|
||||
|
||||
const expectedOutput = `/**
|
||||
@file
|
||||
@brief <Your brief here>
|
||||
<h4> SAS Macros </h4>
|
||||
**/\n%macro test
|
||||
**/\n%macro test;
|
||||
%put 'hello';\n%mend test;`
|
||||
|
||||
const output = await formatText(text)
|
||||
@@ -38,9 +38,9 @@ describe('formatText', () => {
|
||||
})
|
||||
)
|
||||
)
|
||||
const text = `%macro test\n %put 'hello';\r\n%mend; `
|
||||
const text = `%macro test;\n %put 'hello';\r\n%mend; `
|
||||
|
||||
const expectedOutput = `/**\r\n @file\r\n @brief <Your brief here>\r\n <h4> SAS Macros </h4>\r\n**/\r\n%macro test\r\n %put 'hello';\r\n%mend test;`
|
||||
const expectedOutput = `/**\r\n @file\r\n @brief <Your brief here>\r\n <h4> SAS Macros </h4>\r\n**/\r\n%macro test;\r\n %put 'hello';\r\n%mend test;`
|
||||
|
||||
const output = await formatText(text)
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ describe('hasMacroNameInMend - test', () => {
|
||||
it('should return an array with a diagnostic for each macro missing an %mend statement', () => {
|
||||
const content = `%macro somemacro;
|
||||
%put &sysmacroname;
|
||||
%macro othermacro`
|
||||
%macro othermacro;`
|
||||
|
||||
expect(hasMacroNameInMend.test(content)).toEqual([
|
||||
{
|
||||
|
||||
@@ -17,7 +17,7 @@ const test = (value: string, config?: LintConfig) => {
|
||||
const macros = parseMacros(value, config)
|
||||
const diagnostics: Diagnostic[] = []
|
||||
macros.forEach((macro) => {
|
||||
if (macro.startLineNumber === null && macro.endLineNumber !== null) {
|
||||
if (macro.startLineNumbers.length === 0 && macro.endLineNumber !== null) {
|
||||
const endLine = lines[macro.endLineNumber - 1]
|
||||
diagnostics.push({
|
||||
message: `%mend statement is redundant`,
|
||||
@@ -27,10 +27,13 @@ const test = (value: string, config?: LintConfig) => {
|
||||
getColumnNumber(endLine, '%mend') + macro.termination.length,
|
||||
severity: Severity.Warning
|
||||
})
|
||||
} else if (macro.endLineNumber === null && macro.startLineNumber !== null) {
|
||||
} else if (
|
||||
macro.endLineNumber === null &&
|
||||
macro.startLineNumbers.length !== 0
|
||||
) {
|
||||
diagnostics.push({
|
||||
message: `Missing %mend statement for macro - ${macro.name}`,
|
||||
lineNumber: macro.startLineNumber,
|
||||
lineNumber: macro.startLineNumbers![0],
|
||||
startColumnNumber: 1,
|
||||
endColumnNumber: 1,
|
||||
severity: Severity.Warning
|
||||
@@ -73,7 +76,7 @@ const fix = (value: string, config?: LintConfig): string => {
|
||||
const macros = parseMacros(value, config)
|
||||
|
||||
macros.forEach((macro) => {
|
||||
if (macro.startLineNumber === null && macro.endLineNumber !== null) {
|
||||
if (macro.startLineNumbers.length === 0 && macro.endLineNumber !== null) {
|
||||
// %mend statement is redundant
|
||||
const endLine = lines[macro.endLineNumber - 1]
|
||||
const startColumnNumber = getColumnNumber(endLine, '%mend')
|
||||
@@ -83,7 +86,10 @@ const fix = (value: string, config?: LintConfig): string => {
|
||||
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) {
|
||||
} else if (
|
||||
macro.endLineNumber === null &&
|
||||
macro.startLineNumbers.length !== 0
|
||||
) {
|
||||
// missing %mend statement
|
||||
} else if (macro.mismatchedMendMacroName) {
|
||||
// mismatched macro name
|
||||
|
||||
@@ -140,17 +140,17 @@ describe('hasMacroParentheses', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('should return an array with a single diagnostic when a macro definition contains a space', () => {
|
||||
const content = `%macro test ()`
|
||||
// it('should return an array with a single diagnostic when a macro definition contains a space', () => {
|
||||
// const content = `%macro test ()`
|
||||
|
||||
expect(hasMacroParentheses.test(content)).toEqual([
|
||||
{
|
||||
message: 'Macro definition contains space(s)',
|
||||
lineNumber: 1,
|
||||
startColumnNumber: 8,
|
||||
endColumnNumber: 14,
|
||||
severity: Severity.Warning
|
||||
}
|
||||
])
|
||||
})
|
||||
// expect(hasMacroParentheses.test(content)).toEqual([
|
||||
// {
|
||||
// message: 'Macro definition contains space(s)',
|
||||
// lineNumber: 1,
|
||||
// startColumnNumber: 8,
|
||||
// endColumnNumber: 14,
|
||||
// severity: Severity.Warning
|
||||
// }
|
||||
// ])
|
||||
// })
|
||||
})
|
||||
|
||||
@@ -16,36 +16,48 @@ const test = (value: string, config?: LintConfig) => {
|
||||
if (!macro.name) {
|
||||
diagnostics.push({
|
||||
message: 'Macro definition missing name',
|
||||
lineNumber: macro.startLineNumber!,
|
||||
startColumnNumber: getColumnNumber(macro.declarationLine, '%macro'),
|
||||
lineNumber: macro.startLineNumbers![0],
|
||||
startColumnNumber: getColumnNumber(
|
||||
macro.declarationLines![0],
|
||||
'%macro'
|
||||
),
|
||||
endColumnNumber:
|
||||
getColumnNumber(macro.declarationLine, '%macro') +
|
||||
getColumnNumber(macro.declarationLines![0], '%macro') +
|
||||
macro.declaration.length,
|
||||
severity: Severity.Warning
|
||||
})
|
||||
} else if (!macro.declarationLine.includes('(')) {
|
||||
} else if (!macro.declarationLines.find((dl) => dl.includes('('))) {
|
||||
const macroNameLineIndex = macro.declarationLines.findIndex((dl) =>
|
||||
dl.includes(macro.name)
|
||||
)
|
||||
diagnostics.push({
|
||||
message,
|
||||
lineNumber: macro.startLineNumber!,
|
||||
startColumnNumber: getColumnNumber(macro.declarationLine, macro.name),
|
||||
lineNumber: macro.startLineNumbers![macroNameLineIndex],
|
||||
startColumnNumber: getColumnNumber(
|
||||
macro.declarationLines[macroNameLineIndex],
|
||||
macro.name
|
||||
),
|
||||
endColumnNumber:
|
||||
getColumnNumber(macro.declarationLine, macro.name) +
|
||||
getColumnNumber(
|
||||
macro.declarationLines[macroNameLineIndex],
|
||||
macro.name
|
||||
) +
|
||||
macro.name.length -
|
||||
1,
|
||||
severity: Severity.Warning
|
||||
})
|
||||
} else if (macro.name !== macro.name.trim()) {
|
||||
diagnostics.push({
|
||||
message: 'Macro definition contains space(s)',
|
||||
lineNumber: macro.startLineNumber!,
|
||||
startColumnNumber: getColumnNumber(macro.declarationLine, macro.name),
|
||||
endColumnNumber:
|
||||
getColumnNumber(macro.declarationLine, macro.name) +
|
||||
macro.name.length -
|
||||
1 +
|
||||
`()`.length,
|
||||
severity: Severity.Warning
|
||||
})
|
||||
// } else if (macro.name !== macro.name.trim()) {
|
||||
// diagnostics.push({
|
||||
// message: 'Macro definition contains space(s)',
|
||||
// lineNumber: macro.startLineNumber!,
|
||||
// startColumnNumber: getColumnNumber(macro.declarationLine, macro.name),
|
||||
// endColumnNumber:
|
||||
// getColumnNumber(macro.declarationLine, macro.name) +
|
||||
// macro.name.length -
|
||||
// 1 +
|
||||
// `()`.length,
|
||||
// severity: Severity.Warning
|
||||
// })
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -22,17 +22,17 @@ const test = (value: string, config?: LintConfig) => {
|
||||
message: message
|
||||
.replace('{macro}', macro.name)
|
||||
.replace('{parent}', macro.parentMacro),
|
||||
lineNumber: macro.startLineNumber as number,
|
||||
lineNumber: macro.startLineNumbers![0] as number,
|
||||
startColumnNumber: getColumnNumber(
|
||||
lines[(macro.startLineNumber as number) - 1],
|
||||
lines[(macro.startLineNumbers![0] as number) - 1],
|
||||
'%macro'
|
||||
),
|
||||
endColumnNumber:
|
||||
getColumnNumber(
|
||||
lines[(macro.startLineNumber as number) - 1],
|
||||
lines[(macro.startLineNumbers![0] as number) - 1],
|
||||
'%macro'
|
||||
) +
|
||||
lines[(macro.startLineNumber as number) - 1].trim().length -
|
||||
lines[(macro.startLineNumbers![0] as number) - 1].trim().length -
|
||||
1,
|
||||
severity: Severity.Warning
|
||||
})
|
||||
|
||||
@@ -24,6 +24,19 @@ describe('strictMacroDefinition', () => {
|
||||
const line7 =
|
||||
' /* Some Comment */ %macro somemacro(var1, var2) /minoperator ; /* Some Comment */'
|
||||
expect(strictMacroDefinition.test(line7, 1)).toEqual([])
|
||||
|
||||
const line8 =
|
||||
'%macro macroName( arr, arr/* / store source */3 ) /* / store source */;/* / store source */'
|
||||
expect(strictMacroDefinition.test(line8, 1)).toEqual([])
|
||||
|
||||
const line9 = '%macro macroName(var1, var2=with space, var3=);'
|
||||
expect(strictMacroDefinition.test(line9, 1)).toEqual([])
|
||||
|
||||
const line10 = '%macro macroName()/ /* some comment */ store source;'
|
||||
expect(strictMacroDefinition.test(line10, 1)).toEqual([])
|
||||
|
||||
const line11 = '`%macro macroName() /* / store source */;'
|
||||
expect(strictMacroDefinition.test(line11, 1)).toEqual([])
|
||||
})
|
||||
|
||||
it('should return an array with a single diagnostic when Macro definition has space in param', () => {
|
||||
@@ -39,7 +52,7 @@ describe('strictMacroDefinition', () => {
|
||||
])
|
||||
})
|
||||
|
||||
it('should return an array with a two diagnostics when Macro definition has space in param', () => {
|
||||
it('should return an array with a two diagnostics when Macro definition has space in params', () => {
|
||||
const line = '%macro somemacro(var1, var 2, v ar3, var4);'
|
||||
expect(strictMacroDefinition.test(line, 1)).toEqual([
|
||||
{
|
||||
@@ -59,6 +72,20 @@ describe('strictMacroDefinition', () => {
|
||||
])
|
||||
})
|
||||
|
||||
it('should return an array with a two diagnostics when Macro definition has space in params - special case', () => {
|
||||
const line =
|
||||
'%macro macroName( arr, ar r/* / store source */ 3 ) /* / store source */;/* / store source */'
|
||||
expect(strictMacroDefinition.test(line, 1)).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 line = '%macro somemacro(var1, var2)/minXoperator;'
|
||||
expect(strictMacroDefinition.test(line, 1)).toEqual([
|
||||
|
||||
@@ -42,12 +42,34 @@ const test = (value: string, lineNumber: number) => {
|
||||
const params = paramsTrimmed.split(',')
|
||||
params.forEach((param) => {
|
||||
const trimedParam = param.split('=')[0].trim()
|
||||
|
||||
let paramStartIndex: number = 1,
|
||||
paramEndIndex: number = value.length
|
||||
|
||||
if (value.indexOf(trimedParam) === -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 result = regEx.exec(value)
|
||||
if (result) {
|
||||
paramStartIndex = value.indexOf(result[0])
|
||||
paramEndIndex = value.indexOf(result[0]) + result[0].length
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
paramStartIndex = value.indexOf(trimedParam)
|
||||
paramEndIndex = value.indexOf(trimedParam) + trimedParam.length
|
||||
}
|
||||
|
||||
if (trimedParam.includes(' ')) {
|
||||
diagnostics.push({
|
||||
message: `Param '${trimedParam}' cannot have space`,
|
||||
lineNumber,
|
||||
startColumnNumber: value.indexOf(trimedParam) + 1,
|
||||
endColumnNumber: value.indexOf(trimedParam) + trimedParam.length,
|
||||
startColumnNumber: paramStartIndex + 1,
|
||||
endColumnNumber: paramEndIndex,
|
||||
severity: Severity.Warning
|
||||
})
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { parseMacros } from './parseMacros'
|
||||
|
||||
describe('parseMacros', () => {
|
||||
it('should return an array with a single macro', () => {
|
||||
const text = `%macro test;
|
||||
const text = ` %macro test;
|
||||
%put 'hello';
|
||||
%mend`
|
||||
|
||||
@@ -12,11 +12,11 @@ describe('parseMacros', () => {
|
||||
expect(macros.length).toEqual(1)
|
||||
expect(macros).toContainEqual({
|
||||
name: 'test',
|
||||
declarationLine: '%macro test;',
|
||||
declarationLines: [' %macro test;'],
|
||||
terminationLine: '%mend',
|
||||
declaration: '%macro test',
|
||||
termination: '%mend',
|
||||
startLineNumber: 1,
|
||||
startLineNumbers: [1],
|
||||
endLineNumber: 3,
|
||||
parentMacro: '',
|
||||
hasMacroNameInMend: false,
|
||||
@@ -34,11 +34,11 @@ describe('parseMacros', () => {
|
||||
expect(macros.length).toEqual(1)
|
||||
expect(macros).toContainEqual({
|
||||
name: 'test',
|
||||
declarationLine: '%macro test(var,sum);',
|
||||
declarationLines: ['%macro test(var,sum);'],
|
||||
terminationLine: '%mend',
|
||||
declaration: '%macro test(var,sum)',
|
||||
termination: '%mend',
|
||||
startLineNumber: 1,
|
||||
startLineNumbers: [1],
|
||||
endLineNumber: 3,
|
||||
parentMacro: '',
|
||||
hasMacroNameInMend: false,
|
||||
@@ -56,11 +56,11 @@ describe('parseMacros', () => {
|
||||
expect(macros.length).toEqual(1)
|
||||
expect(macros).toContainEqual({
|
||||
name: 'test',
|
||||
declarationLine: '%macro test/parmbuff;',
|
||||
declarationLines: ['%macro test/parmbuff;'],
|
||||
terminationLine: '%mend',
|
||||
declaration: '%macro test/parmbuff',
|
||||
termination: '%mend',
|
||||
startLineNumber: 1,
|
||||
startLineNumbers: [1],
|
||||
endLineNumber: 3,
|
||||
parentMacro: '',
|
||||
hasMacroNameInMend: false,
|
||||
@@ -79,11 +79,15 @@ describe('parseMacros', () => {
|
||||
expect(macros.length).toEqual(1)
|
||||
expect(macros).toContainEqual({
|
||||
name: 'foobar',
|
||||
declarationLine: '/* commentary */ %macro foobar(arg) /store source',
|
||||
declarationLines: [
|
||||
'/* commentary */ %macro foobar(arg) /store source',
|
||||
' des="This macro does not do much";'
|
||||
],
|
||||
terminationLine: '%mend',
|
||||
declaration: '%macro foobar(arg) /store source',
|
||||
declaration:
|
||||
'%macro foobar(arg) /store source des="This macro does not do much"',
|
||||
termination: '%mend',
|
||||
startLineNumber: 1,
|
||||
startLineNumbers: [1, 2],
|
||||
endLineNumber: 4,
|
||||
parentMacro: '',
|
||||
hasMacroNameInMend: false,
|
||||
@@ -104,11 +108,11 @@ describe('parseMacros', () => {
|
||||
expect(macros.length).toEqual(2)
|
||||
expect(macros).toContainEqual({
|
||||
name: 'foo',
|
||||
declarationLine: '%macro foo;',
|
||||
declarationLines: ['%macro foo;'],
|
||||
terminationLine: '%mend;',
|
||||
declaration: '%macro foo',
|
||||
termination: '%mend',
|
||||
startLineNumber: 1,
|
||||
startLineNumbers: [1],
|
||||
endLineNumber: 3,
|
||||
parentMacro: '',
|
||||
hasMacroNameInMend: false,
|
||||
@@ -116,11 +120,11 @@ describe('parseMacros', () => {
|
||||
})
|
||||
expect(macros).toContainEqual({
|
||||
name: 'bar',
|
||||
declarationLine: '%macro bar();',
|
||||
declarationLines: ['%macro bar();'],
|
||||
terminationLine: '%mend bar;',
|
||||
declaration: '%macro bar()',
|
||||
termination: '%mend bar',
|
||||
startLineNumber: 4,
|
||||
startLineNumbers: [4],
|
||||
endLineNumber: 6,
|
||||
parentMacro: '',
|
||||
hasMacroNameInMend: true,
|
||||
@@ -129,9 +133,9 @@ describe('parseMacros', () => {
|
||||
})
|
||||
|
||||
it('should detect nested macro definitions', () => {
|
||||
const text = `%macro test()
|
||||
const text = `%macro test();
|
||||
%put 'hello';
|
||||
%macro test2
|
||||
%macro test2;
|
||||
%put 'world;
|
||||
%mend
|
||||
%mend test`
|
||||
@@ -141,11 +145,11 @@ describe('parseMacros', () => {
|
||||
expect(macros.length).toEqual(2)
|
||||
expect(macros).toContainEqual({
|
||||
name: 'test',
|
||||
declarationLine: '%macro test()',
|
||||
declarationLines: ['%macro test();'],
|
||||
terminationLine: '%mend test',
|
||||
declaration: '%macro test()',
|
||||
termination: '%mend test',
|
||||
startLineNumber: 1,
|
||||
startLineNumbers: [1],
|
||||
endLineNumber: 6,
|
||||
parentMacro: '',
|
||||
hasMacroNameInMend: true,
|
||||
@@ -153,15 +157,125 @@ describe('parseMacros', () => {
|
||||
})
|
||||
expect(macros).toContainEqual({
|
||||
name: 'test2',
|
||||
declarationLine: ' %macro test2',
|
||||
declarationLines: [' %macro test2;'],
|
||||
terminationLine: ' %mend',
|
||||
declaration: '%macro test2',
|
||||
termination: '%mend',
|
||||
startLineNumber: 3,
|
||||
startLineNumbers: [3],
|
||||
endLineNumber: 5,
|
||||
parentMacro: 'test',
|
||||
hasMacroNameInMend: false,
|
||||
mismatchedMendMacroName: ''
|
||||
})
|
||||
})
|
||||
|
||||
describe(`multi-line macro declarations`, () => {
|
||||
it('should return an array with a single macro', () => {
|
||||
const text = `%macro
|
||||
test;
|
||||
%put 'hello';
|
||||
%mend`
|
||||
|
||||
const macros = parseMacros(text, new LintConfig())
|
||||
|
||||
expect(macros.length).toEqual(1)
|
||||
expect(macros).toContainEqual({
|
||||
name: 'test',
|
||||
declarationLines: ['%macro ', ' test;'],
|
||||
terminationLine: '%mend',
|
||||
declaration: '%macro test',
|
||||
termination: '%mend',
|
||||
startLineNumbers: [1, 2],
|
||||
endLineNumber: 4,
|
||||
parentMacro: '',
|
||||
hasMacroNameInMend: false,
|
||||
mismatchedMendMacroName: ''
|
||||
})
|
||||
})
|
||||
|
||||
it('should return an array with a single macro having parameters', () => {
|
||||
const text = `%macro
|
||||
test(
|
||||
var,
|
||||
sum);%put 'hello';
|
||||
%mend`
|
||||
|
||||
const macros = parseMacros(text, new LintConfig())
|
||||
|
||||
expect(macros.length).toEqual(1)
|
||||
expect(macros).toContainEqual({
|
||||
name: 'test',
|
||||
declarationLines: [
|
||||
'%macro ',
|
||||
` test(`,
|
||||
` var,`,
|
||||
` sum);%put 'hello';`
|
||||
],
|
||||
terminationLine: '%mend',
|
||||
declaration: '%macro test( var, sum)',
|
||||
termination: '%mend',
|
||||
startLineNumbers: [1, 2, 3, 4],
|
||||
endLineNumber: 5,
|
||||
parentMacro: '',
|
||||
hasMacroNameInMend: false,
|
||||
mismatchedMendMacroName: ''
|
||||
})
|
||||
})
|
||||
|
||||
it('should return an array with a single macro having PARMBUFF option', () => {
|
||||
const text = `%macro test
|
||||
/parmbuff;
|
||||
%put 'hello';
|
||||
%mend`
|
||||
|
||||
const macros = parseMacros(text, new LintConfig())
|
||||
|
||||
expect(macros.length).toEqual(1)
|
||||
expect(macros).toContainEqual({
|
||||
name: 'test',
|
||||
declarationLines: ['%macro test', ' /parmbuff;'],
|
||||
terminationLine: '%mend',
|
||||
declaration: '%macro test /parmbuff',
|
||||
termination: '%mend',
|
||||
startLineNumbers: [1, 2],
|
||||
endLineNumber: 4,
|
||||
parentMacro: '',
|
||||
hasMacroNameInMend: false,
|
||||
mismatchedMendMacroName: ''
|
||||
})
|
||||
})
|
||||
|
||||
it('should return an array with a single macro having paramerter & SOURCE option', () => {
|
||||
const text = `/* commentary */ %macro foobar/* commentary */(arg)
|
||||
/* commentary */
|
||||
/store
|
||||
/* commentary */source
|
||||
des="This macro does not do much";
|
||||
%put 'hello';
|
||||
%mend`
|
||||
|
||||
const macros = parseMacros(text, new LintConfig())
|
||||
|
||||
expect(macros.length).toEqual(1)
|
||||
expect(macros).toContainEqual({
|
||||
name: 'foobar',
|
||||
declarationLines: [
|
||||
'/* commentary */ %macro foobar/* commentary */(arg) ',
|
||||
' /* commentary */',
|
||||
' /store',
|
||||
' /* commentary */source',
|
||||
' des="This macro does not do much";'
|
||||
],
|
||||
terminationLine: '%mend',
|
||||
declaration:
|
||||
'%macro foobar(arg) /store source des="This macro does not do much"',
|
||||
termination: '%mend',
|
||||
startLineNumbers: [1, 2, 3, 4, 5],
|
||||
endLineNumber: 7,
|
||||
parentMacro: '',
|
||||
hasMacroNameInMend: false,
|
||||
mismatchedMendMacroName: ''
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -4,9 +4,9 @@ import { trimComments } from './trimComments'
|
||||
|
||||
interface Macro {
|
||||
name: string
|
||||
startLineNumber: number | null
|
||||
startLineNumbers: number[]
|
||||
endLineNumber: number | null
|
||||
declarationLine: string
|
||||
declarationLines: string[]
|
||||
terminationLine: string
|
||||
declaration: string
|
||||
termination: string
|
||||
@@ -22,38 +22,92 @@ export const parseMacros = (text: string, config?: LintConfig): Macro[] => {
|
||||
|
||||
let isCommentStarted = false
|
||||
let macroStack: Macro[] = []
|
||||
lines.forEach((line, index) => {
|
||||
let isReadingMacroDefinition = false
|
||||
let isStatementContinues = true
|
||||
let tempMacroDeclaration = ''
|
||||
let tempMacroDeclarationLines: string[] = []
|
||||
let tempStartLineNumbers: number[] = []
|
||||
lines.forEach((line, lineIndex) => {
|
||||
const { statement: trimmedLine, commentStarted } = trimComments(
|
||||
line,
|
||||
isCommentStarted
|
||||
)
|
||||
isCommentStarted = commentStarted
|
||||
const statements: string[] = trimmedLine ? trimmedLine.split(';') : []
|
||||
|
||||
statements.forEach((statement) => {
|
||||
isStatementContinues = !trimmedLine.endsWith(';')
|
||||
|
||||
const statements: string[] = trimmedLine.split(';')
|
||||
|
||||
statements.forEach((statement, statementIndex) => {
|
||||
const { statement: trimmedStatement, commentStarted } = trimComments(
|
||||
statement,
|
||||
isCommentStarted
|
||||
)
|
||||
isCommentStarted = commentStarted
|
||||
|
||||
if (isReadingMacroDefinition) {
|
||||
tempMacroDeclaration =
|
||||
tempMacroDeclaration +
|
||||
(trimmedStatement ? ' ' + trimmedStatement : '')
|
||||
tempMacroDeclarationLines.push(line)
|
||||
tempStartLineNumbers.push(lineIndex + 1)
|
||||
|
||||
if (!Object.is(statements.length - 1, statementIndex)) {
|
||||
isReadingMacroDefinition = false
|
||||
|
||||
const name = tempMacroDeclaration
|
||||
.slice(7, tempMacroDeclaration.length)
|
||||
.trim()
|
||||
.split('/')[0]
|
||||
.split('(')[0]
|
||||
.trim()
|
||||
macroStack.push({
|
||||
name,
|
||||
startLineNumbers: tempStartLineNumbers,
|
||||
endLineNumber: null,
|
||||
parentMacro: macroStack.length
|
||||
? macroStack[macroStack.length - 1].name
|
||||
: '',
|
||||
hasMacroNameInMend: false,
|
||||
mismatchedMendMacroName: '',
|
||||
declarationLines: tempMacroDeclarationLines,
|
||||
terminationLine: '',
|
||||
declaration: tempMacroDeclaration,
|
||||
termination: ''
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (trimmedStatement.startsWith('%macro')) {
|
||||
const startLineNumber = index + 1
|
||||
const startLineNumber = lineIndex + 1
|
||||
|
||||
if (
|
||||
isStatementContinues &&
|
||||
Object.is(statements.length - 1, statementIndex)
|
||||
) {
|
||||
tempMacroDeclaration = trimmedStatement
|
||||
tempMacroDeclarationLines = [line]
|
||||
tempStartLineNumbers = [startLineNumber]
|
||||
isReadingMacroDefinition = true
|
||||
return
|
||||
}
|
||||
|
||||
const name = trimmedStatement
|
||||
.slice(7, trimmedStatement.length)
|
||||
.trim()
|
||||
.split('/')[0]
|
||||
.split('(')[0]
|
||||
.trim()
|
||||
macroStack.push({
|
||||
name,
|
||||
startLineNumber,
|
||||
startLineNumbers: [startLineNumber],
|
||||
endLineNumber: null,
|
||||
parentMacro: macroStack.length
|
||||
? macroStack[macroStack.length - 1].name
|
||||
: '',
|
||||
hasMacroNameInMend: false,
|
||||
mismatchedMendMacroName: '',
|
||||
declarationLine: line,
|
||||
declarationLines: [line],
|
||||
terminationLine: '',
|
||||
declaration: trimmedStatement,
|
||||
termination: ''
|
||||
@@ -63,7 +117,7 @@ export const parseMacros = (text: string, config?: LintConfig): Macro[] => {
|
||||
const macro = macroStack.pop() as Macro
|
||||
const mendMacroName =
|
||||
trimmedStatement.split(' ').filter((s: string) => !!s)[1] || ''
|
||||
macro.endLineNumber = index + 1
|
||||
macro.endLineNumber = lineIndex + 1
|
||||
macro.hasMacroNameInMend = mendMacroName === macro.name
|
||||
macro.mismatchedMendMacroName = macro.hasMacroNameInMend
|
||||
? ''
|
||||
@@ -74,12 +128,12 @@ export const parseMacros = (text: string, config?: LintConfig): Macro[] => {
|
||||
} else {
|
||||
macros.push({
|
||||
name: '',
|
||||
startLineNumber: null,
|
||||
endLineNumber: index + 1,
|
||||
startLineNumbers: [],
|
||||
endLineNumber: lineIndex + 1,
|
||||
parentMacro: '',
|
||||
hasMacroNameInMend: false,
|
||||
mismatchedMendMacroName: '',
|
||||
declarationLine: '',
|
||||
declarationLines: [],
|
||||
terminationLine: line,
|
||||
declaration: '',
|
||||
termination: trimmedStatement
|
||||
|
||||
@@ -13,7 +13,7 @@ describe('trimComments', () => {
|
||||
/* some comment */ CODE_Keyword1 /* some comment */ CODE_Keyword2/* some comment */;/* some comment */
|
||||
/* some comment */`)
|
||||
).toEqual({
|
||||
statement: 'CODE_Keyword1 CODE_Keyword2;',
|
||||
statement: 'CODE_Keyword1 CODE_Keyword2;',
|
||||
commentStarted: false
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
export const trimComments = (
|
||||
statement: string,
|
||||
commentStarted: boolean = false
|
||||
commentStarted: boolean = false,
|
||||
trimEnd: boolean = false
|
||||
): { statement: string; commentStarted: boolean } => {
|
||||
let trimmed = (statement || '').trim()
|
||||
let trimmed = trimEnd ? (statement || '').trimEnd() : (statement || '').trim()
|
||||
|
||||
if (commentStarted || trimmed.startsWith('/*')) {
|
||||
const parts = trimmed.split('*/')
|
||||
@@ -20,13 +21,16 @@ export const trimComments = (
|
||||
} else if (trimmed.includes('/*')) {
|
||||
const statementBeforeCommentStarts = trimmed.slice(0, trimmed.indexOf('/*'))
|
||||
const remainingStatement = trimmed.slice(
|
||||
trimmed.indexOf('/*'),
|
||||
trimmed.indexOf('*/') + 2,
|
||||
trimmed.length
|
||||
)
|
||||
|
||||
const result = trimComments(remainingStatement, false)
|
||||
const result = trimComments(remainingStatement, false, true)
|
||||
const completeStatement = statementBeforeCommentStarts + result.statement
|
||||
return {
|
||||
statement: statementBeforeCommentStarts + result.statement,
|
||||
statement: trimEnd
|
||||
? completeStatement.trimEnd()
|
||||
: completeStatement.trim(),
|
||||
commentStarted: result.commentStarted
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user