Github JSON Dependencies Linker

Linkify all dependencies found in an JSON file.

目前为 2015-03-28 提交的版本。查看 最新版本

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