Github JSON Dependencies Linker

Linkify all dependencies found in an JSON file.

As of 2015-03-25. See the latest version.

  1. // ==UserScript==
  2. // @id Github_JSON_Dependencies_Linker@https://github.com/jerone/UserScripts
  3. // @name Github JSON Dependencies Linker
  4. // @namespace https://github.com/jerone/UserScripts
  5. // @description Linkify all dependencies found in an JSON file.
  6. // @author jerone
  7. // @copyright 2015+, jerone (http://jeroenvanwarmerdam.nl)
  8. // @license GNU GPLv3
  9. // @homepage https://github.com/jerone/UserScripts/tree/master/Github_JSON_Dependencies_Linker
  10. // @homepageURL https://github.com/jerone/UserScripts/tree/master/Github_JSON_Dependencies_Linker
  11. // @supportURL https://github.com/jerone/UserScripts/issues
  12. // @contributionURL https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=VCYMHWQ7ZMBKW
  13. // @version 0.1.0
  14. // @grant GM_xmlhttpRequest
  15. // @run-at document-end
  16. // @include https://github.com/*/package.json
  17. // @include https://github.com/*/bower.json
  18. // @include https://github.com/*/project.json
  19. // ==/UserScript==
  20. /* global GM_xmlhttpRequest */
  21.  
  22. (function() {
  23.  
  24. var isNPM = location.pathname.endsWith('/package.json'),
  25. isBower = location.pathname.endsWith('/bower.json'),
  26. isNuGet = location.pathname.endsWith('/project.json'),
  27. blobElm = document.querySelector('.blob-wrapper'),
  28. blobLineElms = blobElm.querySelectorAll('.blob-code > span'),
  29. pkg = (function() {
  30. // JSON parser could fail on JSON with comments;
  31. try {
  32. return JSON.parse(blobElm.textContent);
  33. } catch (ex) {
  34. function stripJsonComments(str) {
  35. /*!
  36. strip-json-comments
  37. Strip comments from JSON. Lets you use comments in your JSON files!
  38. https://github.com/sindresorhus/strip-json-comments
  39. by Sindre Sorhus
  40. MIT License
  41. */
  42. var currentChar;
  43. var nextChar;
  44. var insideString = false;
  45. var insideComment = false;
  46. var ret = '';
  47. for (var i = 0; i < str.length; i++) {
  48. currentChar = str[i];
  49. nextChar = str[i + 1];
  50. if (!insideComment && str[i - 1] !== '\\' && currentChar === '"') {
  51. insideString = !insideString;
  52. }
  53. if (insideString) {
  54. ret += currentChar;
  55. continue;
  56. }
  57. if (!insideComment && currentChar + nextChar === '//') {
  58. insideComment = 'single';
  59. i++;
  60. } else if (insideComment === 'single' && currentChar + nextChar === '\r\n') {
  61. insideComment = false;
  62. i++;
  63. ret += currentChar;
  64. ret += nextChar;
  65. continue;
  66. } else if (insideComment === 'single' && currentChar === '\n') {
  67. insideComment = false;
  68. } else if (!insideComment && currentChar + nextChar === '/*') {
  69. insideComment = 'multi';
  70. i++;
  71. continue;
  72. } else if (insideComment === 'multi' && currentChar + nextChar === '*/') {
  73. insideComment = false;
  74. i++;
  75. continue;
  76. }
  77. if (insideComment) {
  78. continue;
  79. }
  80. ret += currentChar;
  81. }
  82. return ret;
  83. }
  84. // Strip out comments from the JSON and try again;
  85. return JSON.parse(stripJsonComments(blobElm.textContent));
  86. }
  87. })(),
  88. dependencyKeys = [
  89. 'dependencies',
  90. 'devDependencies',
  91. 'peerDependencies',
  92. 'bundleDependencies',
  93. 'bundledDependencies',
  94. 'optionalDependencies'
  95. ],
  96. modules = [];
  97.  
  98. // Get an unique list of all modules;
  99. dependencyKeys.forEach(function(dependencyKey) {
  100. var dependencies = pkg[dependencyKey] || {};
  101. Object.keys(dependencies).forEach(function(module) {
  102. if (modules.indexOf(module) === -1) {
  103. modules.push(module);
  104. }
  105. });
  106. });
  107.  
  108. // Get url depending on json type;
  109. var getUrl = (function() {
  110. if (isNPM) {
  111. return function(module) {
  112. var url = 'https://www.npmjs.org/package/' + module;
  113. linkify(module, url);
  114. };
  115. } else if (isBower) {
  116. return function(module) {
  117. GM_xmlhttpRequest({
  118. method: 'GET',
  119. url: 'http://bower.herokuapp.com/packages/' + module,
  120. onload: function(response) {
  121. var data = JSON.parse(response.responseText);
  122. var re = /github\.com\/([\w\-\.]+)\/([\w\-\.]+)/i;
  123. var parsedUrl = re.exec(data.url.replace(/\.git$/, ''));
  124. if (parsedUrl) {
  125. var user = parsedUrl[1];
  126. var repo = parsedUrl[2];
  127. var url = 'https://github.com/' + user + '/' + repo;
  128. linkify(module, url);
  129. } else {
  130. linkify(module, data.url);
  131. }
  132. }
  133. });
  134. };
  135. } else if (isNuGet) {
  136. return function(module) {
  137. var url = 'https://www.nuget.org/packages/' + module;
  138. linkify(module, url);
  139. };
  140. }
  141. })();
  142.  
  143. // Linkify module;
  144. function linkify(module, url) {
  145.  
  146. // Try to find the module; could be mulitple locations;
  147. var moduleFilterText = '"' + module + '"';
  148. var moduleElms = Array.prototype.filter.call(blobLineElms, function(blobLineElm) {
  149. return blobLineElm.textContent.trim() === moduleFilterText;
  150. });
  151.  
  152. // Modules could exist in multiple dependency lists;
  153. Array.prototype.forEach.call(moduleElms, function(moduleElm) {
  154.  
  155. // Module names are textNodes on Github;
  156. var moduleElmText = Array.prototype.find.call(moduleElm.childNodes, function(moduleElmChild) {
  157. return moduleElmChild.nodeType === 3;
  158. });
  159.  
  160. var moduleElmLink = document.createElement('a');
  161. moduleElmLink.setAttribute('href', url);
  162. moduleElmLink.appendChild(document.createTextNode(module));
  163.  
  164. // Replace textNode, so we keep surrounding elements (like the highlighted quotes);
  165. moduleElm.replaceChild(moduleElmLink, moduleElmText);
  166. });
  167. }
  168.  
  169. // Init;
  170. modules.forEach(function(module) {
  171. getUrl(module);
  172. });
  173.  
  174. })();