mirror of
https://github.com/sasjs/lint.git
synced 2026-01-02 18:40:06 +00:00
test: for hasMacroParentheses & noNestedMacros
This commit is contained in:
@@ -25,8 +25,8 @@ const test = (value: string) => {
|
|||||||
|
|
||||||
if (trimmedStatement.startsWith('%macro ')) {
|
if (trimmedStatement.startsWith('%macro ')) {
|
||||||
const macroName = trimmedStatement
|
const macroName = trimmedStatement
|
||||||
.split(' ')
|
.slice(7, trimmedStatement.length)
|
||||||
.filter((s: string) => !!s)[1]
|
.trim()
|
||||||
.split('(')[0]
|
.split('(')[0]
|
||||||
stack.push(macroName)
|
stack.push(macroName)
|
||||||
} else if (trimmedStatement.startsWith('%mend')) {
|
} else if (trimmedStatement.startsWith('%mend')) {
|
||||||
|
|||||||
128
src/rules/hasMacroParentheses.spec.ts
Normal file
128
src/rules/hasMacroParentheses.spec.ts
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
import { Severity } from '../types/Severity'
|
||||||
|
import { hasMacroParentheses } from './hasMacroParentheses'
|
||||||
|
|
||||||
|
describe('hasMacroParentheses', () => {
|
||||||
|
it('should return an empty array when macro defined correctly', () => {
|
||||||
|
const content = `
|
||||||
|
%macro somemacro();
|
||||||
|
%put &sysmacroname;
|
||||||
|
%mend somemacro;`
|
||||||
|
|
||||||
|
expect(hasMacroParentheses.test(content)).toEqual([])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return an array with a single diagnostics when macro defined without parentheses', () => {
|
||||||
|
const content = `
|
||||||
|
%macro somemacro;
|
||||||
|
%put &sysmacroname;
|
||||||
|
%mend somemacro;`
|
||||||
|
|
||||||
|
expect(hasMacroParentheses.test(content)).toEqual([
|
||||||
|
{
|
||||||
|
message: 'Macro definition missing parentheses',
|
||||||
|
lineNumber: 2,
|
||||||
|
startColumnNumber: 10,
|
||||||
|
endColumnNumber: 18,
|
||||||
|
severity: Severity.Warning
|
||||||
|
}
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return an array with a single diagnostics when macro defined without name', () => {
|
||||||
|
const content = `
|
||||||
|
%macro ();
|
||||||
|
%put &sysmacroname;
|
||||||
|
%mend;`
|
||||||
|
|
||||||
|
expect(hasMacroParentheses.test(content)).toEqual([
|
||||||
|
{
|
||||||
|
message: 'Macro definition missing name',
|
||||||
|
lineNumber: 2,
|
||||||
|
startColumnNumber: 3,
|
||||||
|
endColumnNumber: 12,
|
||||||
|
severity: Severity.Warning
|
||||||
|
}
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return an array with a single diagnostics when macro defined without name and parentheses', () => {
|
||||||
|
const content = `
|
||||||
|
%macro ;
|
||||||
|
%put &sysmacroname;
|
||||||
|
%mend;`
|
||||||
|
|
||||||
|
expect(hasMacroParentheses.test(content)).toEqual([
|
||||||
|
{
|
||||||
|
message: 'Macro definition missing name',
|
||||||
|
lineNumber: 2,
|
||||||
|
startColumnNumber: 3,
|
||||||
|
endColumnNumber: 10,
|
||||||
|
severity: Severity.Warning
|
||||||
|
}
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return an empty array when the file is undefined', () => {
|
||||||
|
const content = undefined
|
||||||
|
|
||||||
|
expect(hasMacroParentheses.test((content as unknown) as string)).toEqual([])
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('with extra spaces and comments', () => {
|
||||||
|
it('should return an empty array when %mend has correct macro name', () => {
|
||||||
|
const content = `
|
||||||
|
/* 1st comment */
|
||||||
|
%macro somemacro();
|
||||||
|
|
||||||
|
%put &sysmacroname;
|
||||||
|
|
||||||
|
/* 2nd
|
||||||
|
comment */
|
||||||
|
/* 3rd comment */ %mend somemacro ;`
|
||||||
|
|
||||||
|
expect(hasMacroParentheses.test(content)).toEqual([])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return an array with a single diagnostic when macro defined without parentheses having code in comments', () => {
|
||||||
|
const content = `/**
|
||||||
|
@file examplemacro.sas
|
||||||
|
@brief an example of a macro to be used in a service
|
||||||
|
@details This macro is great. Yadda yadda yadda. Usage:
|
||||||
|
|
||||||
|
* code formatting applies when indented by 4 spaces; code formatting applies when indented by 4 spaces; code formatting applies when indented by 4 spaces; code formatting applies when indented by 4 spaces; code formatting applies when indented by 4 spaces;
|
||||||
|
|
||||||
|
some code
|
||||||
|
%macro examplemacro123();
|
||||||
|
|
||||||
|
%examplemacro()
|
||||||
|
|
||||||
|
<h4> SAS Macros </h4>
|
||||||
|
@li doesnothing.sas
|
||||||
|
|
||||||
|
@author Allan Bowe
|
||||||
|
**/
|
||||||
|
|
||||||
|
%macro examplemacro;
|
||||||
|
|
||||||
|
proc sql;
|
||||||
|
create table areas
|
||||||
|
as select area
|
||||||
|
|
||||||
|
from sashelp.springs;
|
||||||
|
|
||||||
|
%doesnothing();
|
||||||
|
|
||||||
|
%mend;`
|
||||||
|
|
||||||
|
expect(hasMacroParentheses.test(content)).toEqual([
|
||||||
|
{
|
||||||
|
message: 'Macro definition missing parentheses',
|
||||||
|
lineNumber: 19,
|
||||||
|
startColumnNumber: 12,
|
||||||
|
endColumnNumber: 23,
|
||||||
|
severity: Severity.Warning
|
||||||
|
}
|
||||||
|
])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -22,14 +22,23 @@ const test = (value: string) => {
|
|||||||
commentStarted
|
commentStarted
|
||||||
))
|
))
|
||||||
|
|
||||||
if (trimmedStatement.startsWith('%macro ')) {
|
if (trimmedStatement.startsWith('%macro')) {
|
||||||
const macroNameDefinition = trimmedStatement
|
const macroNameDefinition = trimmedStatement
|
||||||
.slice(7, trimmedStatement.length)
|
.slice(7, trimmedStatement.length)
|
||||||
.trim()
|
.trim()
|
||||||
|
|
||||||
const macroNameDefinitionParts = macroNameDefinition.split('(')
|
const macroNameDefinitionParts = macroNameDefinition.split('(')
|
||||||
const macroName = macroNameDefinitionParts[0]
|
const macroName = macroNameDefinitionParts[0]
|
||||||
if (macroNameDefinitionParts.length === 1)
|
|
||||||
|
if (!macroName)
|
||||||
|
diagnostics.push({
|
||||||
|
message: 'Macro definition missing name',
|
||||||
|
lineNumber: getLineNumber(statements, index + 1),
|
||||||
|
startColumnNumber: getColNumber(statement, '%macro'),
|
||||||
|
endColumnNumber: statement.length,
|
||||||
|
severity: Severity.Warning
|
||||||
|
})
|
||||||
|
else if (macroNameDefinitionParts.length === 1)
|
||||||
diagnostics.push({
|
diagnostics.push({
|
||||||
message,
|
message,
|
||||||
lineNumber: getLineNumber(statements, index + 1),
|
lineNumber: getLineNumber(statements, index + 1),
|
||||||
|
|||||||
78
src/rules/noNestedMacros.spec.ts
Normal file
78
src/rules/noNestedMacros.spec.ts
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
import { Severity } from '../types/Severity'
|
||||||
|
import { noNestedMacros } from './noNestedMacros'
|
||||||
|
|
||||||
|
describe('noNestedMacros', () => {
|
||||||
|
it('should return an empty array when no nested macro', () => {
|
||||||
|
const content = `
|
||||||
|
%macro somemacro();
|
||||||
|
%put &sysmacroname;
|
||||||
|
%mend somemacro;`
|
||||||
|
|
||||||
|
expect(noNestedMacros.test(content)).toEqual([])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return an array with a single diagnostics when nested macro defined', () => {
|
||||||
|
const content = `
|
||||||
|
%macro outer();
|
||||||
|
/* any amount of arbitrary code */
|
||||||
|
%macro inner();
|
||||||
|
%put inner;
|
||||||
|
%mend;
|
||||||
|
%inner()
|
||||||
|
%put outer;
|
||||||
|
%mend;
|
||||||
|
|
||||||
|
%outer()`
|
||||||
|
|
||||||
|
expect(noNestedMacros.test(content)).toEqual([
|
||||||
|
{
|
||||||
|
message: "Macro definition present inside another macro 'outer'",
|
||||||
|
lineNumber: 4,
|
||||||
|
startColumnNumber: 7,
|
||||||
|
endColumnNumber: 21,
|
||||||
|
severity: Severity.Warning
|
||||||
|
}
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return an array with a single diagnostics when nested macro defined 2 levels', () => {
|
||||||
|
const content = `
|
||||||
|
%macro outer();
|
||||||
|
/* any amount of arbitrary code */
|
||||||
|
%macro inner();
|
||||||
|
%put inner;
|
||||||
|
|
||||||
|
%macro inner2();
|
||||||
|
%put inner2;
|
||||||
|
%mend;
|
||||||
|
%mend;
|
||||||
|
%inner()
|
||||||
|
%put outer;
|
||||||
|
%mend;
|
||||||
|
|
||||||
|
%outer()`
|
||||||
|
|
||||||
|
expect(noNestedMacros.test(content)).toEqual([
|
||||||
|
{
|
||||||
|
message: "Macro definition present inside another macro 'outer'",
|
||||||
|
lineNumber: 4,
|
||||||
|
startColumnNumber: 7,
|
||||||
|
endColumnNumber: 21,
|
||||||
|
severity: Severity.Warning
|
||||||
|
},
|
||||||
|
{
|
||||||
|
message: "Macro definition present inside another macro 'inner'",
|
||||||
|
lineNumber: 7,
|
||||||
|
startColumnNumber: 17,
|
||||||
|
endColumnNumber: 32,
|
||||||
|
severity: Severity.Warning
|
||||||
|
}
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return an empty array when the file is undefined', () => {
|
||||||
|
const content = undefined
|
||||||
|
|
||||||
|
expect(noNestedMacros.test((content as unknown) as string)).toEqual([])
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -25,8 +25,8 @@ const test = (value: string) => {
|
|||||||
|
|
||||||
if (trimmedStatement.startsWith('%macro ')) {
|
if (trimmedStatement.startsWith('%macro ')) {
|
||||||
const macroName = trimmedStatement
|
const macroName = trimmedStatement
|
||||||
.split(' ')
|
.slice(7, trimmedStatement.length)
|
||||||
.filter((s: string) => !!s)[1]
|
.trim()
|
||||||
.split('(')[0]
|
.split('(')[0]
|
||||||
if (stack.length) {
|
if (stack.length) {
|
||||||
const parentMacro = stack.slice(-1).pop()
|
const parentMacro = stack.slice(-1).pop()
|
||||||
|
|||||||
Reference in New Issue
Block a user