diff --git a/src/apexParsing/apexParser.js b/src/apexParsing/apexParser.js index 3327cf7..63e33fc 100644 --- a/src/apexParsing/apexParser.js +++ b/src/apexParsing/apexParser.js @@ -3,11 +3,13 @@ const fs = require('fs'); const ClassModel = require('../apexmodels/classModel.js'); const MethodModel = require('../apexmodels/methodModel.js'); const PropertyModel = require('../apexmodels/propertyModel.js'); +const StringUtils = require('../utils/stringUtils'); class ApexParser { constructor(accessModifiers,sourceDirectory) { this.accessModifiers = accessModifiers; this.sourceDirectory = sourceDirectory; + this.stringUtils = new StringUtils(); } parseFileContents(filePath) { @@ -93,8 +95,8 @@ class ApexParser { } // keep track of our nesting so we know which class we are in - let openCurlies = this.countChars(strLine, '{'); - let closeCurlies = this.countChars(strLine, '}'); + let openCurlies = this.stringUtils.countChars(strLine, '{'); + let closeCurlies = this.stringUtils.countChars(strLine, '}'); nestedCurlyBraceDepth += openCurlies; nestedCurlyBraceDepth -= closeCurlies; @@ -123,7 +125,7 @@ class ApexParser { } // ignore lines not dealing with scope - if (!this.strContainsScope(strLine) && + if (!this.stringUtils.getMatchingSubstring(strLine, this.accessModifiers) && // interface methods don't have scope !(cModel && cModel.getIsInterface() @@ -416,52 +418,6 @@ class ApexParser { } }); } - - strPrevWord(str, iSearch) { - if (!str || iSearch >= str.length) { - return null; - } - - let iStart; - let iEnd = 0; - for (iStart = iSearch - 1; iStart >= 0; iStart--) { - if (iEnd === 0) { - if (str.charAt(iStart) === ' ') { - continue; - } - iEnd = iStart + 1; - } else if (str.charAt(iStart) === ' ') { - iStart++; - break; - } - } - - if (iStart === -1) { - return null; - } else { - return str.substring(iStart, iEnd); - } - } - - countChars(str, ch) { - let count = 0; - for (let i = 0; i < str.length; ++i) { - if (str.charAt(i) === ch) { - ++count; - } - } - return count; - } - - strContainsScope(str) { - str = str.toLowerCase(); - for (let i = 0; i < this.accessModifiers.length; i++) { - if (str.toLowerCase().includes(this.accessModifiers[i].toLowerCase() + " ")) { - return this.accessModifiers[i]; - } - } - return null; - } } module.exports = ApexParser; \ No newline at end of file diff --git a/src/apexmodels/apexModel.js b/src/apexmodels/apexModel.js index 69c95b0..4519a30 100644 --- a/src/apexmodels/apexModel.js +++ b/src/apexmodels/apexModel.js @@ -1,6 +1,9 @@ +const StringUtils = require('../utils/stringUtils'); + class ApexModel { constructor(accessModifiers) { this.accessModifiers = accessModifiers; + this.stringUtils = new StringUtils(); } getNameLine() { @@ -18,7 +21,7 @@ class ApexModel { } getDescription() { - return this.getValueOrEmptyString(this.description); + return this.stringUtils.getValueOrEmptyString(this.description); } setDescription(description) { @@ -26,7 +29,7 @@ class ApexModel { } getAuthor() { - return this.getValueOrEmptyString(this.author); + return this.stringUtils.getValueOrEmptyString(this.author); } setAuthor(author) { @@ -34,7 +37,7 @@ class ApexModel { } getDate() { - return this.getValueOrEmptyString(this.date); + return this.stringUtils.getValueOrEmptyString(this.date); } setDate(date) { @@ -42,7 +45,7 @@ class ApexModel { } getReturns() { - return this.getValueOrEmptyString(this.returns); + return this.stringUtils.getValueOrEmptyString(this.returns); } setReturns(returns) { @@ -50,7 +53,7 @@ class ApexModel { } getExample() { - return this.getValueOrEmptyString(this.example); + return this.stringUtils.getValueOrEmptyString(this.example); } setExample(example) { @@ -58,42 +61,24 @@ class ApexModel { } getScope() { - return this.getValueOrEmptyString(this.scope); + return this.stringUtils.getValueOrEmptyString(this.scope); } setScope(scope) { this.scope = scope; } - getValueOrEmptyString(value) { - if(!value) { - return ''; - } - - return value; - } - parseScope() { this.scope = null; if(this.nameLine) { - let str = this.strContainsScope(this.nameLine); + let str = this.stringUtils.getMatchingSubstring(this.nameLine, this.accessModifiers); if (str) { this.scope = str; } this.scope = this.nameLine; } } - - strContainsScope(str) { - str = str.toLowerCase(); - for (let i = 0; i < this.accessModifiers.length; i++) { - if (str.toLowerCase().includes(this.accessModifiers[i].toLowerCase() + " ")) { - return this.accessModifiers[i]; - } - } - return null; - } } module.exports = ApexModel; \ No newline at end of file diff --git a/src/apexmodels/methodModel.js b/src/apexmodels/methodModel.js index a96594c..1ec66e9 100644 --- a/src/apexmodels/methodModel.js +++ b/src/apexmodels/methodModel.js @@ -39,38 +39,12 @@ class MethodModel extends ApexModel { if (nameLine && nameLine.length > 0) { const lastindex = nameLine.indexOf("("); if (lastindex >= 0) { - const methodName = this.strPrevWord(nameLine, lastindex); + const methodName = this.stringUtils.getPrevWord(nameLine, lastindex); return methodName; } } return ""; } - - strPrevWord(str, iSearch) { - if (!str || iSearch >= str.length) { - return null; - } - - let iStart; - let iEnd = 0; - for (iStart = iSearch - 1; iStart >= 0; iStart--) { - if (iEnd === 0) { - if (str.charAt(iStart) === ' ') { - continue; - } - iEnd = iStart + 1; - } else if (str.charAt(iStart) === ' ') { - iStart++; - break; - } - } - - if (iStart === -1) { - return null; - } else { - return str.substring(iStart, iEnd); - } - } } module.exports = MethodModel; \ No newline at end of file diff --git a/src/utils/stringUtils.js b/src/utils/stringUtils.js new file mode 100644 index 0000000..e45293b --- /dev/null +++ b/src/utils/stringUtils.js @@ -0,0 +1,76 @@ +class StringUtils { + + /** + * @summary + * Returns an empty string if its a null-ish value, otherwise returns + * the original string. + * + * @param {string} str + */ + getValueOrEmptyString(str) { + return str ? str : ''; + } + + /** + * @summary + * Returns the previous word just before a given index in a string. + * + * @param {string} str + * @param {number} iSearch + */ + getPrevWord(str, iSearch) { + if (!str || iSearch >= str.length) return null; + let iStart = 0, iEnd = 0; + for (iStart = iSearch - 1; iStart >= 0; iStart--) { + if (iEnd === 0) { + if (str.charAt(iStart) === ' ') continue; + iEnd = iStart + 1; + } + else if (str.charAt(iStart) === ' ') { + iStart++; + break; + } + } + + return iStart < 0 ? null : str.substring(iStart, iEnd); + } + + /** + * @summary + * Fairly obvious, counts the number of times a character occurs + * in a string. + * + * @param {string} str + * @param {string} ch + */ + countChars(str, ch) { + let count = 0; + for (let i = 0; i < str.length; ++i) { + if (str.charAt(i) === ch) { + ++count; + } + } + return count; + } + + /** + * @summary + * Does a case-insensitive match to check if any of the options exist + * in the original string. It returns the string that exists, if any. + * Otherwise it returns null. + * + * @param {string} str + * @param {string[]} options + */ + getMatchingSubstring(str, options) { + const s = str.toLowerCase(); + for (let i = 0; i < options.length; i++) { + if (s.includes(options[i].toLowerCase() + " ")) { + return options[i]; + } + } + return null; + } +} + +module.exports = StringUtils; \ No newline at end of file