diff --git a/background.js b/background.js index 2ef5cc8..7df6155 100644 --- a/background.js +++ b/background.js @@ -1,12 +1,12 @@ -chrome.tabs.onUpdated.addListener(function(tabId, changedInfo, tab){ +chrome.tabs.onUpdated.addListener(function (tabId, changedInfo, tab) { console.log('TAB ID = ' + tabId); - if (changedInfo.status == 'complete') { + if (changedInfo.status === 'complete') { var GITHUB_URL = "github.com"; var tabUrl = tab.url; if (tabUrl.indexOf(GITHUB_URL) > -1) { - var JAVA_SOURCE_REGEX = /^(https?):\/\/(github\.com)\/([\w]+)\/([\S]+)\/blob\/([\w]+)\/(.*)\/(src\/main\/java)\/(.*)\/([\w]+\.java)/; - var result = tabUrl.match(JAVA_SOURCE_REGEX); + var SOURCE_REGEX = /^(https?):\/\/(github\.com)\/([\w]+)\/([\S]+)\/blob\/([\w]+)\/(.*)\/(src\/main\/(?:java|kotlin))\/(.*)\/([\w]+\.(?:java|kt))/; + var result = tabUrl.match(SOURCE_REGEX); if (result) { var len = result.length; console.log(result); @@ -18,11 +18,11 @@ chrome.tabs.onUpdated.addListener(function(tabId, changedInfo, tab){ var modulename = result[6]; // gradle project module name. for example : mobile var sourceCodeFolder = result[7]; // root folder java packages are stored. for example: src/main/java var className = result[len - 1]; + var ext = className.split(".")[1]; var packageNameWithSlashes = result[len - 2]; var packageName = packageNameWithSlashes.replace(/\//g, "."); console.log("Package Name : " + packageName); - console.log("Class Name : " + className); - + console.log("Class Name : " + className); var messagePayload = { task: "activate_class_links", @@ -33,18 +33,17 @@ chrome.tabs.onUpdated.addListener(function(tabId, changedInfo, tab){ branchName: result[5], // current branch. for example: master modulename: result[6], // gradle project module name. for example : mobile sourceCodeFolder: result[7], // root folder java packages are stored. for example: src/main/java - packageName: packageName - } - - /* - https://github.com/NewsInShorts/inshortsapp/blob/master/mobile/src/main/java/com/nis/app/agents/AppAgent.java - Now from a URL like above extract out the current package we are in, for example - Package Name = com.nis.app.agents - Class Name = AppAgent + packageName: packageName, + ext: ext + }; - */ - chrome.tabs.sendMessage(tab.id, messagePayload, - doStuffWithDOM); + /* + https://github.com/NewsInShorts/inshortsapp/blob/master/mobile/src/main/java/com/nis/app/agents/AppAgent.java + Now from a URL like above extract out the current package we are in, for example + Package Name = com.nis.app.agents + Class Name = AppAgent + */ + chrome.tabs.sendMessage(tab.id, messagePayload, doStuffWithDOM); } } @@ -54,16 +53,14 @@ chrome.tabs.onUpdated.addListener(function(tabId, changedInfo, tab){ /* A function creator for callbacks */ function doStuffWithDOM(dataToBeLogged) { - // console.log("I received the following DOM content:\n" + dataToBeLogged); - if (jQuery) { - console.log('Jquery Loaded'); - // jQuery loaded - console.log(dataToBeLogged); - - } else { - // jQuery not loaded - console.log('Jquery Not Loaded Yet'); - } - + // console.log("I received the following DOM content:\n" + dataToBeLogged); + if (jQuery) { + console.log('Jquery Loaded'); + // jQuery loaded + console.log(dataToBeLogged); + } else { + // jQuery not loaded + console.log('Jquery Not Loaded Yet'); + } } diff --git a/content.js b/content.js index 7c378c3..3d9977d 100644 --- a/content.js +++ b/content.js @@ -1,164 +1,182 @@ /* Listen for messages */ -var REGEX_IMPORT = /^(import )/ -var REGEX_PACKAGE_NAME_EXCLUDING_CLASS_NAME = /(.*\.)/ +var REGEX_IMPORT = /^(import )/; +var REGEX_VALID_USAGE_OF_CLASS_NAME = /^(\s+)?[A-Z][\S]+(\(|\.|>|\s|$)/; +var REGEX_PACKAGE_NAME_EXCLUDING_CLASS_NAME = /(.*\.)/; var REGEX_BASE_PACKAGE; // This will help us determine the line from which the actual code begins. var INDEX_OF_LAST_IMPORT_STATEMENT = -1; -var arrayOfBroweseableClasses = new Array(); +var arrayOfBroweseableClasses = []; var PROTOCOL; var DOMAIN; var USER_NAME; var REPOSITORY_NAME; var BRANCH; -var MODULE_NAME; // gadle based projects have modules +var MODULE_NAME; // gradle based projects have modules var SOURCE_FOLDER_ROOT; var ANDROID_REFERENCE_URL_BASE = "https://developer.android.com/reference/"; -chrome.runtime.onMessage.addListener(function(msg, sender, sendResponse) { - /* If the received message has the expected format... */ - if (msg.task && (msg.task == "activate_class_links")) { - PROTOCOL = msg.protocol; - DOMAIN = msg.domain; - USER_NAME = msg.userName; - REPOSITORY_NAME = msg.repositoryName; - BRANCH = msg.branchName; - MODULE_NAME = msg.modulename; - SOURCE_FOLDER_ROOT = msg.sourceCodeFolder; - - var packageNameFolders = msg.packageName.split("."); - - REGEX_BASE_PACKAGE = new RegExp('('+packageNameFolders[0] + '\.' + packageNameFolders[1] + ')'); - - var tableRows = $('div.blob-wrapper tr'); - $(tableRows).each(function(index){ - var sourceCodeLine = $(this).find(':nth-child(2)').text(); - if (itIsAnImportStatement(sourceCodeLine)) { - var packageName = getPackageName(sourceCodeLine); - if (packageBelongsToOurSourceCode(packageName) || packageBelongsToAndroid(packageName)) { - var className = getClassName(packageName); - if (className !== 'R') { - var browseableClass = new BrowseableClass(className, packageName); - arrayOfBroweseableClasses.push(browseableClass); - // console.log(browseableClass.getGithubUrl()); - } - } - - if (INDEX_OF_LAST_IMPORT_STATEMENT < index) { - INDEX_OF_LAST_IMPORT_STATEMENT = index; +String.prototype.replaceBetween = function (start, end, what) { + return this.substring(0, start) + what + this.substring(end); +}; + +chrome.runtime.onMessage.addListener(function (msg) { + /* If the received message has the expected format... */ + if (msg.task && (msg.task === "activate_class_links")) { + PROTOCOL = msg.protocol; + DOMAIN = msg.domain; + USER_NAME = msg.userName; + REPOSITORY_NAME = msg.repositoryName; + BRANCH = msg.branchName; + MODULE_NAME = msg.modulename; + SOURCE_FOLDER_ROOT = msg.sourceCodeFolder; + + var packageNameFolders = msg.packageName.split("."); + + REGEX_BASE_PACKAGE = new RegExp('(' + packageNameFolders[0] + '\.' + packageNameFolders[1] + ')'); + + var tableRows = $('div.blob-wrapper tr'); + $(tableRows).each(function (index) { + var sourceCodeLine = $(this).find(':nth-child(2)').text(); + if (itIsAnImportStatement(sourceCodeLine)) { + var packageName = getPackageName(sourceCodeLine); + if (packageBelongsToOurSourceCode(packageName) || packageBelongsToAndroid(packageName)) { + var className = getClassName(packageName); + if (className !== 'R') { + var browseableClass = new BrowseableClass(className, packageName, msg.ext); + arrayOfBroweseableClasses.push(browseableClass); + // console.log(browseableClass.getGithubUrl()); } } - }); - for (var i=0;i'); - } else if (code.length == arrayOfBroweseableClasses[i].className.length) { - $(el[j]).wrapInner(''); + $(el[j]).wrapInner(''); + } else if (code.length === clazz.className.length) { + $(el[j]).wrapInner(''); } } + } else if (msg.ext === "kt") { + var codeHtml = $(el[j]).html(); + var codeText = $(el[j]).text(); + + /* + Workaround for Kotlin. It gets the first char of a class (first index); it checks if before the class name there's another char, if true skip this line; + it calculates the used length, adding to the first index, the length of class name, plus a special char (like . ( < >). + At the end it checks if the substring matches with a valid usage of class name, so replace it with the URL + */ + var indexHtml = codeHtml.indexOf(clazz.className); + var indexText = codeText.indexOf(clazz.className); + + switch (codeText.charAt(indexText - 1)) { + case "<": + case ">": + case " ": + case "(": + break; + default: + continue; + } + + var classUsage = indexHtml + clazz.className.length + 1; + if (codeHtml.charAt(classUsage - 1) >= 'A' || 'Z' <= codeHtml.charAt(classUsage - 1)) continue; + + var result = codeHtml.substr(indexHtml, classUsage).match(REGEX_VALID_USAGE_OF_CLASS_NAME); + + if (result) { + $(el[j]).html(codeHtml.replaceBetween(indexHtml, classUsage - 1, '' + clazz.className + '')); + } } } - } + + } }); /** -* Checks if this line of code is an import statement. -* @param {String} lineOfCode -* @return (Boolean) true if it is an import statement and false otherwise -*/ + * Checks if this line of code is an import statement. + * @param {String} lineOfCode + * @return (Boolean) true if it is an import statement and false otherwise + */ function itIsAnImportStatement(lineOfCode) { - var result = lineOfCode.match(REGEX_IMPORT); - if (result) { - return true; - } else { - return false; - } - + return !!result; } /** -* Checks if this package lies in our source code or not, by checking the first -* two folder names in the package. Like if com.ishankhanna.example.app is the -* is a package to be tested if it belongs to us or not, we will check if -* com.ishankhanna.example is there in this package name or not. -* @param {String} packageNameToBeValidated -* @returns {Boolean} true if it belongs to our source code and false otherwise -*/ + * Checks if this package lies in our source code or not, by checking the first + * two folder names in the package. Like if com.ishankhanna.example.app is the + * is a package to be tested if it belongs to us or not, we will check if + * com.ishankhanna.example is there in this package name or not. + * @param {String} packageNameToBeValidated + * @returns {Boolean} true if it belongs to our source code and false otherwise + */ function packageBelongsToOurSourceCode(packageNameToBeValidated) { - - var result = packageNameToBeValidated.match(REGEX_BASE_PACKAGE) - if (result) { - return true; - } else { - return false; - } - + return !!packageNameToBeValidated.match(REGEX_BASE_PACKAGE); } /** -* Checks if the package belongs to android - simply checks if it starts with "android.*" -*/ + * Checks if the package belongs to android - simply checks if it starts with "android.*" + */ function packageBelongsToAndroid(packageNameToBeValidated) { - - if (packageNameToBeValidated.startsWith("android.")) { - return true; - } else { - return false; - } - + return packageNameToBeValidated.startsWith("android."); } /** -* Extracts the package name from the import statement of the source code. -* @param {String} importStatement -* @return {String} packageName -*/ + * Extracts the package name from the import statement of the source code. + * @param {String} importStatement + * @return {String} packageName + */ function getPackageName(importStatement) { // TODO : Figure out why the hell are we doing this split twice. var codes = importStatement.split(" "); - var packageName = codes[1].split(";")[0]; - return packageName; + return codes[1].split(";")[0]; } /** -* Extracts the class name from the package name. -* @param {String} packageName -* @return {String} className -*/ + * Extracts the class name from the package name. + * @param {String} packageName + * @return {String} className + */ function getClassName(packageName) { var elementsOfPackageName = packageName.split("."); - var className = elementsOfPackageName[elementsOfPackageName.length-1]; - return className; + return elementsOfPackageName[elementsOfPackageName.length - 1]; } -function BrowseableClass(className, packageName) { +function BrowseableClass(className, packageName, ext) { this.className = className; this.packageName = packageName; + this.ext = ext; } -BrowseableClass.prototype.getLinkedUrl = function() { - - if(packageBelongsToAndroid(this.packageName)) { - var packageNameWithSlashes = this.packageName.replace(/\./g, "\/"); - return ANDROID_REFERENCE_URL_BASE+packageNameWithSlashes+".html"; - } else if(packageBelongsToOurSourceCode(this.packageName)) { - var result = this.packageName.match(REGEX_PACKAGE_NAME_EXCLUDING_CLASS_NAME); - var packageNameWithSlashes = result[0].replace(/\./g, "\/"); - return PROTOCOL + "://" + DOMAIN + "/" + USER_NAME + "/" + REPOSITORY_NAME + - "/blob/" + BRANCH + "/" + MODULE_NAME + "/" + SOURCE_FOLDER_ROOT + "/" - + packageNameWithSlashes + this.className + '.java'; +BrowseableClass.prototype.getLinkedUrl = function () { + if (packageBelongsToAndroid(this.packageName)) { + var packageNameWithSlashes = this.packageName.replace(/\./g, "\/"); + return ANDROID_REFERENCE_URL_BASE + packageNameWithSlashes + ".html"; + } else if (packageBelongsToOurSourceCode(this.packageName)) { + var result = this.packageName.match(REGEX_PACKAGE_NAME_EXCLUDING_CLASS_NAME); + var packageNameWithSlashes = result[0].replace(/\./g, "\/"); + return PROTOCOL + "://" + DOMAIN + "/" + USER_NAME + "/" + REPOSITORY_NAME + + "/blob/" + BRANCH + "/" + MODULE_NAME + "/" + SOURCE_FOLDER_ROOT + "/" + + packageNameWithSlashes + this.className + "." + this.ext; } -} - -var REGEX_VALID_USAGE_OF_CLASS_NAME = /^(\s+)?[A-Z]{1}[\S]+(\(|\.|>|\s|$)/; +}; \ No newline at end of file