Files
pgadmin4/web/pgadmin/static/js/codemirror/addon/fold/pgadmin-sqlfoldcode.js
Akshay Joshi 9f836f5433 Fixed following code smells reported by SonarQube:
1) Immediately return this expression instead of assigning it to the temporary variable.
 2) Extract this nested ternary operation into an independent statement.
 3) Expected a `for-of` loop instead of a `for` loop with this simple iteration.
2022-01-18 14:49:54 +05:30

134 lines
4.5 KiB
JavaScript

/////////////////////////////////////////////////////////////
//
// pgAdmin 4 - PostgreSQL Tools
//
// Copyright (C) 2013 - 2022, The pgAdmin Development Team
// This software is released under the PostgreSQL Licence
//
//////////////////////////////////////////////////////////////
(function(mod) {
if (typeof exports == 'object' && typeof module == 'object') // CommonJS
mod(require('codemirror'));
else if (typeof define == 'function' && define.amd) // AMD
define(['codemirror'], mod);
else // Plain browser env
mod(window.CodeMirror);
})(function(CodeMirror) {
'use strict';
var pgadminKeywordRangeFinder = function(cm, start, tokenSet) {
var line = start.line,
lineText = cm.getLine(line);
var at = lineText.length,
startChar, tokenType;
let tokenSetNo = 0;
let startTkn = tokenSet[tokenSetNo].start,
endTkn = tokenSet[tokenSetNo].end;
while (at > 0) {
var found = lineText.toUpperCase().lastIndexOf(startTkn, at);
found = checkStartTokenFoundOnEndToken(found, lineText.toUpperCase(), endTkn, startTkn);
var startToken = startTkn;
var endToken = endTkn;
if (found < start.ch) {
/* If the start token is not found then search for the next set of token */
tokenSetNo++;
if(tokenSetNo >= tokenSet.length) {
return undefined;
}
startTkn = tokenSet[tokenSetNo].start;
endTkn = tokenSet[tokenSetNo].end;
at = lineText.length;
continue;
}
tokenType = cm.getTokenAt(CodeMirror.Pos(line, found + 1)).type;
if (!/^(comment|string)/.test(tokenType)) {
startChar = found;
break;
}
at = found - 1;
}
if (startChar == null || lineText.toUpperCase().lastIndexOf(startToken) > startChar) return;
var count = 1,
lastLine = cm.lineCount(),
end, endCh;
outer: for (var i = line + 1; i < lastLine; ++i) {
var text = cm.getLine(i).toUpperCase(),
pos = 0;
var whileloopvar = 0;
while (whileloopvar < 1) {
var nextOpen = text.indexOf(startToken, pos);
nextOpen = checkStartTokenFoundOnEndToken(nextOpen, text, endToken, startToken);
var nextClose = text.indexOf(endToken, pos);
if (nextOpen < 0) nextOpen = text.length;
if (nextClose < 0) nextClose = text.length;
pos = Math.min(nextOpen, nextClose);
if (pos == text.length) { whileloopvar=1; break; }
if (cm.getTokenAt(CodeMirror.Pos(i, pos + 1)).type == tokenType) {
if (pos == nextOpen) ++count;
else if (!--count) {
end = i;
endCh = pos;
break outer;
}
}
++pos;
}
}
if (end == null || end == line + 1) return;
return {
from: CodeMirror.Pos(line, startChar + startTkn.length),
to: CodeMirror.Pos(end, endCh),
};
};
/**
* This function is responsible for finding whether the startToken is present
* in the endToken as well, to avoid mismatch of start and end points.
* e.g. In case of IF and END IF, IF is detected in both tokens, which creates
* confusion. The said function will resolve such issues.
* @function checkStartTokenFoundOnEndToken
* @returns {Number} - returns found
*/
function checkStartTokenFoundOnEndToken(found, text, endToken, startToken) {
if(found > 0) {
if(text.includes(endToken)
|| !checkTokenMixedWithOtherAlphabets(text, startToken)) {
found = -1;
}
}
return found;
}
/**
* This function is responsible for finding whether the startToken is mixed
* with other alphabets of the text. To avoid word like NOTIFY to be mistakenly treat as keyword.
* e.g. to avoid the IF detected as keyword in the word NOTIFY.
* Function also works with other tokens like LOOP, CASE, etc.
* @function checkTokenMixedWithOtherAlphabets
* @returns {Boolean} - returns true/false
*/
function checkTokenMixedWithOtherAlphabets(text, startToken) {
//this reg will check the token should be in format as - IF condition or IF(condition)
let reg = `\\b\\${startToken}\\s*\\(\\w*\\)(?!\\w)|\\b\\${startToken}\\(\\w*\\)(?!\\w)|\\b\\${startToken}\\s*(?!\\w)`;
let regex = RegExp(reg, 'g');
if(regex.exec(text) !== null) {
return true;
}
return false;
}
CodeMirror.registerHelper('fold', 'sql', function(cm, start) {
return pgadminKeywordRangeFinder(cm, start, [
{start: 'BEGIN', end:'END;'},
{start: 'IF', end:'END IF'},
{start: 'LOOP', end:'END LOOP'},
{start: 'CASE', end:'END CASE'},
]);
});
});