Github JSON Dependencies Linker

Linkify all dependencies found in an JSON file.

  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. // cSpell:ignore linkify, Sindre Sorhus
  25. /* eslint security/detect-object-injection: "off" */
  26.  
  27. (function () {
  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 =
  40. location.pathname.endsWith("/package.json") ||
  41. location.pathname.endsWith("/npm-shrinkwrap.json"),
  42. isBower = location.pathname.endsWith("/bower.json"),
  43. isNuGet = location.pathname.endsWith("/project.json"),
  44. isAtom = (function () {
  45. if (location.pathname.endsWith("/package.json")) {
  46. if (pkg.atomShellVersion) {
  47. return true;
  48. } else if (pkg.engines && pkg.engines.atom) {
  49. return true;
  50. }
  51. }
  52. return false;
  53. })(),
  54. dependencyKeys = [
  55. "dependencies",
  56. "devDependencies",
  57. "peerDependencies",
  58. "bundleDependencies",
  59. "bundledDependencies",
  60. "packageDependencies",
  61. "optionalDependencies",
  62. ],
  63. modules = (function () {
  64. var _modules = {};
  65. dependencyKeys.forEach(function (dependencyKey) {
  66. _modules[dependencyKey] = [];
  67. });
  68. return _modules;
  69. })();
  70.  
  71. // Get an unique list of all modules.
  72. function fetchModules(root) {
  73. dependencyKeys.forEach(function (dependencyKey) {
  74. var dependencies = root[dependencyKey] || {};
  75. Object.keys(dependencies).forEach(function (module) {
  76. if (modules[dependencyKey].indexOf(module) === -1) {
  77. modules[dependencyKey].push(module);
  78. }
  79. fetchModules(dependencies[module]);
  80. });
  81. });
  82. }
  83. fetchModules(pkg);
  84.  
  85. // Linkify module.
  86. function linkify(module, url) {
  87. // Try to find the module; could be multiple locations.
  88. var moduleFilterText = '"' + module + '"';
  89. var moduleElms = Array.prototype.filter.call(
  90. blobLineElms,
  91. function (blobLineElm) {
  92. if (blobLineElm.textContent.trim() === moduleFilterText) {
  93. // Module name preceding a colon is never a key.
  94. var prev = blobLineElm.previousSibling;
  95. return !(prev && prev.textContent.trim() === ":");
  96. }
  97. return false;
  98. },
  99. );
  100.  
  101. // Modules could exist in multiple dependency lists.
  102. Array.prototype.forEach.call(moduleElms, function (moduleElm) {
  103. // Module names are textNodes on Github.
  104. var moduleElmText = Array.prototype.find.call(
  105. moduleElm.childNodes,
  106. function (moduleElmChild) {
  107. return moduleElmChild.nodeType === 3;
  108. },
  109. );
  110.  
  111. var moduleElmLink = document.createElement("a");
  112. moduleElmLink.setAttribute("href", url);
  113. moduleElmLink.appendChild(document.createTextNode(module));
  114.  
  115. // Replace textNode, so we keep surrounding elements (like the highlighted quotes).
  116. moduleElm.replaceChild(moduleElmLink, moduleElmText);
  117. });
  118. }
  119.  
  120. /*!
  121. strip-json-comments
  122. Strip comments from JSON. Lets you use comments in your JSON files!
  123. https://github.com/sindresorhus/strip-json-comments
  124. by Sindre Sorhus
  125. MIT License
  126. */
  127. function stripJsonComments(str) {
  128. var currentChar;
  129. var nextChar;
  130. var insideString = false;
  131. var insideComment = false;
  132. var ret = "";
  133. for (var i = 0; i < str.length; i++) {
  134. currentChar = str[i];
  135. nextChar = str[i + 1];
  136. if (!insideComment && str[i - 1] !== "\\" && currentChar === '"') {
  137. insideString = !insideString;
  138. }
  139. if (insideString) {
  140. ret += currentChar;
  141. continue;
  142. }
  143. if (!insideComment && currentChar + nextChar === "//") {
  144. insideComment = "single";
  145. i++;
  146. } else if (
  147. insideComment === "single" &&
  148. currentChar + nextChar === "\r\n"
  149. ) {
  150. insideComment = false;
  151. i++;
  152. ret += currentChar;
  153. ret += nextChar;
  154. continue;
  155. } else if (insideComment === "single" && currentChar === "\n") {
  156. insideComment = false;
  157. } else if (!insideComment && currentChar + nextChar === "/*") {
  158. insideComment = "multi";
  159. i++;
  160. continue;
  161. } else if (
  162. insideComment === "multi" &&
  163. currentChar + nextChar === "*/"
  164. ) {
  165. insideComment = false;
  166. i++;
  167. continue;
  168. }
  169. if (insideComment) {
  170. continue;
  171. }
  172. ret += currentChar;
  173. }
  174. return ret;
  175. }
  176.  
  177. // Init.
  178. Object.keys(modules).forEach(function (dependencyKey) {
  179. modules[dependencyKey].forEach(function (module) {
  180. if (isAtom && dependencyKey === "packageDependencies") {
  181. // Atom needs to be before NPM.
  182. let url = "https://atom.io/packages/" + module;
  183. linkify(module, url);
  184. } else if (isNPM) {
  185. let url = "https://www.npmjs.org/package/" + module;
  186. linkify(module, url);
  187. } else if (isBower) {
  188. GM_xmlhttpRequest({
  189. method: "GET",
  190. url: "http://bower.herokuapp.com/packages/" + module,
  191. onload: function (response) {
  192. var data = JSON.parse(response.responseText);
  193. var re = /github\.com\/([\w\-.]+)\/([\w\-.]+)/i;
  194. var parsedUrl = re.exec(data.url.replace(/\.git$/, ""));
  195. if (parsedUrl) {
  196. var user = parsedUrl[1];
  197. var repo = parsedUrl[2];
  198. var url = "https://github.com/" + user + "/" + repo;
  199. linkify(module, url);
  200. } else {
  201. linkify(module, data.url);
  202. }
  203. },
  204. });
  205. } else if (isNuGet) {
  206. var url = "https://www.nuget.org/packages/" + module;
  207. linkify(module, url);
  208. }
  209. });
  210. });
  211. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址