From 0caf31b7ffb95884f92997d9dc95dc7a4af1dd4a Mon Sep 17 00:00:00 2001 From: Saad Jutt Date: Sat, 22 May 2021 00:08:24 +0500 Subject: [PATCH] chore: Code Refactor --- src/rules/file/strictMacroDefinition.ts | 234 +++++++++++++----------- src/types/Macro.ts | 12 ++ src/types/index.ts | 1 + src/utils/parseMacros.ts | 17 +- 4 files changed, 140 insertions(+), 124 deletions(-) create mode 100644 src/types/Macro.ts diff --git a/src/rules/file/strictMacroDefinition.ts b/src/rules/file/strictMacroDefinition.ts index b55eaf0..fed6b85 100644 --- a/src/rules/file/strictMacroDefinition.ts +++ b/src/rules/file/strictMacroDefinition.ts @@ -1,8 +1,6 @@ -import { Diagnostic } from '../../types/Diagnostic' -import { LintConfig } from '../../types' +import { Diagnostic, LintConfig, Macro, Severity } 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' @@ -24,120 +22,136 @@ const validOptions = [ 'STORE' ] +const processParams = ( + content: string, + macro: Macro, + diagnostics: Diagnostic[] +): string => { + const declaration = macro.declaration + + const regExpParams = new RegExp(/(?<=\().*(?=\))/) + const regExpParamsResult = regExpParams.exec(declaration) + + let _declaration = declaration + if (regExpParamsResult) { + const paramsPresent = regExpParamsResult[0] + + const params = paramsPresent.trim().split(',') + params.forEach((param) => { + const trimedParam = param.split('=')[0].trim() + + let paramLineNumber: number = 1, + paramStartIndex: number = 1, + paramEndIndex: number = content.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] + } + return _declaration +} + +const processOptions = ( + _declaration: string, + macro: Macro, + diagnostics: Diagnostic[] +): void => { + let optionsPresent = _declaration.split('/')?.[1]?.trim() + + if (optionsPresent) { + const regex = new RegExp(/="(.*?)"/, 'g') + + let result = regex.exec(optionsPresent) + + // removing Option's `="..."` part, e.g. des="..." + while (result) { + optionsPresent = + optionsPresent.slice(0, result.index) + + optionsPresent.slice(result.index + result[0].length) + + result = regex.exec(optionsPresent) + } + + optionsPresent + .split(' ') + ?.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 + }) + } + }) + } +} + const test = (value: string, config?: LintConfig) => { const diagnostics: Diagnostic[] = [] const macros = parseMacros(value, config) macros.forEach((macro) => { - const declaration = macro.declaration + const _declaration = processParams(value, macro, diagnostics) - const regExpParams = new RegExp(/(?<=\().*(?=\))/) - const regExpParamsResult = regExpParams.exec(declaration) - - let _declaration = declaration - if (regExpParamsResult) { - const paramsPresent = regExpParamsResult[0] - - 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] - } - - let optionsPresent = _declaration.split('/')?.[1]?.trim() - - if (optionsPresent) { - const regex = new RegExp(/="(.*?)"/, 'g') - - let result = regex.exec(optionsPresent) - - while (result) { - optionsPresent = - optionsPresent.slice(0, result.index) + - optionsPresent.slice(result.index + result[0].length) - - result = regex.exec(optionsPresent) - } - - optionsPresent - .split(' ') - ?.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 - }) - } - }) - } + processOptions(_declaration, macro, diagnostics) }) return diagnostics diff --git a/src/types/Macro.ts b/src/types/Macro.ts new file mode 100644 index 0000000..9a44866 --- /dev/null +++ b/src/types/Macro.ts @@ -0,0 +1,12 @@ +export interface Macro { + name: string + startLineNumbers: number[] + endLineNumber: number | null + declarationLines: string[] + terminationLine: string + declaration: string + termination: string + parentMacro: string + hasMacroNameInMend: boolean + mismatchedMendMacroName: string +} diff --git a/src/types/index.ts b/src/types/index.ts index aba5333..37b9911 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -4,3 +4,4 @@ export * from './LintConfig' export * from './LintRule' export * from './LintRuleType' export * from './Severity' +export * from './Macro' diff --git a/src/utils/parseMacros.ts b/src/utils/parseMacros.ts index 51a955e..2147e53 100644 --- a/src/utils/parseMacros.ts +++ b/src/utils/parseMacros.ts @@ -1,20 +1,7 @@ -import { LintConfig } from '../types/LintConfig' +import { LintConfig, Macro } from '../types' import { LineEndings } from '../types/LineEndings' import { trimComments } from './trimComments' -interface Macro { - name: string - startLineNumbers: number[] - endLineNumber: number | null - declarationLines: string[] - terminationLine: string - declaration: string - termination: string - parentMacro: string - hasMacroNameInMend: boolean - mismatchedMendMacroName: string -} - export const parseMacros = (text: string, config?: LintConfig): Macro[] => { const lineEnding = config?.lineEndings === LineEndings.CRLF ? '\r\n' : '\n' const lines: string[] = text ? text.split(lineEnding) : [] @@ -39,6 +26,8 @@ export const parseMacros = (text: string, config?: LintConfig): Macro[] => { const statements: string[] = trimmedLine.split(';') if (isReadingMacroDefinition) { + // checking if code is split into statements based on `;` is a part of HTML Encoded Character + // if it happened, merges two statements into one statements.forEach((statement, statementIndex) => { if (/&[^\s]{1,5}$/.test(statement)) { const next = statements[statementIndex]