Github JSON Dependencies Linker

Linkify all dependencies found in an JSON file.

目前为 2024-02-01 提交的版本。查看 最新版本

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