├── .editorconfig
├── .gitattributes
├── .github
├── funding.yml
└── workflows
│ ├── main.yml
│ └── npm-publish.yml
├── .gitignore
├── .npmrc
├── __snapshots__
└── index.test.js.snap
├── index.d.ts
├── index.js
├── index.test-d.ts
├── index.test.js
├── license
├── package.json
├── readme.md
└── tsconfig.json
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = tab
5 | end_of_line = lf
6 | charset = utf-8
7 | trim_trailing_whitespace = true
8 | insert_final_newline = true
9 |
10 | [{package.json,*.yml}]
11 | indent_style = space
12 | indent_size = 2
13 |
14 | [*.md]
15 | trim_trailing_whitespace = false
16 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
2 |
--------------------------------------------------------------------------------
/.github/funding.yml:
--------------------------------------------------------------------------------
1 | github: fregante
2 | custom: [paypal.me/fregante, www.buymeacoffee.com/fregante]
3 |
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | - pull_request
5 | - push
6 |
7 | jobs:
8 | Lint:
9 | runs-on: ubuntu-latest
10 | steps:
11 | - uses: actions/checkout@v4
12 | - uses: actions/setup-node@v4
13 | with:
14 | node-version-file: package.json
15 | - run: npm install
16 | - run: npx xo
17 |
18 | Types:
19 | runs-on: ubuntu-latest
20 | steps:
21 | - uses: actions/checkout@v4
22 | - uses: actions/setup-node@v4
23 | with:
24 | node-version-file: package.json
25 | - run: npm install
26 | - run: npx tsd
27 |
28 | Test:
29 | runs-on: ubuntu-latest
30 | steps:
31 | - uses: actions/checkout@v4
32 | - uses: actions/setup-node@v4
33 | with:
34 | node-version-file: package.json
35 | - run: npm install
36 | - run: npx vitest
37 |
--------------------------------------------------------------------------------
/.github/workflows/npm-publish.yml:
--------------------------------------------------------------------------------
1 | env: {}
2 |
3 | # FILE GENERATED WITH: npx ghat fregante/ghatemplates/npm-publish
4 | # SOURCE: https://github.com/fregante/ghatemplates
5 |
6 | # Collaborators can publish a new version of what's on master via "workflow_dispatch"
7 | # https://github.blog/changelog/2020-07-06-github-actions-manual-triggers-with-workflow_dispatch/
8 |
9 | name: Publish
10 |
11 | on:
12 | workflow_dispatch:
13 | inputs:
14 | Version:
15 | description: 'Version accepted by `npm version *`'
16 | required: true
17 |
18 | jobs:
19 | NPM:
20 | runs-on: ubuntu-latest
21 |
22 | # https://docs.npmjs.com/generating-provenance-statements#example-github-actions-workflow
23 | permissions:
24 | contents: write
25 | id-token: write
26 |
27 | steps:
28 | - uses: actions/checkout@v4
29 | - uses: actions/setup-node@v4
30 | with:
31 | node-version-file: package.json
32 | registry-url: https://registry.npmjs.org
33 | - run: npm ci || npm install
34 | - uses: fregante/setup-git-user@v2
35 | - name: Create version
36 | # Get the generated version, this enables support for keywords: `npm version patch`
37 | run: |
38 | VERSION="$(npm version "${{ github.event.inputs.Version }}")"
39 | echo "VERSION=$VERSION" >> $GITHUB_ENV
40 | - run: npm publish --provenance
41 | env:
42 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
43 | - run: git push --follow-tags
44 | - run: gh release create "$VERSION" --generate-notes
45 | env:
46 | GH_TOKEN: ${{ github.token }}
47 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .DS_Store
3 | Desktop.ini
4 | ._*
5 | Thumbs.db
6 | *.tmp
7 | *.bak
8 | *.log
9 | *.lock
10 | logs
11 | package-lock.json
12 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | package-lock=false
2 |
--------------------------------------------------------------------------------
/__snapshots__/index.test.js.snap:
--------------------------------------------------------------------------------
1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2 |
3 | exports[`http://www.google.com/ 1`] = `http://www.google.com`;
4 |
5 | exports[`https://cdn.rawgit.com/fregante/shorten-repo-url/d71718db/.gitignore 1`] = `d71718db
/.gitignore (raw)`;
6 |
7 | exports[`https://cdn.rawgit.com/fregante/shorten-repo-url/v0.12/.gitignore 1`] = `v0.12
/.gitignore (raw)`;
8 |
9 | exports[`https://cdn.rawgit.com/nodejs/node/d71718db/.gitignore 1`] = `nodejs/node@d71718db
/.gitignore (raw)`;
10 |
11 | exports[`https://cdn.rawgit.com/nodejs/node/v0.12/.gitignore 1`] = `nodejs/node@v0.12
/.gitignore (raw)`;
12 |
13 | exports[`https://developer.mozilla.org/en-US/docs/Web/API/Document/createElement#parameters 1`] = `developer.mozilla.org/en-US/docs/Web/API/Document/createElement#parameters`;
14 |
15 | exports[`https://example.com/nodejs/node/blob/cc8fc46/.gitignore 1`] = `example.com/nodejs/node/blob/cc8fc46/.gitignore`;
16 |
17 | exports[`https://example.site/한글로-된-URL 1`] = `example.site/한글로-된-URL`;
18 |
19 | exports[`https://github.com 1`] = `github.com`;
20 |
21 | exports[`https://github.com/ 1`] = `github.com`;
22 |
23 | exports[`https://github.com/bfred-it/shorten-repo-url/network/dependencies 1`] = `bfred-it/shorten-repo-url (dependencies)`;
24 |
25 | exports[`https://github.com/bfred-it/shorten-repo-url/network/dependents 1`] = `bfred-it/shorten-repo-url (dependents)`;
26 |
27 | exports[`https://github.com/bfred-it/shorten-repo-url/wiki 1`] = `bfred-it/shorten-repo-url/wiki`;
28 |
29 | exports[`https://github.com/features 1`] = `github.com/features`;
30 |
31 | exports[`https://github.com/fregante/shorten-repo-url/ 1`] = `fregante/shorten-repo-url`;
32 |
33 | exports[`https://github.com/fregante/shorten-repo-url/?tab=readme-ov-file 1`] = `fregante/shorten-repo-url`;
34 |
35 | exports[`https://github.com/fregante/shorten-repo-url/archive/6.4.1.zip 1`] = `6.4.1
.zip`;
36 |
37 | exports[`https://github.com/fregante/shorten-repo-url/blame/cc8fc46/.gitignore 1`] = `cc8fc46
/.gitignore (blame)`;
38 |
39 | exports[`https://github.com/fregante/shorten-repo-url/blame/master/.gitignore 1`] = `master
/.gitignore (blame)`;
40 |
41 | exports[`https://github.com/fregante/shorten-repo-url/blame/v0.12/.gitignore 1`] = `v0.12
/.gitignore (blame)`;
42 |
43 | exports[`https://github.com/fregante/shorten-repo-url/blob/cc8fc46/.gitignore 1`] = `cc8fc46
/.gitignore`;
44 |
45 | exports[`https://github.com/fregante/shorten-repo-url/blob/main/한글.txt 1`] = `main
/한글.txt`;
46 |
47 | exports[`https://github.com/fregante/shorten-repo-url/blob/master/.gitignore 1`] = `master
/.gitignore`;
48 |
49 | exports[`https://github.com/fregante/shorten-repo-url/blob/v0.12/.gitignore 1`] = `v0.12
/.gitignore`;
50 |
51 | exports[`https://github.com/fregante/shorten-repo-url/commit/cc8fc46.diff 1`] = `cc8fc46
.diff`;
52 |
53 | exports[`https://github.com/fregante/shorten-repo-url/commit/cc8fc46.patch 1`] = `cc8fc46
.patch`;
54 |
55 | exports[`https://github.com/fregante/shorten-repo-url/commits/cc8fc46/.gitignore 1`] = `cc8fc46
/.gitignore (commits)`;
56 |
57 | exports[`https://github.com/fregante/shorten-repo-url/commits/master/.gitignore 1`] = `master
/.gitignore (commits)`;
58 |
59 | exports[`https://github.com/fregante/shorten-repo-url/commits/v0.12/.gitignore 1`] = `v0.12
/.gitignore (commits)`;
60 |
61 | exports[`https://github.com/fregante/shorten-repo-url/compare 1`] = `fregante/shorten-repo-url/compare`;
62 |
63 | exports[`https://github.com/fregante/shorten-repo-url/compare/d71718db6aa4feb8dc10edbad1134472468e971a 1`] = `d71718d
(compare)`;
64 |
65 | exports[`https://github.com/fregante/shorten-repo-url/compare/master 1`] = `master
(compare)`;
66 |
67 | exports[`https://github.com/fregante/shorten-repo-url/compare/master...master 1`] = `master...master
(compare)`;
68 |
69 | exports[`https://github.com/fregante/shorten-repo-url/contributors 1`] = `fregante/shorten-repo-url/contributors`;
70 |
71 | exports[`https://github.com/fregante/shorten-repo-url/issues 1`] = `fregante/shorten-repo-url/issues`;
72 |
73 | exports[`https://github.com/fregante/shorten-repo-url/issues?q=is%3Aissue++is%3Aopen+sort%3Aupdated-desc+&unrelated=true 1`] = `fregante/shorten-repo-url/issues?unrelated=true (is:open sort:updated-desc)`;
74 |
75 | exports[`https://github.com/fregante/shorten-repo-url/issues?q=wow 1`] = `fregante/shorten-repo-url/issues (wow)`;
76 |
77 | exports[`https://github.com/fregante/shorten-repo-url/labels 1`] = `fregante/shorten-repo-url/labels`;
78 |
79 | exports[`https://github.com/fregante/shorten-repo-url/labels/npm 1`] = `npm (label)`;
80 |
81 | exports[`https://github.com/fregante/shorten-repo-url/milestone/25 1`] = `fregante/shorten-repo-url/milestone/25`;
82 |
83 | exports[`https://github.com/fregante/shorten-repo-url/milestones 1`] = `fregante/shorten-repo-url/milestones`;
84 |
85 | exports[`https://github.com/fregante/shorten-repo-url/network 1`] = `fregante/shorten-repo-url/network`;
86 |
87 | exports[`https://github.com/fregante/shorten-repo-url/projects 1`] = `fregante/shorten-repo-url/projects`;
88 |
89 | exports[`https://github.com/fregante/shorten-repo-url/pull/123/checks 1`] = `#123 (checks)`;
90 |
91 | exports[`https://github.com/fregante/shorten-repo-url/pull/123/commits 1`] = `#123 (commits)`;
92 |
93 | exports[`https://github.com/fregante/shorten-repo-url/pull/123/files 1`] = `#123 (files)`;
94 |
95 | exports[`https://github.com/fregante/shorten-repo-url/pulse 1`] = `fregante/shorten-repo-url/pulse`;
96 |
97 | exports[`https://github.com/fregante/shorten-repo-url/releases 1`] = `fregante/shorten-repo-url/releases`;
98 |
99 | exports[`https://github.com/fregante/shorten-repo-url/releases/download/6.4.1/now-macos 1`] = `6.4.1
now-macos (download)`;
100 |
101 | exports[`https://github.com/fregante/shorten-repo-url/releases/tag/v0.12.0 1`] = `v0.12.0
(release)`;
102 |
103 | exports[`https://github.com/fregante/shorten-repo-url/tree/d71718db6aa4feb8dc10edbad1134472468e971a 1`] = `d71718d
`;
104 |
105 | exports[`https://github.com/fregante/shorten-repo-url/tree/d71718db6aa4feb8dc10edbad1134472468e971a/doc 1`] = `d71718d
/doc`;
106 |
107 | exports[`https://github.com/fregante/shorten-repo-url/tree/master/doc 1`] = `master
/doc`;
108 |
109 | exports[`https://github.com/fregante/shorten-repo-url/tree/v0.12 1`] = `v0.12
`;
110 |
111 | exports[`https://github.com/fregante/shorten-repo-url/tree/v0.12/doc 1`] = `v0.12
/doc`;
112 |
113 | exports[`https://github.com/fregante/shorten-repo-url/wiki/%22Can-you-add-this-feature%3F%22 1`] = `Wiki: "Can you add this feature?"`;
114 |
115 | exports[`https://github.com/issues 1`] = `github.com/issues`;
116 |
117 | exports[`https://github.com/issues?q=is%3Aissue++is%3Aopen+sort%3Aupdated-desc+&unrelated=true 1`] = `github.com/issues?unrelated=true (is:open sort:updated-desc)`;
118 |
119 | exports[`https://github.com/marketplace 1`] = `github.com/marketplace`;
120 |
121 | exports[`https://github.com/network/dependencies 1`] = `github.com/network/dependencies`;
122 |
123 | exports[`https://github.com/nodejs 1`] = `@nodejs`;
124 |
125 | exports[`https://github.com/nodejs/node/ 1`] = `nodejs/node`;
126 |
127 | exports[`https://github.com/nodejs/node/blame/cc8fc46/.gitignore 1`] = `nodejs/node@cc8fc46
/.gitignore (blame)`;
128 |
129 | exports[`https://github.com/nodejs/node/blame/master/.gitignore 1`] = `nodejs/node@master
/.gitignore (blame)`;
130 |
131 | exports[`https://github.com/nodejs/node/blame/v0.12/.gitignore 1`] = `nodejs/node@v0.12
/.gitignore (blame)`;
132 |
133 | exports[`https://github.com/nodejs/node/blob/cc8fc46/.gitignore 1`] = `nodejs/node@cc8fc46
/.gitignore`;
134 |
135 | exports[`https://github.com/nodejs/node/blob/master/.gitignore 1`] = `nodejs/node@master
/.gitignore`;
136 |
137 | exports[`https://github.com/nodejs/node/blob/v0.12/.gitignore 1`] = `nodejs/node@v0.12
/.gitignore`;
138 |
139 | exports[`https://github.com/nodejs/node/commit/cc8fc46.diff 1`] = `nodejs/node@cc8fc46
.diff`;
140 |
141 | exports[`https://github.com/nodejs/node/commit/cc8fc46.patch 1`] = `nodejs/node@cc8fc46
.patch`;
142 |
143 | exports[`https://github.com/nodejs/node/commits/cc8fc46/.gitignore 1`] = `nodejs/node@cc8fc46
/.gitignore (commits)`;
144 |
145 | exports[`https://github.com/nodejs/node/commits/master/.gitignore 1`] = `nodejs/node@master
/.gitignore (commits)`;
146 |
147 | exports[`https://github.com/nodejs/node/commits/v0.12/.gitignore 1`] = `nodejs/node@v0.12
/.gitignore (commits)`;
148 |
149 | exports[`https://github.com/nodejs/node/compare 1`] = `nodejs/node/compare`;
150 |
151 | exports[`https://github.com/nodejs/node/compare/d71718db6aa4feb8dc10edbad1134472468e971a 1`] = `nodejs/node@d71718d
(compare)`;
152 |
153 | exports[`https://github.com/nodejs/node/compare/master 1`] = `nodejs/node@master
(compare)`;
154 |
155 | exports[`https://github.com/nodejs/node/compare/master...master 1`] = `nodejs/node@master...master
(compare)`;
156 |
157 | exports[`https://github.com/nodejs/node/contributors 1`] = `nodejs/node/contributors`;
158 |
159 | exports[`https://github.com/nodejs/node/graphs/commit-activity 1`] = `nodejs/node/graphs/commit-activity`;
160 |
161 | exports[`https://github.com/nodejs/node/labels 1`] = `nodejs/node/labels`;
162 |
163 | exports[`https://github.com/nodejs/node/labels/Please%21%20♥ 1`] = `nodejs/node/Please! ♥ (label)`;
164 |
165 | exports[`https://github.com/nodejs/node/labels/npm 1`] = `nodejs/node/npm (label)`;
166 |
167 | exports[`https://github.com/nodejs/node/milestone/25 1`] = `nodejs/node/milestone/25`;
168 |
169 | exports[`https://github.com/nodejs/node/milestones 1`] = `nodejs/node/milestones`;
170 |
171 | exports[`https://github.com/nodejs/node/network 1`] = `nodejs/node/network`;
172 |
173 | exports[`https://github.com/nodejs/node/projects 1`] = `nodejs/node/projects`;
174 |
175 | exports[`https://github.com/nodejs/node/pull/123/files 1`] = `nodejs/node#123 (files)`;
176 |
177 | exports[`https://github.com/nodejs/node/pulse 1`] = `nodejs/node/pulse`;
178 |
179 | exports[`https://github.com/nodejs/node/releases 1`] = `nodejs/node/releases`;
180 |
181 | exports[`https://github.com/nodejs/node/releases/tag/v0.12.0 1`] = `nodejs/node@v0.12.0
(release)`;
182 |
183 | exports[`https://github.com/nodejs/node/tree/d71718db6aa4feb8dc10edbad1134472468e971a 1`] = `nodejs/node@d71718d
`;
184 |
185 | exports[`https://github.com/nodejs/node/tree/d71718db6aa4feb8dc10edbad1134472468e971a/doc 1`] = `nodejs/node@d71718d
/doc`;
186 |
187 | exports[`https://github.com/nodejs/node/tree/master/doc 1`] = `nodejs/node@master
/doc`;
188 |
189 | exports[`https://github.com/nodejs/node/tree/v0.12 1`] = `nodejs/node@v0.12
`;
190 |
191 | exports[`https://github.com/nodejs/node/tree/v0.12/doc 1`] = `nodejs/node@v0.12
/doc`;
192 |
193 | exports[`https://github.com/nodejs/node/wiki 1`] = `nodejs/node/wiki`;
194 |
195 | exports[`https://github.com/nodejs/shorten-repo-url/ 1`] = `nodejs/shorten-repo-url`;
196 |
197 | exports[`https://github.com/pulls 1`] = `github.com/pulls`;
198 |
199 | exports[`https://github.com/pulls?q=is%3Apr++is%3Aopen+sort%3Aupdated-desc+&unrelated=true 1`] = `github.com/pulls?unrelated=true (is:open sort:updated-desc)`;
200 |
201 | exports[`https://github.com/refined-github/refined-github/labels/Please%21%20♥%EF%B8%8E 1`] = `refined-github/refined-github/Please! ♥︎ (label)`;
202 |
203 | exports[`https://github.com/refined-github/refined-github/wiki/%22Can-you-add-this-feature%3F%22 1`] = `Wiki: "Can you add this feature?" (refined-github/refined-github)`;
204 |
205 | exports[`https://github.com/refined-github/refined-github/wiki/%22Can-you-add-this-feature%3F%22# 1`] = `Wiki: "Can you add this feature?" (refined-github/refined-github)`;
206 |
207 | exports[`https://github.com/refined-github/refined-github/wiki/%22Can-you-add-this-feature%3F%22#3-it-doesnt-require-options 1`] = `Wiki: "Can you add this feature?" (3 it doesnt require options) (refined-github/refined-github)`;
208 |
209 | exports[`https://github.com/scarf005/hangul-test/wiki/한글-위키-페이지 1`] = `Wiki: 한글 위키 페이지 (scarf005/hangul-test)`;
210 |
211 | exports[`https://github.com/scarf005/hangul-test/wiki/한글-위키-페이지#한글-헤딩 1`] = `Wiki: 한글 위키 페이지 (한글 헤딩) (scarf005/hangul-test)`;
212 |
213 | exports[`https://github.com/settings/profile 1`] = `github.com/settings/profile`;
214 |
215 | exports[`https://github.com/sindresorhus 1`] = `@sindresorhus`;
216 |
217 | exports[`https://github.com/sindresorhus/notifier-for-github/pull/253/files/6b4489d417c9425dc27c5fb8d6b4a8518debd035..60cdcf3c3646164441bf8f037cef620479cdec59 1`] = `6b4489d4..60cdcf3c
(#253)`;
218 |
219 | exports[`https://github.com/trending 1`] = `github.com/trending`;
220 |
221 | exports[`https://github.com/trending/developers 1`] = `github.com/trending/developers`;
222 |
223 | exports[`https://github.com/zeit/now-cli/archive/6.4.1.zip 1`] = `zeit/now-cli@6.4.1
.zip`;
224 |
225 | exports[`https://github.com/zeit/now-cli/releases/download/6.4.1/now-macos 1`] = `zeit/now-cli@6.4.1
now-macos (download)`;
226 |
227 | exports[`https://raw.githubusercontent.com/fregante/shorten-repo-url/d71718db/.gitignore 1`] = `d71718db
/.gitignore (raw)`;
228 |
229 | exports[`https://raw.githubusercontent.com/fregante/shorten-repo-url/master/.gitignore 1`] = `master
/.gitignore (raw)`;
230 |
231 | exports[`https://raw.githubusercontent.com/fregante/shorten-repo-url/v0.12/.gitignore 1`] = `v0.12
/.gitignore (raw)`;
232 |
233 | exports[`https://raw.githubusercontent.com/nodejs/node/d71718db/.gitignore 1`] = `nodejs/node@d71718db
/.gitignore (raw)`;
234 |
235 | exports[`https://raw.githubusercontent.com/nodejs/node/master/.gitignore 1`] = `nodejs/node@master
/.gitignore (raw)`;
236 |
237 | exports[`https://raw.githubusercontent.com/nodejs/node/v0.12/.gitignore 1`] = `nodejs/node@v0.12
/.gitignore (raw)`;
238 |
239 | exports[`https://rawgit.com/fregante/shorten-repo-url/master/.gitignore 1`] = `master
/.gitignore (raw)`;
240 |
241 | exports[`https://rawgit.com/nodejs/node/master/.gitignore 1`] = `nodejs/node@master
/.gitignore (raw)`;
242 |
243 | exports[`https://togithub.com/fregante/shorten-repo-url/commit/98c6175b0cbd4caca71d24e68e57b942b0dfb549 1`] = `98c6175
`;
244 |
245 | exports[`https://togithub.com/fregante/shorten-repo-url/issues/25 1`] = `#25`;
246 |
247 | exports[`https://togithub.com/fregante/shorten-repo-url/issues/28#issue-850900171 1`] = `#28 (comment)`;
248 |
249 | exports[`https://togithub.com/fregante/shorten-repo-url/pull/32 1`] = `#32`;
250 |
251 | exports[`https://togithub.com/fregante/shorten-repo-url/pull/32/files 1`] = `#32 (files)`;
252 |
253 | exports[`https://togithub.com/fregante/shorten-repo-url/pull/33#discussion_r750069394 1`] = `#33 (review)`;
254 |
255 | exports[`https://togithub.com/fregante/shorten-repo-url/pull/33#pullrequestreview-801229042 1`] = `#33 (review)`;
256 |
257 | exports[`https://togithub.com/nodejs/node/pull/123 1`] = `nodejs/node#123`;
258 |
259 | exports[`https://togithub.com/nodejs/node/pull/123/files 1`] = `nodejs/node#123 (files)`;
260 |
261 | exports[`https://togithub.com/refined-github/refined-github/commit/4f270c4f50e0a2a20085a6e92095117f10340322 1`] = `refined-github/refined-github@4f270c4
`;
262 |
263 | exports[`https://togithub.com/refined-github/refined-github/commit/e81a9646b448d90c7e02ab41332cab0507dccbbd#commitcomment-60089354 1`] = `refined-github/refined-github@e81a964
(comment)`;
264 |
265 | exports[`https://www.google.com/ 1`] = `google.com`;
266 |
267 | exports[`https://www.npmjs.com/ 1`] = `npmjs.com`;
268 |
269 | exports[`https://www.npmjs.com/packaasdge/node 1`] = `npmjs.com/packaasdge/node`;
270 |
271 | exports[`https://wwww.google.com/ 1`] = `wwww.google.com`;
272 |
273 | exports[`https://한글로-된-경로.com/하위경로#한글-해시 1`] = `한글로-된-경로.com/하위경로#한글-해시`;
274 |
--------------------------------------------------------------------------------
/index.d.ts:
--------------------------------------------------------------------------------
1 | /**
2 | Shortens a GitHub URL string.
3 |
4 | @param anchor An HTMLAnchorElement
5 | @param url The GitHub URL to shorten.
6 | @returns The shortened URL in HTML as a string
7 | @example https://github.com/nodejs/node/tree/v0.12/doc becomes nodejs/node@v0.12
8 |
9 | */
10 | export default function shortenRepoUrl(url: string, currentUrl?: string): string;
11 |
12 | /**
13 | Shortens a GitHub URL in a DOM anchor if the link label is not customized (i.e. if the `href` matches the `textContent`)
14 |
15 | @param anchor An HTMLAnchorElement
16 | @param url The GitHub URL to shorten.
17 | @examplehttps://github.com becomes github.com
18 |
19 | */
20 | export function applyToLink(anchor: HTMLAnchorElement, url?: string): void;
21 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | import reservedNames from 'github-reserved-names/reserved-names.json' with { type: 'json' };
2 |
3 | const patchDiffRegex = /[.](patch|diff)$/;
4 | const releaseRegex = /^releases[/]tag[/]([^/]+)/;
5 | const labelRegex = /^labels[/]([^/]+)/;
6 | const compareRegex = /^compare[/]([^/]+)/;
7 | const pullRegex = /^pull[/](?\d+)(?:[/](?[^/]+))?(?:[/](?[\da-f]{40})[.][.](?[\da-f]{40}))?$/;
8 | const issueRegex = /^issues[/](\d+)$/;
9 | const commitRegex = /^commit[/]([\da-f]{40})$/;
10 | const releaseArchiveRegex = /^archive[/](.+)([.]zip|[.]tar[.]gz)/;
11 | const releaseDownloadRegex = /^releases[/]download[/]([^/]+)[/](.+)/;
12 | const dependentsRegex = /^network[/]dependents[/]?$/;
13 | const dependenciesRegex = /^network[/]dependencies[/]?$/;
14 | const wikiRegex = /^wiki[/](.+)$/;
15 |
16 | /** @type {(searchParameters: URLSearchParams, pathname: string) => string} */
17 | function pullQueryOut(searchParameters, pathname) {
18 | let query = searchParameters.get('q');
19 |
20 | if (!query) {
21 | return '';
22 | }
23 |
24 | searchParameters.delete('q');
25 | if (pathname.endsWith('/issues')) {
26 | query = query.replace('is:issue', '');
27 | }
28 |
29 | if (pathname.endsWith('/pulls')) {
30 | query = query.replace('is:pr', '');
31 | }
32 |
33 | return ` (${query.replaceAll(/\s+/g, ' ').trim()})`;
34 | }
35 |
36 | /** @param revision {string} */
37 | function styleRevision(revision) {
38 | if (!revision) {
39 | return;
40 | }
41 |
42 | revision = revision.replace(patchDiffRegex, '');
43 | if (/^[0-9a-f]{40}$/.test(revision)) {
44 | revision = revision.slice(0, 7);
45 | }
46 |
47 | return `${revision}
`;
48 | }
49 |
50 | /** @param hash {string} */
51 | function commentIndicator(hash) {
52 | if (hash.startsWith('#issue-') || hash.startsWith('#commitcomment-')) {
53 | return ' (comment)';
54 | }
55 |
56 | if (hash.startsWith('#pullrequestreview-') || hash.startsWith('#discussion_r')) {
57 | return ' (review)';
58 | }
59 |
60 | return '';
61 | }
62 |
63 | /**
64 | * Filter out null values
65 | * @type {(array: string[], delimiter?: string) => string}
66 | */
67 | function joinValues(array, delimiter = '/') {
68 | return array.filter(Boolean).join(delimiter);
69 | }
70 |
71 | /**
72 | * @param href {string}
73 | * @param currentUrl {string}
74 | */
75 | function shortenRepoUrl(href, currentUrl = 'https://github.com') {
76 | if (!href) {
77 | return;
78 | }
79 |
80 | currentUrl = new URL(currentUrl);
81 | const currentRepo = currentUrl.pathname.slice(1).split('/', 2).join('/');
82 |
83 | /**
84 | * Parse URL manually to avoid URL encoding and punycode
85 | */
86 | const origin = href.split('/', 3).join('/');
87 | const pathname = href.slice(origin.length).replace(/[?#].*/, '') || '/';
88 | const hash = /#.+$/.exec(href)?.[0] ?? '';
89 |
90 | // Use URL exclusively for search parameters because they're too hard to parse
91 | const url = new URL(href);
92 | const {search, searchParams} = url;
93 |
94 | const pathnameParts = pathname.slice(1).split('/'); // ['user', 'repo', 'pull', '342']
95 | const repoPath = pathnameParts.slice(2).join('/'); // 'pull/342'
96 |
97 | const isRaw = [
98 | 'https://raw.githubusercontent.com',
99 | 'https://cdn.rawgit.com',
100 | 'https://rawgit.com',
101 | ].includes(origin);
102 |
103 | const isRedirection = [
104 | 'https://togithub.com', // Renovate
105 | 'https://github-redirect.dependabot.com', // Dependabot
106 | 'https://redirect.github.com', // Dependabot
107 | ].includes(origin);
108 |
109 | let [
110 | user,
111 | repo,
112 | type,
113 | revision,
114 | ...filePath
115 | ] = pathnameParts;
116 |
117 | if (isRaw) {
118 | [
119 | user,
120 | repo,
121 | // Raw URLs don't have `blob` here
122 | revision,
123 | ...filePath
124 | ] = pathnameParts;
125 | type = 'raw';
126 | }
127 |
128 | revision = styleRevision(revision);
129 | filePath = filePath.join('/');
130 |
131 | const isLocal = origin === currentUrl.origin;
132 | const isThisRepo = (isLocal || isRaw || isRedirection) && currentRepo === `${user}/${repo}`;
133 | const isReserved = reservedNames.includes(user);
134 | const isDependents = dependentsRegex.test(repoPath);
135 | const isDependencies = dependenciesRegex.test(repoPath);
136 | const [, diffOrPatch] = repoPath.match(patchDiffRegex) || [];
137 | const [, release] = repoPath.match(releaseRegex) || [];
138 | const [, releaseTag, releaseTagExtension] = repoPath.match(releaseArchiveRegex) || [];
139 | const [, downloadTag, downloadFilename] = repoPath.match(releaseDownloadRegex) || [];
140 | const [, label] = repoPath.match(labelRegex) || [];
141 | const [, compare] = repoPath.match(compareRegex) || [];
142 | const {pull, pullPage, pullPartialStart, pullPartialEnd} = repoPath.match(pullRegex)?.groups ?? {};
143 | const [, issue] = isRedirection ? repoPath.match(issueRegex) || [] : [];
144 | const [, commit] = isRedirection ? repoPath.match(commitRegex) || [] : [];
145 | const [, wiki] = repoPath.match(wikiRegex) || [];
146 | const isFileOrDirectory = revision && [
147 | 'raw',
148 | 'tree',
149 | 'blob',
150 | 'blame',
151 | 'commits',
152 | ].includes(type);
153 |
154 | const repoUrl = isThisRepo ? '' : `${user}/${repo}`;
155 |
156 | /**
157 | * Shorten URL
158 | */
159 | if (isReserved || pathname === '/' || (!isLocal && !isRaw && !isRedirection)) {
160 | const cleanHref = [
161 | origin
162 | .replace(/^https:[/][/]/, '')
163 | .replace(/^www[.]/, ''),
164 | pathname
165 | .replace(/[/]$/, ''),
166 | ];
167 |
168 | if (['issues', 'pulls'].includes(user) && !repo) {
169 | const query = pullQueryOut(url.searchParams, url.pathname);
170 | cleanHref.push(url.search, query);
171 | } else {
172 | cleanHref.push(url.search);
173 | }
174 |
175 | cleanHref.push(decodeURI(url.hash));
176 |
177 | return cleanHref.join('');
178 | }
179 |
180 | if (user && !repo) {
181 | return `@${user}${search}${hash}`;
182 | }
183 |
184 | if (isFileOrDirectory) {
185 | const revisioned = joinValues(
186 | [joinValues([repoUrl, revision], '@'), filePath],
187 | '/',
188 | );
189 | const partial = `${revisioned}${search}${hash}`;
190 | if (type !== 'blob' && type !== 'tree') {
191 | return `${partial} (${type})`;
192 | }
193 |
194 | return partial;
195 | }
196 |
197 | if (diffOrPatch) {
198 | const partial = joinValues([repoUrl, revision], '@');
199 | return `${partial}.${diffOrPatch}${search}${hash}`;
200 | }
201 |
202 | if (release) {
203 | const partial = joinValues([repoUrl, `${release}
`], '@');
204 | return `${partial}${search}${hash} (release)`;
205 | }
206 |
207 | if (releaseTagExtension) {
208 | const partial = joinValues([repoUrl, `${releaseTag}
`], '@');
209 | return `${partial}${releaseTagExtension}${search}${hash}`;
210 | }
211 |
212 | if (downloadFilename) {
213 | const partial = joinValues([repoUrl, `${downloadTag}
`], '@');
214 | return `${partial} ${downloadFilename}${search}${hash} (download)`;
215 | }
216 |
217 | if (label) {
218 | return (
219 | joinValues([repoUrl, decodeURIComponent(label)])
220 | + `${search}${hash} (label)`
221 | );
222 | }
223 |
224 | if (isDependents) {
225 | return `${user}/${repo} (dependents)`;
226 | }
227 |
228 | if (isDependencies) {
229 | return `${user}/${repo} (dependencies)`;
230 | }
231 |
232 | if (pull) {
233 | if (pullPage === 'files' && pullPartialStart && pullPartialEnd) {
234 | return `${pullPartialStart.slice(0, 8)}..${pullPartialEnd.slice(0, 8)}
(#${pull})`;
235 | }
236 |
237 | if (pullPage) {
238 | return `${repoUrl}#${pull} (${pullPage})`;
239 | }
240 | }
241 |
242 | if (compare) {
243 | const partial = joinValues([repoUrl, revision], '@');
244 | return `${partial}${search}${hash} (compare)`;
245 | }
246 |
247 | if (wiki) {
248 | const hashPart = (hash ? ' (' + hash.slice(1) + ')' : '');
249 | const cleanLabel = (wiki + hashPart).replaceAll('-', ' ');
250 | const repoPart = repoUrl ? ` (${repoUrl})` : '';
251 | return `Wiki: ${decodeURIComponent(cleanLabel)}${repoPart}`;
252 | }
253 |
254 | // Shorten URLs that would otherwise be natively shortened
255 | if (isRedirection) {
256 | if (issue) {
257 | return `${repoUrl}#${issue}${commentIndicator(hash)}`;
258 | }
259 |
260 | if (pull) {
261 | return `${repoUrl}#${pull}${commentIndicator(hash)}`;
262 | }
263 |
264 | if (commit) {
265 | return joinValues([repoUrl, `${commit.slice(0, 7)}
`], '@') + commentIndicator(hash);
266 | }
267 | }
268 |
269 | const query = pullQueryOut(searchParams, pathname);
270 |
271 | if (searchParams.get('tab') === 'readme-ov-file') {
272 | searchParams.delete('tab');
273 | }
274 |
275 | // Drop leading and trailing slash of relative path
276 | return pathname.replaceAll(/^[/]|[/]$/g, '') + url.search + hash + query;
277 | }
278 |
279 | /**
280 | * Without this, %% would throw an error
281 | * @type {(url: string) => string}
282 | */
283 | function safeDecode(url) {
284 | try {
285 | return new URL(url).href;
286 | } catch {
287 | return url;
288 | }
289 | }
290 |
291 | /** @param a {HTMLAnchorElement} */
292 | function getLinkHref(a) {
293 | return a.dataset.originalHref ?? a.href;
294 | }
295 |
296 | /** @param a {HTMLAnchorElement} */
297 | function isCustomLink(a) {
298 | const url = safeDecode(getLinkHref(a));
299 | const label = safeDecode(a.textContent);
300 | return (
301 | // `trim` makes it compatible with this feature: https://github.com/sindresorhus/refined-github/pull/3085
302 | url !== label.trim()
303 | // .href automatically adds a / to naked origins so that needs to be tested too
304 | && url !== `${label}/`
305 | );
306 | }
307 |
308 | /** @type {(a: HTMLAnchorElement, currentUrl: string) => boolean} */
309 | export function applyToLink(a, currentUrl) {
310 | // `safeDecode` is needed because some URLs are encoded in different ways in the DOM and in the `href` property: https://github.com/refined-github/shorten-repo-url/issues/19
311 |
312 | if (
313 | // Shorten only if the link name hasn't been customized
314 | !isCustomLink(a)
315 | // And if there are no additional images in the link
316 | && !a.firstElementChild
317 | ) {
318 | const url = a.textContent;
319 | const shortened = shortenRepoUrl(url, currentUrl);
320 | a.replaceChildren(
321 | ...shortened.split(
322 | /([^<]+)<\/code>/g,
323 | ).map((part, i) => {
324 | if (i % 2 === 0) {
325 | return part;
326 | }
327 |
328 | const codeElement = document.createElement('code');
329 | codeElement.textContent = part;
330 | return codeElement;
331 | }),
332 | );
333 | return true;
334 | }
335 |
336 | return false;
337 | }
338 |
339 | export default shortenRepoUrl;
340 |
--------------------------------------------------------------------------------
/index.test-d.ts:
--------------------------------------------------------------------------------
1 | import {expectType} from 'tsd';
2 | import {applyToLink} from './index.js';
3 |
4 | expectType(
5 | applyToLink(document.createElement('a'), 'https://bettersite.com'),
6 | );
7 |
--------------------------------------------------------------------------------
/index.test.js:
--------------------------------------------------------------------------------
1 | import {test, expect} from 'vitest';
2 | import {Window} from 'happy-dom';
3 | import shortenUrl, {applyToLink} from './index.js';
4 |
5 | const currentLocation = 'https://github.com/fregante/shorten-repo-url/issue/1';
6 | globalThis.document = new Window({url: currentLocation}).document;
7 |
8 | expect.addSnapshotSerializer({
9 | serialize(value) {
10 | return value;
11 | },
12 | test(value) {
13 | return value;
14 | },
15 | });
16 |
17 | const urls = [
18 | 'https://github.com/fregante/shorten-repo-url/',
19 | 'https://github.com/fregante/shorten-repo-url/?tab=readme-ov-file',
20 | 'https://github.com/fregante/shorten-repo-url/tree/v0.12',
21 | 'https://github.com/fregante/shorten-repo-url/tree/d71718db6aa4feb8dc10edbad1134472468e971a',
22 | 'https://github.com/nodejs/node/',
23 | 'https://github.com/nodejs/shorten-repo-url/',
24 | 'https://github.com/nodejs/node/tree/v0.12',
25 | 'https://github.com/nodejs/node/tree/d71718db6aa4feb8dc10edbad1134472468e971a',
26 | 'https://github.com/fregante/shorten-repo-url/tree/master/doc',
27 | 'https://github.com/fregante/shorten-repo-url/tree/v0.12/doc',
28 | 'https://github.com/fregante/shorten-repo-url/tree/d71718db6aa4feb8dc10edbad1134472468e971a/doc',
29 | 'https://github.com/nodejs/node/tree/master/doc',
30 | 'https://github.com/nodejs/node/tree/v0.12/doc',
31 | 'https://github.com/nodejs/node/tree/d71718db6aa4feb8dc10edbad1134472468e971a/doc',
32 | 'https://github.com/fregante/shorten-repo-url/blob/master/.gitignore',
33 | 'https://github.com/fregante/shorten-repo-url/blob/v0.12/.gitignore',
34 | 'https://github.com/fregante/shorten-repo-url/blob/cc8fc46/.gitignore',
35 | 'https://github.com/fregante/shorten-repo-url/blob/main/한글.txt',
36 | 'https://github.com/nodejs/node/blob/master/.gitignore',
37 | 'https://github.com/nodejs/node/blob/v0.12/.gitignore',
38 | 'https://github.com/nodejs/node/blob/cc8fc46/.gitignore',
39 | 'https://github.com/fregante/shorten-repo-url/blame/master/.gitignore',
40 | 'https://github.com/fregante/shorten-repo-url/blame/v0.12/.gitignore',
41 | 'https://github.com/fregante/shorten-repo-url/blame/cc8fc46/.gitignore',
42 | 'https://github.com/nodejs/node/blame/master/.gitignore',
43 | 'https://github.com/nodejs/node/blame/v0.12/.gitignore',
44 | 'https://github.com/nodejs/node/blame/cc8fc46/.gitignore',
45 | 'https://github.com/fregante/shorten-repo-url/commits/master/.gitignore',
46 | 'https://github.com/fregante/shorten-repo-url/commits/v0.12/.gitignore',
47 | 'https://github.com/fregante/shorten-repo-url/commits/cc8fc46/.gitignore',
48 | 'https://github.com/nodejs/node/commits/master/.gitignore',
49 | 'https://github.com/nodejs/node/commits/v0.12/.gitignore',
50 | 'https://github.com/nodejs/node/commits/cc8fc46/.gitignore',
51 | 'https://github.com/fregante/shorten-repo-url/commit/cc8fc46.diff',
52 | 'https://github.com/fregante/shorten-repo-url/commit/cc8fc46.patch',
53 | 'https://github.com/nodejs/node/commit/cc8fc46.diff',
54 | 'https://github.com/nodejs/node/commit/cc8fc46.patch',
55 | 'https://github.com/fregante/shorten-repo-url/releases/tag/v0.12.0',
56 | 'https://github.com/nodejs/node/releases/tag/v0.12.0',
57 | 'https://github.com/fregante/shorten-repo-url/milestone/25',
58 | 'https://github.com/fregante/shorten-repo-url/compare/d71718db6aa4feb8dc10edbad1134472468e971a',
59 | 'https://github.com/fregante/shorten-repo-url/compare/master',
60 | 'https://github.com/fregante/shorten-repo-url/compare/master...master',
61 | 'https://github.com/nodejs/node/compare/d71718db6aa4feb8dc10edbad1134472468e971a',
62 | 'https://github.com/nodejs/node/compare/master',
63 | 'https://github.com/nodejs/node/compare/master...master',
64 | 'https://github.com/nodejs/node/milestone/25',
65 | 'https://github.com/fregante/shorten-repo-url/labels/npm',
66 | 'https://github.com/nodejs/node/labels/npm',
67 | 'https://github.com/nodejs/node/labels/Please%21%20♥',
68 | 'https://github.com/refined-github/refined-github/labels/Please%21%20♥%EF%B8%8E',
69 | 'https://github.com/fregante/shorten-repo-url/archive/6.4.1.zip',
70 | 'https://github.com/fregante/shorten-repo-url/releases/download/6.4.1/now-macos',
71 | 'https://github.com/zeit/now-cli/archive/6.4.1.zip',
72 | 'https://github.com/zeit/now-cli/releases/download/6.4.1/now-macos',
73 | 'https://github.com/bfred-it/shorten-repo-url/network/dependents',
74 | 'https://github.com/bfred-it/shorten-repo-url/network/dependencies',
75 | 'https://github.com/network/dependencies',
76 | 'https://github.com/bfred-it/shorten-repo-url/wiki',
77 | 'https://github.com/fregante/shorten-repo-url/pulse',
78 | 'https://github.com/fregante/shorten-repo-url/labels',
79 | 'https://github.com/fregante/shorten-repo-url/compare',
80 | 'https://github.com/fregante/shorten-repo-url/network',
81 | 'https://github.com/fregante/shorten-repo-url/projects',
82 | 'https://github.com/fregante/shorten-repo-url/releases',
83 | 'https://github.com/fregante/shorten-repo-url/milestones',
84 | 'https://github.com/fregante/shorten-repo-url/contributors',
85 | 'https://github.com/fregante/shorten-repo-url/pull/123/files',
86 | 'https://github.com/nodejs/node/pull/123/files',
87 | 'https://github.com/fregante/shorten-repo-url/pull/123/commits',
88 | 'https://github.com/fregante/shorten-repo-url/pull/123/checks',
89 | 'https://github.com/nodejs/node/wiki',
90 | 'https://github.com/nodejs/node/pulse',
91 | 'https://github.com/nodejs/node/labels',
92 | 'https://github.com/nodejs/node/compare',
93 | 'https://github.com/nodejs/node/network',
94 | 'https://github.com/nodejs/node/projects',
95 | 'https://github.com/nodejs/node/releases',
96 | 'https://github.com/nodejs/node/milestones',
97 | 'https://github.com/nodejs/node/contributors',
98 | 'https://github.com/nodejs/node/graphs/commit-activity',
99 | 'https://rawgit.com/fregante/shorten-repo-url/master/.gitignore',
100 | 'https://cdn.rawgit.com/fregante/shorten-repo-url/v0.12/.gitignore',
101 | 'https://cdn.rawgit.com/fregante/shorten-repo-url/d71718db/.gitignore',
102 | 'https://raw.githubusercontent.com/fregante/shorten-repo-url/master/.gitignore',
103 | 'https://raw.githubusercontent.com/fregante/shorten-repo-url/v0.12/.gitignore',
104 | 'https://raw.githubusercontent.com/fregante/shorten-repo-url/d71718db/.gitignore',
105 | 'https://rawgit.com/nodejs/node/master/.gitignore',
106 | 'https://cdn.rawgit.com/nodejs/node/v0.12/.gitignore',
107 | 'https://cdn.rawgit.com/nodejs/node/d71718db/.gitignore',
108 | 'https://raw.githubusercontent.com/nodejs/node/master/.gitignore',
109 | 'https://raw.githubusercontent.com/nodejs/node/v0.12/.gitignore',
110 | 'https://raw.githubusercontent.com/nodejs/node/d71718db/.gitignore',
111 | 'https://github.com/sindresorhus',
112 | 'https://github.com/nodejs',
113 | 'https://github.com/pulls',
114 | 'https://github.com/issues',
115 | 'https://github.com/trending',
116 | 'https://github.com/features',
117 | 'https://github.com/marketplace',
118 | 'https://github.com/trending/developers',
119 | 'https://github.com/settings/profile',
120 | 'https://github.com/',
121 | 'https://github.com',
122 | 'https://github.com/fregante/shorten-repo-url/issues',
123 | 'https://github.com/fregante/shorten-repo-url/issues?q=wow',
124 | 'https://github.com/fregante/shorten-repo-url/issues?q=is%3Aissue++is%3Aopen+sort%3Aupdated-desc+&unrelated=true',
125 | 'https://github.com/issues?q=is%3Aissue++is%3Aopen+sort%3Aupdated-desc+&unrelated=true',
126 | 'https://github.com/pulls?q=is%3Apr++is%3Aopen+sort%3Aupdated-desc+&unrelated=true',
127 | 'https://github.com/sindresorhus/notifier-for-github/pull/253/files/6b4489d417c9425dc27c5fb8d6b4a8518debd035..60cdcf3c3646164441bf8f037cef620479cdec59',
128 | 'https://togithub.com/fregante/shorten-repo-url/issues/25',
129 | 'https://togithub.com/fregante/shorten-repo-url/issues/28#issue-850900171',
130 | 'https://togithub.com/fregante/shorten-repo-url/pull/32',
131 | 'https://togithub.com/fregante/shorten-repo-url/pull/32/files',
132 | 'https://togithub.com/fregante/shorten-repo-url/pull/33#pullrequestreview-801229042',
133 | 'https://togithub.com/fregante/shorten-repo-url/pull/33#discussion_r750069394',
134 | 'https://togithub.com/nodejs/node/pull/123',
135 | 'https://togithub.com/nodejs/node/pull/123/files',
136 | 'https://togithub.com/fregante/shorten-repo-url/commit/98c6175b0cbd4caca71d24e68e57b942b0dfb549',
137 | 'https://togithub.com/refined-github/refined-github/commit/4f270c4f50e0a2a20085a6e92095117f10340322',
138 | 'https://togithub.com/refined-github/refined-github/commit/e81a9646b448d90c7e02ab41332cab0507dccbbd#commitcomment-60089354',
139 | 'https://github.com/refined-github/refined-github/wiki/%22Can-you-add-this-feature%3F%22#3-it-doesnt-require-options',
140 | 'https://github.com/refined-github/refined-github/wiki/%22Can-you-add-this-feature%3F%22#',
141 | 'https://github.com/refined-github/refined-github/wiki/%22Can-you-add-this-feature%3F%22',
142 | 'https://github.com/fregante/shorten-repo-url/wiki/%22Can-you-add-this-feature%3F%22',
143 | 'https://github.com/scarf005/hangul-test/wiki/한글-위키-페이지',
144 | 'https://github.com/scarf005/hangul-test/wiki/한글-위키-페이지#한글-헤딩',
145 | 'https://developer.mozilla.org/en-US/docs/Web/API/Document/createElement#parameters',
146 | 'https://www.google.com/',
147 | 'https://wwww.google.com/',
148 | 'http://www.google.com/',
149 | 'https://www.npmjs.com/',
150 | 'https://www.npmjs.com/packaasdge/node',
151 | 'https://example.com/nodejs/node/blob/cc8fc46/.gitignore',
152 | 'https://example.site/한글로-된-URL',
153 | 'https://한글로-된-경로.com/하위경로#한글-해시',
154 | ];
155 |
156 | test.each(urls)('%s', url => {
157 | const shortened = shortenUrl(url, currentLocation);
158 | expect(shortened).toMatchSnapshot();
159 |
160 | const a = document.createElement('a');
161 | a.href = url;
162 |
163 | // The URL might contain CJK characters, but after it's passed to a.href it's encoded
164 | const correctlyEncodedUrl = a.href;
165 |
166 | a.textContent = url;
167 | applyToLink(a, currentLocation);
168 | expect(a.href, 'applyToLink should not alter the href').toBe(correctlyEncodedUrl);
169 | expect(a.innerHTML).toBe(shortened);
170 | });
171 |
172 |
--------------------------------------------------------------------------------
/license:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) Federico Brigante (https://fregante.com)
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6 |
7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
10 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "shorten-repo-url",
3 | "version": "5.2.1",
4 | "description": "Shorten GitHub URLs like GitHub shortens Issues and Commit URLs",
5 | "keywords": [
6 | "commit",
7 | "file",
8 | "github",
9 | "gitlab",
10 | "issue",
11 | "link",
12 | "links",
13 | "ref",
14 | "reference",
15 | "shorter",
16 | "url"
17 | ],
18 | "repository": "refined-github/shorten-repo-url",
19 | "funding": "https://github.com/sponsors/fregante",
20 | "license": "MIT",
21 | "author": "Federico Brigante (https://fregante.com)",
22 | "type": "module",
23 | "exports": "./index.js",
24 | "main": "./index.js",
25 | "types": "./index.d.ts",
26 | "files": [
27 | "index.js",
28 | "index.d.ts"
29 | ],
30 | "scripts": {
31 | "test": "xo && tsd && vitest run"
32 | },
33 | "xo": {
34 | "parser": "@typescript-eslint/parser",
35 | "globals": [
36 | "document"
37 | ],
38 | "rules": {
39 | "unicorn/better-regex": "off",
40 | "unicorn/prefer-module": "off",
41 | "complexity": "off"
42 | }
43 | },
44 | "dependencies": {
45 | "github-reserved-names": "^2.0.5"
46 | },
47 | "devDependencies": {
48 | "@sindresorhus/tsconfig": "^5.0.0",
49 | "happy-dom": "^15.0.0",
50 | "tsd": "^0.31.1",
51 | "vitest": "^2.0.5",
52 | "xo": "^0.58.0"
53 | },
54 | "engines": {
55 | "node": ">=20.10"
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # shorten-repo-url
2 |
3 | > Shorten GitHub links like GitHub shortens Issues and Commit links. Used on [refined-github](https://github.com/refined-github/refined-github)
4 |
5 | 
6 |
7 | Look at [the tests](https://github.com/refined-github/shorten-repo-url/blob/main/index.test.js) to see what each URL is shortened to. GitLab URLs are mostly compatible but they're not officially supported.
8 |
9 | It works on any domain, so GitHub Enterprise is also supported.
10 |
11 | ## Install
12 |
13 | ```
14 | $ npm install shorten-repo-url
15 | ```
16 |
17 | ## Usage
18 |
19 | ```js
20 | const shortenRepoUrl = require('shorten-repo-url');
21 |
22 | const HTML = shortenRepoUrl(
23 | 'https://github.com/nodejs/node/tree/v0.12/doc',
24 | 'https://github.com/nodejs/node' // same repo
25 | );
26 | //=> 'v0.12
' // repo-less URL
27 |
28 | const HTML = shortenRepoUrl(
29 | 'https://github.com/nodejs/node/tree/v0.12/doc',
30 | 'https://github.com' // not the same repo
31 | );
32 | //=> 'nodejs/node@v0.12
' // URL with repo
33 | ```
34 |
35 | ## API
36 |
37 | ### shortenRepoUrl(url, currentUrl)
38 |
39 | Returns the shortened URL in HTML as a `string` like `nodejs/node@v0.12
`.
40 |
41 | #### url
42 |
43 | Type: `string`
44 |
45 | The GitHub URL to shorten.
46 |
47 | #### currentUrl
48 |
49 | Type: `string`, like `location.href`
50 |
51 | The URL of the current page, to build relative URLs like `v0.12
` instead of the longer `nodejs/node@v0.12
`
52 |
53 | ### shortenRepoUrl.applyToLink(link, currentUrl)
54 |
55 | Automatically shorten the link's text if the text matches the URL, i.e. `https://github.com`. If a `data-original-href` attribute is present, it will be used when comparing the link’s text and when generating the shortened URL.
56 |
57 | Note: this function will never change the `href` of the link, it only changes the text.
58 |
59 | It will return `true` or `false` depending on whether the link was shortened.
60 |
61 | #### link
62 |
63 | Type: `Element`
64 |
65 | Example: `shortenRepoUrl.applyToLink(document.querySelector(a))`
66 |
67 | #### currentUrl
68 |
69 | Type: `string`, like `location.href`
70 |
71 | Same as before.
72 |
73 | ## License
74 |
75 | MIT © [Federico Brigante](https://fregante.com)
76 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@sindresorhus/tsconfig",
3 | "compilerOptions": {
4 | "target": "ES2022",
5 | }
6 | }
7 |
--------------------------------------------------------------------------------