Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 5 additions & 49 deletions src/apexParsing/apexParser.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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;
35 changes: 10 additions & 25 deletions src/apexmodels/apexModel.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
const StringUtils = require('../utils/stringUtils');
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Within this repo we're using the file extension in the require path. It's a mild stylistic issue and we don't have a style guide.


class ApexModel {
constructor(accessModifiers) {
this.accessModifiers = accessModifiers;
this.stringUtils = new StringUtils();
}

getNameLine() {
Expand All @@ -18,82 +21,64 @@ class ApexModel {
}

getDescription() {
return this.getValueOrEmptyString(this.description);
return this.stringUtils.getValueOrEmptyString(this.description);
}

setDescription(description) {
this.description = description;
}

getAuthor() {
return this.getValueOrEmptyString(this.author);
return this.stringUtils.getValueOrEmptyString(this.author);
}

setAuthor(author) {
this.author = author;
}

getDate() {
return this.getValueOrEmptyString(this.date);
return this.stringUtils.getValueOrEmptyString(this.date);
}

setDate(date) {
this.date = date;
}

getReturns() {
return this.getValueOrEmptyString(this.returns);
return this.stringUtils.getValueOrEmptyString(this.returns);
}

setReturns(returns) {
this.returns = returns;
}

getExample() {
return this.getValueOrEmptyString(this.example);
return this.stringUtils.getValueOrEmptyString(this.example);
}

setExample(example) {
this.example = example;
}

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;
28 changes: 1 addition & 27 deletions src/apexmodels/methodModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
76 changes: 76 additions & 0 deletions src/utils/stringUtils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
class StringUtils {

/**
* @summary
* Returns an empty string if its a null-ish value, otherwise returns
* the original string.
Comment on lines +4 to +6
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The description is a good thing to have. This does not follow the same-line example indicated in JS Doc for @summary

*
* @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;