GitHub First Commit

Add a link to a GitHub repo's first commit

2024-11-29 يوللانغان نەشرى. ئەڭ يېڭى نەشرىنى كۆرۈش.

  1. // ==UserScript==
  2. // @name GitHub First Commit
  3. // @description Add a link to a GitHub repo's first commit
  4. // @author chocolateboy
  5. // @copyright chocolateboy
  6. // @version 4.0.3
  7. // @namespace https://github.com/chocolateboy/userscripts
  8. // @license GPL
  9. // @include https://github.com/
  10. // @include https://github.com/*
  11. // @grant GM_log
  12. // @noframes
  13. // ==/UserScript==
  14.  
  15. // NOTE This file is generated from src/github-first-commit.user.ts and should not be edited directly.
  16.  
  17. "use strict";
  18. (() => {
  19. // src/lib/util.ts
  20. var constant = (value) => (..._args) => value;
  21.  
  22. // src/lib/observer.ts
  23. var INIT = { childList: true, subtree: true };
  24. var done = constant(false);
  25. var resume = constant(true);
  26. var observe = (...args) => {
  27. const $2 = document;
  28. const [target, init, callback] = args.length === 3 ? args : args.length === 2 ? args[0] instanceof Element ? [args[0], INIT, args[1]] : [$2.body, args[0], args[1]] : [$2.body, INIT, args[0]];
  29. const $callback = (mutations, observer2) => {
  30. observer2.disconnect();
  31. const resume2 = callback({ mutations, observer: observer2, target, init });
  32. if (resume2 !== false) {
  33. observer2.observe(target, init);
  34. }
  35. };
  36. const observer = new MutationObserver($callback);
  37. queueMicrotask(() => $callback([], observer));
  38. return observer;
  39. };
  40.  
  41. // src/github-first-commit.user.ts
  42. // @license GPL
  43. var ID = "first-commit";
  44. var PATH = 'meta[name="analytics-location"][content]';
  45. var REPO_PAGE = "/<user-name>/<repo-name>";
  46. var USER_REPO = 'meta[name="octolytics-dimension-repository_network_root_nwo"][content]';
  47. var $ = document;
  48. var openFirstCommit = (user, repo) => {
  49. return fetch(`https://api.github.com/repos/${user}/${repo}/commits`).then((res) => Promise.all([res.headers.get("link"), res.json()])).then(([link, commits]) => {
  50. if (!link) {
  51. return commits;
  52. }
  53. const lastPage = link.match(/^.+?<([^>]+)>;/)[1];
  54. return fetch(lastPage).then((res) => res.json());
  55. }).then((commits) => {
  56. if (Array.isArray(commits)) {
  57. location.href = commits.at(-1).html_url;
  58. } else {
  59. console.error(commits);
  60. }
  61. });
  62. };
  63. observe(() => {
  64. const path = $.querySelector(PATH)?.content;
  65. if (path !== REPO_PAGE) {
  66. return;
  67. }
  68. if ($.getElementById(ID)) {
  69. return;
  70. }
  71. const commitHistory = $.querySelector("div svg.octicon-history")?.closest("div");
  72. if (!commitHistory) {
  73. return;
  74. }
  75. const firstCommit = commitHistory.cloneNode(true);
  76. const label = firstCommit.querySelector(':scope [data-component="text"] > *');
  77. const header = firstCommit.querySelector(":scope h2");
  78. const link = firstCommit.querySelector(":scope a[href]");
  79. const [user, repo] = $.querySelector(USER_REPO).getAttribute("content").split("/");
  80. firstCommit.id = ID;
  81. header.textContent = label.textContent = "1st Commit";
  82. link.removeAttribute("href");
  83. link.setAttribute("aria-label", "First commit");
  84. const onClick = (e) => {
  85. e.preventDefault();
  86. e.stopPropagation();
  87. label.textContent = "Loading...";
  88. openFirstCommit(user, repo);
  89. };
  90. firstCommit.addEventListener("click", onClick, { once: true });
  91. commitHistory.after(firstCommit);
  92. });
  93. })();