@sasjs/lint
Version:
Linting and formatting for SAS code
132 lines • 6.11 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseMacros = void 0;
const LineEndings_1 = require("../types/LineEndings");
const trimComments_1 = require("./trimComments");
const parseMacros = (text, config) => {
const lineEnding = (config === null || config === void 0 ? void 0 : config.lineEndings) === LineEndings_1.LineEndings.CRLF ? '\r\n' : '\n';
const lines = text ? text.split(lineEnding) : [];
const macros = [];
let isCommentStarted = false;
let macroStack = [];
let isReadingMacroDefinition = false;
let isStatementContinues = true;
let tempMacroDeclaration = '';
let tempMacroDeclarationLines = [];
let tempStartLineNumbers = [];
lines.forEach((line, lineIndex) => {
const { statement: trimmedLine, commentStarted } = (0, trimComments_1.trimComments)(line, isCommentStarted);
isCommentStarted = commentStarted;
isStatementContinues = !trimmedLine.endsWith(';');
const statements = 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];
const updatedStatement = `${statement};${statements[statementIndex + 1]}`;
statements.splice(statementIndex, 1, updatedStatement);
statements.splice(statementIndex + 1, 1);
}
});
}
statements.forEach((statement, statementIndex) => {
const { statement: trimmedStatement, commentStarted } = (0, trimComments_1.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 = 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,
startLineNumbers: [startLineNumber],
endLineNumber: null,
parentMacro: macroStack.length
? macroStack[macroStack.length - 1].name
: '',
hasMacroNameInMend: false,
mismatchedMendMacroName: '',
declarationLines: [line],
terminationLine: '',
declaration: trimmedStatement,
termination: ''
});
}
else if (trimmedStatement.startsWith('%mend')) {
if (macroStack.length) {
const macro = macroStack.pop();
const mendMacroName = trimmedStatement.split(' ').filter((s) => !!s)[1] || '';
macro.endLineNumber = lineIndex + 1;
macro.hasMacroNameInMend = mendMacroName === macro.name;
macro.mismatchedMendMacroName = macro.hasMacroNameInMend
? ''
: mendMacroName;
macro.terminationLine = line;
macro.termination = trimmedStatement;
macros.push(macro);
}
else {
macros.push({
name: '',
startLineNumbers: [],
endLineNumber: lineIndex + 1,
parentMacro: '',
hasMacroNameInMend: false,
mismatchedMendMacroName: '',
declarationLines: [],
terminationLine: line,
declaration: '',
termination: trimmedStatement
});
}
}
});
});
macros.push(...macroStack);
return macros;
};
exports.parseMacros = parseMacros;
//# sourceMappingURL=parseMacros.js.map