Commit 6114a1e
Changed files (113)
badges
abc-commit
bad-words
cafe-commit
chore-commit
cosmetic-commit
covid-19
dead-commit
delorean
emoji-only-commit
favorite-word
fix-commit
github-anniversary
mass-delete-commit
my-badges-contributor
old-issue
polite-coder
pr-collaboration
public-keys
revert-revert-commit
spooky-commit
star-gazer
stars
the-ultimate-question
this-is-fine
time-of-commit
scripts
src
all-badges
badges/abc-commit/a-commit.png
Binary file
badges/abc-commit/ab-commit.png
Binary file
badges/abc-commit/abc-commit.png
Binary file
src/all-badges/abc-commit/abc-commit.ts โ badges/abc-commit/abc-commit.ts
@@ -1,19 +1,18 @@
-import { BadgePresenter, ID, Present } from '../../badges.js'
-import { Commit, Repo } from '../../collect/types.js'
+import { Commit, define, Repo } from '#src'
-export default new (class implements BadgePresenter {
- url = new URL(import.meta.url)
- tiers = true
- badges = [
+export default define({
+ url: import.meta.url,
+ tiers: true,
+ badges: [
'a-commit',
'ab-commit',
'abc-commit',
'abcd-commit',
'abcde-commit',
'abcdef-commit',
- ] as const
- present: Present = (data, grant) => {
- const types: [string, ID][] = [
+ ] as const,
+ present(data, grant) {
+ const types: [string, (typeof this.badges)[number]][] = [
['abcdef', 'abcdef-commit'],
['abcde', 'abcde-commit'],
['abcd', 'abcd-commit'],
@@ -43,8 +42,8 @@ export default new (class implements BadgePresenter {
fn()
}
}
- }
-})()
+ },
+})
function link(re: RegExp, repo: Repo, commit: Commit) {
const sha = commit.sha.replace(re, '<strong>$1</strong>')
badges/abc-commit/abcd-commit.png
Binary file
badges/abc-commit/abcde-commit.png
Binary file
badges/abc-commit/abcdef-commit.png
Binary file
badges/bad-words/bad-words.png
Binary file
src/all-badges/bad-words/bad-words.ts โ badges/bad-words/bad-words.ts
@@ -1,11 +1,9 @@
-import { Present, BadgePresenter } from '../../badges.js'
-import { linkCommit } from '../../utils.js'
-import { Commit, Repo } from '../../collect/types.js'
+import { Commit, define } from '#src'
-export default new (class implements BadgePresenter {
- url = new URL(import.meta.url)
- badges = ['bad-words'] as const
- present: Present = (data, grant) => {
+export default define({
+ url: import.meta.url,
+ badges: ['bad-words'] as const,
+ present(data, grant) {
const commits: Commit[] = []
for (const repo of data.repos) {
@@ -22,5 +20,5 @@ export default new (class implements BadgePresenter {
'I used a word "fuck" in my commit message.',
).evidenceCommitsWithMessage(...commits)
}
- }
-})()
+ },
+})
badges/cafe-commit/cafe-commit.png
Binary file
src/all-badges/cafe-commit/cafe-commit.ts โ badges/cafe-commit/cafe-commit.ts
@@ -1,10 +1,9 @@
-import { BadgePresenter, Present } from '../../badges.js'
-import { Commit, Repo } from '../../collect/types.js'
+import { Commit, define, Repo } from '#src'
-export default new (class implements BadgePresenter {
- url = new URL(import.meta.url)
- badges = ['cafe-commit'] as const
- present: Present = (data, grant) => {
+export default define({
+ url: import.meta.url,
+ badges: ['cafe-commit'] as const,
+ present(data, grant) {
const commits: { repo: Repo; commit: Commit }[] = []
for (const repo of data.repos) {
@@ -28,5 +27,5 @@ export default new (class implements BadgePresenter {
`I pushed a commit with "cafe" ${commits.length} times.`,
).evidence(text)
}
- }
-})()
+ },
+})
badges/chore-commit/chore-commit.png
Binary file
src/all-badges/chore-commit/chore-commit.ts โ badges/chore-commit/chore-commit.ts
@@ -1,10 +1,9 @@
-import { BadgePresenter, Present } from '../../badges.js'
+import { define } from '#src'
-export default new (class implements BadgePresenter {
- url = new URL(import.meta.url)
- badges = ['chore-commit'] as const
- tiers = false
- present: Present = (data, grant) => {
+export default define({
+ url: import.meta.url,
+ badges: ['chore-commit'] as const,
+ present(data, grant) {
for (const repo of data.repos) {
for (const commit of repo.commits) {
if (/^chore\b/.test(commit.message)) {
@@ -16,5 +15,5 @@ export default new (class implements BadgePresenter {
}
}
}
- }
-})()
+ },
+})
badges/cosmetic-commit/cosmetic-commit.png
Binary file
src/all-badges/cosmetic-commit/cosmetic-commit.ts โ badges/cosmetic-commit/cosmetic-commit.ts
@@ -1,10 +1,9 @@
-import { BadgePresenter, Present } from '../../badges.js'
-import { Commit } from '../../collect/types.js'
+import { Commit, define } from '#src'
-export default new (class implements BadgePresenter {
- url = new URL(import.meta.url)
- badges = ['cosmetic-commit'] as const
- present: Present = (data, grant) => {
+export default define({
+ url: import.meta.url,
+ badges: ['cosmetic-commit'] as const,
+ present(data, grant) {
const commits: Commit[] = []
for (const repo of data.repos) {
@@ -23,8 +22,8 @@ export default new (class implements BadgePresenter {
...commits.sort(latest).slice(0, 6),
)
}
- }
-})()
+ },
+})
function latest(a: Commit, b: Commit) {
return (
badges/covid-19/covid-19.png
Binary file
badges/covid-19/covid-19.ts
@@ -0,0 +1,15 @@
+import { define } from '#src'
+
+export default define({
+ url: import.meta.url,
+ badges: ['covid-19'] as const,
+ present(data, grant) {
+ const date = new Date(data.user.createdAt)
+ if (date.getFullYear() < 2020) {
+ grant(
+ 'covid-19',
+ 'I rolled before Covid-19: Survivor of the Great TP Shortage',
+ )
+ }
+ },
+})
badges/dead-commit/dead-commit.png
Binary file
src/all-badges/dead-commit/dead-commit.ts โ badges/dead-commit/dead-commit.ts
@@ -1,10 +1,9 @@
-import { BadgePresenter, Present } from '../../badges.js'
-import { Commit, Repo } from '../../collect/types.js'
+import { Commit, define, Repo } from '#src'
-export default new (class implements BadgePresenter {
- url = new URL(import.meta.url)
- badges = ['dead-commit'] as const
- present: Present = (data, grant) => {
+export default define({
+ url: import.meta.url,
+ badges: ['dead-commit'] as const,
+ present(data, grant) {
const commits: { repo: Repo; commit: Commit }[] = []
for (const repo of data.repos) {
@@ -28,5 +27,5 @@ export default new (class implements BadgePresenter {
`I pushed a commit with "dead" ${commits.length} times.`,
).evidence(text)
}
- }
-})()
+ },
+})
badges/delorean/delorean.png
Binary file
src/all-badges/delorean/delorean.ts โ badges/delorean/delorean.ts
@@ -1,10 +1,9 @@
-import { BadgePresenter, Present } from '../../badges.js'
-import { Commit } from '../../collect/types.js'
+import { Commit, define } from '#src'
-export default new (class implements BadgePresenter {
- url = new URL(import.meta.url)
- badges = ['delorean'] as const
- present: Present = (data, grant) => {
+export default define({
+ url: import.meta.url,
+ badges: ['delorean'] as const,
+ present(data, grant) {
const commits: Commit[] = []
for (const repo of data.repos) {
@@ -22,8 +21,8 @@ export default new (class implements BadgePresenter {
'I committed on the day Doctor Emmett Brown invented the flux capacitor!',
).evidenceCommits(...commits.sort(latest).slice(0, 6))
}
- }
-})()
+ },
+})
function latest(a: Commit, b: Commit) {
return (
badges/emoji-only-commit/emoji-only-commit.png
Binary file
src/all-badges/emoji-only-commit/emoji-only-commit.ts โ badges/emoji-only-commit/emoji-only-commit.ts
@@ -1,9 +1,9 @@
-import { Present, BadgePresenter } from '../../badges.js'
+import { define } from '#src'
-export default new (class implements BadgePresenter {
- url = new URL(import.meta.url)
- badges = ['emoji-only-commit'] as const
- present: Present = (data, grant) => {
+export default define({
+ url: import.meta.url,
+ badges: ['emoji-only-commit'] as const,
+ present(data, grant) {
const commits = data.repos.flatMap((repo) =>
repo.commits.filter((commit) =>
/^(\p{Emoji}|\s)+$/u.test(commit.message + commit.messageBody),
@@ -16,5 +16,5 @@ export default new (class implements BadgePresenter {
'I used only emojis in my commit message.',
).evidenceCommitsWithMessage(...commits)
}
- }
-})()
+ },
+})
badges/favorite-word/favorite-word.png
Binary file
src/all-badges/favorite-word/favorite-word.ts โ badges/favorite-word/favorite-word.ts
@@ -1,9 +1,9 @@
-import { BadgePresenter, Present } from '../../badges.js'
+import { define } from '#src'
-export default new (class implements BadgePresenter {
- url = new URL(import.meta.url)
- badges = ['favorite-word'] as const
- present: Present = (data, grant) => {
+export default define({
+ url: import.meta.url,
+ badges: ['favorite-word'] as const,
+ present(data, grant) {
const counts: Record<string, number> = {}
for (const repo of data.repos) {
for (const commit of repo.commits) {
@@ -28,5 +28,5 @@ export default new (class implements BadgePresenter {
.map((p, i) => `${i + 1}. ${p[0]} (used ${p[1]} times)`)
.join('\n'),
)
- }
-})()
+ },
+})
badges/fix-commit/fix-2.png
Binary file
badges/fix-commit/fix-3.png
Binary file
badges/fix-commit/fix-4.png
Binary file
badges/fix-commit/fix-5.png
Binary file
badges/fix-commit/fix-6+.png
Binary file
badges/fix-commit/fix-6.png
Binary file
src/all-badges/fix-commit/fix-commit.ts โ badges/fix-commit/fix-commit.ts
@@ -1,19 +1,17 @@
-import { BadgePresenter, Grant, Present } from '../../badges.js'
+import { Commit, define } from '#src'
-import { Commit } from '../../collect/types.js'
-
-export default new (class implements BadgePresenter {
- url = new URL(import.meta.url)
- tiers = true
- badges = [
+export default define({
+ url: import.meta.url,
+ tiers: true,
+ badges: [
'fix-2',
'fix-3',
'fix-4',
'fix-5',
'fix-6',
'fix-6+', // For more than 6
- ] as const
- present: Present = (data, grant) => {
+ ] as const,
+ present(data, grant) {
for (const repo of data.repos) {
const sequences: Commit[][] = []
let previousCommitDate = null
@@ -74,5 +72,5 @@ export default new (class implements BadgePresenter {
.tier(6)
}
}
- }
-})()
+ },
+})
badges/github-anniversary/github-anniversary-10.png
Binary file
badges/github-anniversary/github-anniversary-15.png
Binary file
badges/github-anniversary/github-anniversary-20.png
Binary file
badges/github-anniversary/github-anniversary-5.png
Binary file
src/all-badges/github-anniversary/github-anniversary.ts โ badges/github-anniversary/github-anniversary.ts
@@ -1,15 +1,15 @@
-import { BadgePresenter, Present } from '../../badges.js'
+import { define } from '#src'
-export default new (class implements BadgePresenter {
- url = new URL(import.meta.url)
- tiers = true
- badges = [
+export default define({
+ url: import.meta.url,
+ tiers: true,
+ badges: [
'github-anniversary-5',
'github-anniversary-10',
'github-anniversary-15',
'github-anniversary-20',
- ] as const
- present: Present = (data, grant) => {
+ ] as const,
+ present(data, grant) {
const createdAt = new Date(data.user.createdAt)
const now = Date.now()
@@ -26,5 +26,5 @@ export default new (class implements BadgePresenter {
grant(badge, `I joined GitHub ${years} years ago.`)
}
})
- }
-})()
+ },
+})
badges/mass-delete-commit/mass-delete-commit-10k.png
Binary file
badges/mass-delete-commit/mass-delete-commit.png
Binary file
src/all-badges/mass-delete-commit/mass-delete-commit.ts โ badges/mass-delete-commit/mass-delete-commit.ts
@@ -1,14 +1,10 @@
-import { BadgePresenter, Present } from '../../badges.js'
+import { define } from '#src'
-export default new (class implements BadgePresenter {
- url = new URL(import.meta.url)
- tiers = true
- badges = [
- //
- 'mass-delete-commit',
- 'mass-delete-commit-10k',
- ] as const
- present: Present = (data, grant) => {
+export default define({
+ url: import.meta.url,
+ tiers: true,
+ badges: ['mass-delete-commit', 'mass-delete-commit-10k'] as const,
+ present(data, grant) {
for (const repo of data.repos) {
for (const commit of repo.commits) {
if (
@@ -30,5 +26,5 @@ export default new (class implements BadgePresenter {
}
}
}
- }
-})()
+ },
+})
badges/my-badges-contributor/my-badges-contributor.png
Binary file
src/all-badges/my-badges-contributor/my-badges-contributor.ts โ badges/my-badges-contributor/my-badges-contributor.ts
@@ -1,10 +1,9 @@
-import { BadgePresenter, Present } from '../../badges.js'
-import { Pull } from '../../collect/types.js'
+import { define, Pull } from '#src'
-export default new (class implements BadgePresenter {
- url = new URL(import.meta.url)
- badges = ['my-badges-contributor'] as const
- present: Present = (data, grant) => {
+export default define({
+ url: import.meta.url,
+ badges: ['my-badges-contributor'] as const,
+ present(data, grant) {
const pulls: Pull[] = []
for (const pull of data.pulls) {
if (
@@ -22,5 +21,5 @@ export default new (class implements BadgePresenter {
'I contributed to <https://github.com/my-badges/my-badges>!',
).evidencePRs(...pulls)
}
- }
-})()
+ },
+})
badges/old-issue/old-issue-1.png
Binary file
badges/old-issue/old-issue-10.png
Binary file
badges/old-issue/old-issue-2.png
Binary file
badges/old-issue/old-issue-3.png
Binary file
badges/old-issue/old-issue-4.png
Binary file
badges/old-issue/old-issue-5.png
Binary file
badges/old-issue/old-issue-6.png
Binary file
badges/old-issue/old-issue-7.png
Binary file
badges/old-issue/old-issue-8.png
Binary file
badges/old-issue/old-issue-9.png
Binary file
src/all-badges/old-issue/old-issue.ts โ badges/old-issue/old-issue.ts
@@ -1,11 +1,9 @@
-import { BadgePresenter, Present } from '../../badges.js'
+import { define, Issue } from '#src'
-import { Issue } from '../../collect/types.js'
-
-export default new (class implements BadgePresenter {
- url = new URL(import.meta.url)
- tiers = true
- badges = [
+export default define({
+ url: import.meta.url,
+ tiers: true,
+ badges: [
'old-issue-1',
'old-issue-2',
'old-issue-3',
@@ -16,8 +14,8 @@ export default new (class implements BadgePresenter {
'old-issue-8',
'old-issue-9',
'old-issue-10',
- ] as const
- present: Present = (data, grant) => {
+ ] as const,
+ present(data, grant) {
const buckets: { [years: number]: Issue[] } = {}
for (const issue of data.issues.sort(age)) {
@@ -41,8 +39,8 @@ export default new (class implements BadgePresenter {
.evidenceIssuesWithTitles(...buckets[years])
.tier(years)
}
- }
-})()
+ },
+})
function age(a: Issue, b: Issue) {
return new Date(a.closedAt).getTime() - new Date(b.closedAt).getTime()
badges/polite-coder/polite-coder.png
Binary file
src/all-badges/polite-coder/polite-coder.ts โ badges/polite-coder/polite-coder.ts
@@ -1,10 +1,9 @@
-import { BadgePresenter, Present } from '../../badges.js'
-import { linkIssue } from '../../utils.js'
+import { define, linkIssue } from '#src'
-export default new (class implements BadgePresenter {
- url = new URL(import.meta.url)
- badges = ['polite-coder', 'rebel-coder'] as const
- present: Present = (data, grant) => {
+export default define({
+ url: import.meta.url,
+ badges: ['polite-coder', 'rebel-coder'] as const,
+ present(data, grant) {
if (data.issues.length <= 10) {
return
}
@@ -31,5 +30,5 @@ export default new (class implements BadgePresenter {
'Straight to the point!',
)
}
- }
-})()
+ },
+})
badges/polite-coder/rebel-coder.png
Binary file
src/all-badges/pr-collaboration/pr-collaboration-10.png โ badges/pr-collaboration/pr-collaboration-10.png
File renamed without changes
src/all-badges/pr-collaboration/pr-collaboration-15.png โ badges/pr-collaboration/pr-collaboration-15.png
File renamed without changes
src/all-badges/pr-collaboration/pr-collaboration-20.png โ badges/pr-collaboration/pr-collaboration-20.png
File renamed without changes
src/all-badges/pr-collaboration/pr-collaboration-25.png โ badges/pr-collaboration/pr-collaboration-25.png
File renamed without changes
src/all-badges/pr-collaboration/pr-collaboration-5.png โ badges/pr-collaboration/pr-collaboration-5.png
File renamed without changes
src/all-badges/pr-collaboration/pr-collaboration.ts โ badges/pr-collaboration/pr-collaboration.ts
@@ -1,18 +1,16 @@
-import { BadgePresenter, Present } from '../../badges.js'
+import { define, Pull } from '#src'
-import { Pull } from '../../collect/types.js'
-
-export default new (class implements BadgePresenter {
- url = new URL(import.meta.url)
- tiers = true
- badges = [
+export default define({
+ url: import.meta.url,
+ tiers: true,
+ badges: [
'pr-collaboration-5',
'pr-collaboration-10',
'pr-collaboration-15',
'pr-collaboration-20',
'pr-collaboration-25',
- ] as const
- present: Present = (data, grant) => {
+ ] as const,
+ present(data, grant) {
for (const pull of data.pulls.sort(byParticipantsCount)) {
if (pull.participants.totalCount >= 5) {
grant(
@@ -55,8 +53,8 @@ export default new (class implements BadgePresenter {
.tier(5)
}
}
- }
-})()
+ },
+})
function byParticipantsCount(a: Pull, b: Pull) {
return a.participants.totalCount - b.participants.totalCount
badges/public-keys/public-keys-1.png
Binary file
badges/public-keys/public-keys-2.png
Binary file
badges/public-keys/public-keys-3.png
Binary file
badges/public-keys/public-keys-4.png
Binary file
badges/public-keys/public-keys-5.png
Binary file
src/all-badges/public-keys/public-keys.ts โ badges/public-keys/public-keys.ts
@@ -1,16 +1,16 @@
-import { BadgePresenter, Present } from '../../badges.js'
+import { define } from '#src'
-export default new (class implements BadgePresenter {
- url = new URL(import.meta.url)
- tiers = true
- badges = [
+export default define({
+ url: import.meta.url,
+ tiers: true,
+ badges: [
'public-keys-1',
'public-keys-2',
'public-keys-3',
'public-keys-4',
'public-keys-5',
- ] as const
- present: Present = (data, grant) => {
+ ] as const,
+ present(data, grant) {
const count = data.user.publicKeys?.totalCount ?? 0
if (count == 1) {
grant('public-keys-1', 'I have one public key').tier(1)
@@ -27,5 +27,5 @@ export default new (class implements BadgePresenter {
if (count >= 5) {
grant('public-keys-5', 'I have five or more public keys').tier(5)
}
- }
-})()
+ },
+})
badges/revert-revert-commit/revert-revert-commit.png
Binary file
src/all-badges/revert-revert-commit/revert-revert-commit.ts โ badges/revert-revert-commit/revert-revert-commit.ts
@@ -1,10 +1,9 @@
-import { BadgePresenter, Present } from '../../badges.js'
-import { Commit } from '../../collect/types.js'
+import { Commit, define } from '#src'
-export default new (class implements BadgePresenter {
- url = new URL(import.meta.url)
- badges = ['revert-revert-commit'] as const
- present: Present = (data, grant) => {
+export default define({
+ url: import.meta.url,
+ badges: ['revert-revert-commit'] as const,
+ present(data, grant) {
const commits: Commit[] = []
for (const repo of data.repos) {
@@ -21,5 +20,5 @@ export default new (class implements BadgePresenter {
'I reverted a revert commit.',
).evidenceCommits(...commits)
}
- }
-})()
+ },
+})
badges/spooky-commit/spooky-commit.png
Binary file
src/all-badges/spooky-commit/spooky-commit.ts โ badges/spooky-commit/spooky-commit.ts
@@ -1,10 +1,9 @@
-import { BadgePresenter, Present } from '../../badges.js'
-import { Commit } from '../../collect/types.js'
+import { Commit, define } from '#src'
-export default new (class implements BadgePresenter {
- url = new URL(import.meta.url)
- badges = ['spooky-commit'] as const
- present: Present = (data, grant) => {
+export default define({
+ url: import.meta.url,
+ badges: ['spooky-commit'] as const,
+ present(data, grant) {
const commits: Commit[] = []
for (const repo of data.repos) {
@@ -22,8 +21,8 @@ export default new (class implements BadgePresenter {
'I committed on the Halloween! Boo!',
).evidenceCommits(...commits.sort(latest).slice(0, 6))
}
- }
-})()
+ },
+})
function latest(a: Commit, b: Commit) {
return (
badges/star-gazer/star-gazer.png
Binary file
badges/star-gazer/star-gazer.ts
@@ -0,0 +1,13 @@
+import { define } from '#src'
+
+export default define({
+ url: import.meta.url,
+ badges: ['star-gazer'] as const,
+ present(data, grant) {
+ if (data.user.starredRepositories?.totalCount >= 1000) {
+ grant('star-gazer', "I'm a star gazer!").evidence(
+ "I've starred over 1000 repositories!",
+ )
+ }
+ },
+})
badges/stars/stars-100.png
Binary file
badges/stars/stars-1000.png
Binary file
badges/stars/stars-10000.png
Binary file
badges/stars/stars-2000.png
Binary file
badges/stars/stars-20000.png
Binary file
badges/stars/stars-500.png
Binary file
badges/stars/stars-5000.png
Binary file
src/all-badges/stars/stars.ts โ badges/stars/stars.ts
@@ -1,11 +1,9 @@
-import { BadgePresenter, Present } from '../../badges.js'
+import { define, Repo } from '#src'
-import { Repo } from '../../collect/types.js'
-
-export default new (class implements BadgePresenter {
- url = new URL(import.meta.url)
- tiers = true
- badges = [
+export default define({
+ url: import.meta.url,
+ tiers: true,
+ badges: [
'stars-100',
'stars-500',
'stars-1000',
@@ -13,8 +11,8 @@ export default new (class implements BadgePresenter {
'stars-5000',
'stars-10000',
'stars-20000',
- ] as const
- present: Present = (data, grant) => {
+ ] as const,
+ present(data, grant) {
const repos = data.repos.sort(asc).filter(withStars)
let totalStars = 0
@@ -57,8 +55,8 @@ export default new (class implements BadgePresenter {
.evidence(text(repos, 20_000))
.tier(7)
}
- }
-})()
+ },
+})
function asc(a: Repo, b: Repo) {
return (a.stargazers_count || 0) - (b.stargazers_count || 0)
badges/the-ultimate-question/the-ultimate-question.png
Binary file
src/all-badges/the-ultimate-question/the-ultimate-question.ts โ badges/the-ultimate-question/the-ultimate-question.ts
@@ -1,10 +1,9 @@
-import { BadgePresenter, Present } from '../../badges.js'
-import { Issue, Pull } from '../../collect/types.js'
+import { define, Issue, Pull } from '#src'
-export default new (class implements BadgePresenter {
- url = new URL(import.meta.url)
- badges = ['the-ultimate-question'] as const
- present: Present = (data, grant) => {
+export default define({
+ url: import.meta.url,
+ badges: ['the-ultimate-question'] as const,
+ present(data, grant) {
const list: (Issue | Pull)[] = []
for (const issue of data.issues) {
@@ -20,8 +19,8 @@ export default new (class implements BadgePresenter {
'I found the answer to the ultimate question of life, the universe, and everything!',
).evidence(list.map((x) => `- ${link(x)}`).join('\n'))
}
- }
-})()
+ },
+})
function link(x: Issue | Pull): string {
return `<a href="https://github.com/${x.repository.owner.login}/${x.repository.name}/issues/${x.number}">#${x.number}</a>`
badges/this-is-fine/this-is-fine.png
Binary file
src/all-badges/this-is-fine/this-is-fine.ts โ badges/this-is-fine/this-is-fine.ts
@@ -1,11 +1,9 @@
-import { BadgePresenter, Present } from '../../badges.js'
+import { define, Pull } from '#src'
-import { Pull } from '../../collect/types.js'
-
-export default new (class implements BadgePresenter {
- url = new URL(import.meta.url)
- badges = ['this-is-fine'] as const
- present: Present = (data, grant) => {
+export default define({
+ url: import.meta.url,
+ badges: ['this-is-fine'] as const,
+ present(data, grant) {
const pulls: Pull[] = []
for (const pull of data.pulls) {
@@ -37,5 +35,5 @@ export default new (class implements BadgePresenter {
'I merged a PR with failing checks',
).evidencePRsWithTitle(...pulls)
}
- }
-})()
+ },
+})
badges/time-of-commit/evening-commits.png
Binary file
badges/time-of-commit/midnight-commits.png
Binary file
badges/time-of-commit/morning-commits.png
Binary file
badges/time-of-commit/sleepy-coder.png
Binary file
src/all-badges/time-of-commit/time-of-commit.ts โ badges/time-of-commit/time-of-commit.ts
@@ -1,15 +1,14 @@
-import { BadgePresenter, Present } from '../../badges.js'
-import { Commit, User } from '../../collect/types.js'
+import { Commit, define, User } from '#src'
-export default new (class implements BadgePresenter {
- url = new URL(import.meta.url)
- badges = [
+export default define({
+ url: import.meta.url,
+ badges: [
'midnight-commits',
'morning-commits',
'evening-commits',
'sleepy-coder',
- ] as const
- present: Present = (data, grant) => {
+ ] as const,
+ present(data, grant) {
const morningCommits: Commit[] = []
const eveningCommits: Commit[] = []
const midnightCommits: Commit[] = []
@@ -58,8 +57,8 @@ export default new (class implements BadgePresenter {
...midnightCommits.sort(latest).slice(0, 6),
)
}
- }
-})()
+ },
+})
function latest(a: Commit, b: Commit) {
return (
badges/yeti/yeti.png
Binary file
src/all-badges/yeti/yeti.ts โ badges/yeti/yeti.ts
@@ -1,9 +1,9 @@
-import { BadgePresenter, Present } from '../../badges.js'
+import { define } from '#src'
-export default new (class implements BadgePresenter {
- url = new URL(import.meta.url)
- badges = ['yeti'] as const
- present: Present = (data, grant) => {
+export default define({
+ url: import.meta.url,
+ badges: ['yeti'] as const,
+ present(data, grant) {
for (const repo of data.repos) {
for (const commit of repo.commits) {
if (/yeti/i.test(commit.message)) {
@@ -12,5 +12,5 @@ export default new (class implements BadgePresenter {
}
}
}
- }
-})()
+ },
+})
src/all-badges/index.ts โ badges/index.ts
@@ -1,28 +1,28 @@
-export const allBadges = [
+export default [
await import('./abc-commit/abc-commit.js'),
- await import('./stars/stars.js'),
- await import('./time-of-commit/time-of-commit.js'),
- await import('./github-anniversary/github-anniversary.js'),
- await import('./yeti/yeti.js'),
- await import('./star-gazer/star-gazer.js'),
- await import('./dead-commit/dead-commit.js'),
await import('./bad-words/bad-words.js'),
- await import('./mass-delete-commit/mass-delete-commit.js'),
- await import('./revert-revert-commit/revert-revert-commit.js'),
- await import('./my-badges-contributor/my-badges-contributor.js'),
- await import('./fix-commit/fix-commit.js'),
+ await import('./cafe-commit/cafe-commit.js'),
await import('./chore-commit/chore-commit.js'),
- await import('./delorean/delorean.js'),
+ await import('./cosmetic-commit/cosmetic-commit.js'),
await import('./covid-19/covid-19.js'),
- await import('./pr-collaboration/pr-collaboration.js'),
- await import('./public-keys/public-keys.js'),
- await import('./old-issue/old-issue.js'),
- await import('./this-is-fine/this-is-fine.js'),
- await import('./the-ultimate-question/the-ultimate-question.js'),
+ await import('./dead-commit/dead-commit.js'),
+ await import('./delorean/delorean.js'),
+ await import('./emoji-only-commit/emoji-only-commit.js'),
await import('./favorite-word/favorite-word.js'),
+ await import('./fix-commit/fix-commit.js'),
+ await import('./github-anniversary/github-anniversary.js'),
+ await import('./mass-delete-commit/mass-delete-commit.js'),
+ await import('./my-badges-contributor/my-badges-contributor.js'),
+ await import('./old-issue/old-issue.js'),
await import('./polite-coder/polite-coder.js'),
- await import('./emoji-only-commit/emoji-only-commit.js'),
+ await import('./pr-collaboration/pr-collaboration.js'),
+ await import('./public-keys/public-keys.js'),
+ await import('./revert-revert-commit/revert-revert-commit.js'),
await import('./spooky-commit/spooky-commit.js'),
- await import('./cosmetic-commit/cosmetic-commit.js'),
- await import('./cafe-commit/cafe-commit.js')
+ await import('./star-gazer/star-gazer.js'),
+ await import('./stars/stars.js'),
+ await import('./the-ultimate-question/the-ultimate-question.js'),
+ await import('./this-is-fine/this-is-fine.js'),
+ await import('./time-of-commit/time-of-commit.js'),
+ await import('./yeti/yeti.js'),
] as const
scripts/check-images.mjs
@@ -0,0 +1,38 @@
+#!/usr/bin/env node
+
+import allBadges from '#badges'
+import fs from 'node:fs'
+import { fileURLToPath } from 'node:url'
+import * as path from 'node:path'
+import { imageDimensionsFromStream } from 'image-dimensions'
+
+const expectedDimensions = 256
+
+const root = path.join(path.dirname(fileURLToPath(import.meta.url)), '..')
+
+let ok = true
+for (const { default: b } of allBadges) {
+ const dirname = path.basename(path.dirname(fileURLToPath(b.url)))
+ for (const id of b.badges) {
+ const imagePath = path.join('badges', dirname, `${id}.png`)
+ const rootPath = path.join(root, imagePath)
+ if (!fs.existsSync(rootPath)) {
+ console.error(`Missing image for badge "${id}" at ${rootPath}`)
+ ok = false
+ }
+ const { width, height } = await imageDimensionsFromStream(
+ fs.createReadStream(rootPath),
+ )
+ if (width !== expectedDimensions || height !== expectedDimensions) {
+ console.error(
+ `Bad image dimensions for badge ${id}.png: ${width}x${height} (expected: ${expectedDimensions}x${expectedDimensions})`,
+ )
+ ok = false
+ }
+ }
+}
+if (!ok) {
+ process.exit(1)
+} else {
+ console.log('All images exist and have the expected dimensions')
+}
src/all-badges/cafe-commit/cafe-commit.png
Binary file
src/all-badges/covid-19/covid-19.ts
@@ -1,15 +0,0 @@
-import { BadgePresenter, Present } from '../../badges.js'
-
-export default new (class implements BadgePresenter {
- url = new URL(import.meta.url)
- badges = ['covid-19'] as const
- present: Present = (data, grant) => {
- const date = new Date(data.user.createdAt)
- if (date.getFullYear() < 2020) {
- grant(
- 'covid-19',
- 'I rolled before Covid-19: Survivor of the Great TP Shortage',
- )
- }
- }
-})()
src/all-badges/star-gazer/star-gazer.ts
@@ -1,13 +0,0 @@
-import { BadgePresenter, Present } from '../../badges.js'
-
-export default new (class implements BadgePresenter {
- url = new URL(import.meta.url)
- badges = ['star-gazer'] as const
- present: Present = (data, grant) => {
- if (data.user.starredRepositories?.totalCount >= 1000) {
- grant('star-gazer', "I'm a star gazer!").evidence(
- "I've starred over 1000 repositories!",
- )
- }
- }
-})()
src/all-badges/README
@@ -0,0 +1,1 @@
+Temporary folder for migration to new badges location.
src/badges.ts
@@ -1,25 +1,26 @@
-import { allBadges } from './all-badges/index.js'
-import { expectType, linkCommit, linkIssue, linkPull } from './utils.js'
+import allBadges from '#badges'
+import { linkCommit, linkIssue, linkPull } from './utils.js'
import { Commit, Data, Issue, Pull } from './collect/types.js'
-for (const {
- default: { badges },
-} of allBadges) {
- expectType<readonly [string, ...string[]]>(badges)
-}
+export type Presenters = (typeof allBadges)[number]['default']
+
+export type ID = Presenters['badges'][number]
-export type ID = (typeof allBadges)[number]['default']['badges'][number]
+export type List = readonly [string, ...string[]]
-export interface BadgePresenter {
- url: URL
+export type Presenter<B extends List> = {
+ url: string
+ badges: B
tiers?: boolean
- badges: unknown
- present: Present
+ present: (
+ data: Data,
+ grant: (id: B[number], desc: string) => Evidence,
+ ) => void
}
-export type Grant = ReturnType<typeof badgeCollection>
-
-export type Present = (data: Data, grant: Grant) => void
+export function define<B extends List>(presenter: Presenter<B>): Presenter<B> {
+ return presenter
+}
export type Badge = {
id: ID
@@ -29,23 +30,7 @@ export type Badge = {
image: string
}
-export function badgeCollection(newBadges: Badge[]) {
- return function grant(id: ID, desc: string) {
- const badge: Badge = {
- id,
- tier: 0,
- desc,
- body: '',
- image: '',
- }
- if (!newBadges.some((x) => x.id === id)) {
- newBadges.push(badge)
- }
- return new Evidence(badge)
- }
-}
-
-class Evidence {
+export class Evidence {
constructor(private badge: Badge) {}
tier(tier: number) {
src/check-images.ts
@@ -1,27 +0,0 @@
-import { allBadges } from './all-badges/index.js'
-import fs from 'node:fs'
-import { fileURLToPath } from 'url'
-import * as path from 'path'
-
-void (async function main() {
- const root = path.join(path.dirname(fileURLToPath(import.meta.url)), '..')
-
- let foundMissing = false
- for (const { default: b } of allBadges) {
- const dirname = path.basename(path.dirname(fileURLToPath(b.url)))
- for (const id of b.badges) {
- const imagePath = path.join('src/all-badges', dirname, `${id}.png`)
- const rootPath = path.join(root, imagePath)
- if (!fs.existsSync(rootPath)) {
- console.error(`Missing image for badge "${id}" at ${rootPath}`)
- foundMissing = true
- } else {
- console.log(`<img src="${imagePath}" alt="${id}" width="42">`)
- }
- }
- }
- if (foundMissing) {
- process.exit(1)
- return
- }
-})()
src/index.ts
@@ -0,0 +1,3 @@
+export { define } from './badges.js'
+export { Repo, User, Issue, Pull, Commit } from './collect/types.js'
+export { linkCommit, linkIssue, linkPull } from './utils.js'
src/main.ts
@@ -1,12 +1,12 @@
#!/usr/bin/env node
+import allBadges from '#badges'
import minimist from 'minimist'
import { Octokit } from 'octokit'
import { retry } from '@octokit/plugin-retry'
import { throttling } from '@octokit/plugin-throttling'
import { presentBadges } from './present-badges.js'
import { getData } from './get-data.js'
-import { allBadges } from './all-badges/index.js'
import { getUserBadges, gitClone, gitPush, thereAreChanges } from './repo.js'
import { updateBadges } from './update-badges.js'
import { updateReadme } from './update-readme.js'
src/present-badges.ts
@@ -1,12 +1,11 @@
-import { Badge, badgeCollection, BadgePresenter, ID } from './badges.js'
-import { allBadges } from './all-badges/index.js'
+import { Badge, Evidence, ID, List, Presenter } from './badges.js'
import path from 'node:path'
import { fileURLToPath } from 'node:url'
import { parseMask } from './utils.js'
import { Data } from './collect/types.js'
-export const presentBadges = (
- presenters: BadgePresenter[],
+export const presentBadges = <P extends Presenter<List>>(
+ presenters: P[],
data: Data,
userBadges: Badge[],
pickBadges: string[],
@@ -16,6 +15,8 @@ export const presentBadges = (
for (const presenter of presenters) {
const newBadges: Badge[] = []
const grant = badgeCollection(newBadges)
+
+ // @ts-ignore As `id: string` is not assignable to `id: ID`.
presenter.present(data, grant)
if (newBadges.length === 0) {
@@ -25,11 +26,10 @@ export const presentBadges = (
// Enhance badges with image URLs.
for (const b of newBadges) {
const baseDir = path.basename(path.dirname(fileURLToPath(presenter.url)))
- b.image = `https://github.com/my-badges/my-badges/blob/master/src/all-badges/${baseDir}/${b.id}.png?raw=true`
+ b.image = `https://github.com/my-badges/my-badges/blob/master/badges/${baseDir}/${b.id}.png?raw=true`
}
- const badgeFromPresenter = (x: Badge) =>
- (presenter.badges as ID[]).includes(x.id)
+ const badgeFromPresenter = (x: Badge) => presenter.badges.includes(x.id)
// Merge existing userBadges with newBadges.
if (compact && presenter.tiers) {
@@ -76,3 +76,19 @@ export const presentBadges = (
return userBadges
}
+
+export function badgeCollection(newBadges: Badge[]) {
+ return function grant(id: ID, desc: string) {
+ const badge: Badge = {
+ id,
+ tier: 0,
+ desc,
+ body: '',
+ image: '',
+ }
+ if (!newBadges.some((x) => x.id === id)) {
+ newBadges.push(badge)
+ }
+ return new Evidence(badge)
+ }
+}
src/utils.ts
@@ -26,8 +26,6 @@ export function quoteAttr(s: string) {
.replace(/[\r\n]/g, ' ')
}
-export const expectType = <T>(expression: T) => void 0
-
export function parseMask(value: string): RegExp {
return new RegExp(`^${value}$`.replace('*', '.+'))
}
test/present-badges.test.ts
@@ -1,7 +1,7 @@
import * as assert from 'node:assert'
import { describe, it } from 'node:test'
import { presentBadges } from '../src/present-badges.js'
-import { Badge, BadgePresenter } from '../src/badges.js'
+import { Badge, define, List, Presenter } from '../src/badges.js'
import { Data } from '../src/collect/types.js'
describe('present-badges', () => {
@@ -35,7 +35,7 @@ describe('present-badges', () => {
it('presentBadges() applies `pick`', async () => {
const userBadges = presentBadges(
- [await import('../src/all-badges/stars/stars.js')].map((m) => m.default),
+ [await import('#badges/stars/stars.js')].map((m) => m.default),
data,
[],
['stars-100', 'stars-500'],
@@ -55,7 +55,7 @@ describe('present-badges', () => {
'\n' +
"<sup>I have push, maintainer or admin permissions, so I'm definitely an author.<sup>\n",
image:
- 'https://github.com/my-badges/my-badges/blob/master/src/all-badges/stars/stars-100.png?raw=true',
+ 'https://github.com/my-badges/my-badges/blob/master/badges/stars/stars-100.png?raw=true',
},
{
id: 'stars-500',
@@ -68,14 +68,14 @@ describe('present-badges', () => {
'\n' +
"<sup>I have push, maintainer or admin permissions, so I'm definitely an author.<sup>\n",
image:
- 'https://github.com/my-badges/my-badges/blob/master/src/all-badges/stars/stars-500.png?raw=true',
+ 'https://github.com/my-badges/my-badges/blob/master/badges/stars/stars-500.png?raw=true',
},
])
})
it('presentBadges() applies `omit`', async () => {
const userBadges = presentBadges(
- [await import('../src/all-badges/stars/stars.js')].map((m) => m.default),
+ [await import('#badges/stars/stars.js')].map((m) => m.default),
data,
[],
['stars-100', 'stars-500'],
@@ -95,14 +95,14 @@ describe('present-badges', () => {
'\n' +
"<sup>I have push, maintainer or admin permissions, so I'm definitely an author.<sup>\n",
image:
- 'https://github.com/my-badges/my-badges/blob/master/src/all-badges/stars/stars-100.png?raw=true',
+ 'https://github.com/my-badges/my-badges/blob/master/badges/stars/stars-100.png?raw=true',
},
])
})
it('presentBadges() supports masks for `omit` && `pick`', async () => {
const userBadges = presentBadges(
- [await import('../src/all-badges/stars/stars.js')].map((m) => m.default),
+ [await import('#badges/stars/stars.js')].map((m) => m.default),
data,
[],
['stars-*'],
@@ -122,7 +122,7 @@ describe('present-badges', () => {
'\n' +
"<sup>I have push, maintainer or admin permissions, so I'm definitely an author.<sup>\n",
image:
- 'https://github.com/my-badges/my-badges/blob/master/src/all-badges/stars/stars-100.png?raw=true',
+ 'https://github.com/my-badges/my-badges/blob/master/badges/stars/stars-100.png?raw=true',
},
{
id: 'stars-500',
@@ -135,14 +135,14 @@ describe('present-badges', () => {
'\n' +
"<sup>I have push, maintainer or admin permissions, so I'm definitely an author.<sup>\n",
image:
- 'https://github.com/my-badges/my-badges/blob/master/src/all-badges/stars/stars-500.png?raw=true',
+ 'https://github.com/my-badges/my-badges/blob/master/badges/stars/stars-500.png?raw=true',
},
])
})
it('presentBadges() applies `compact`', async () => {
const userBadges = presentBadges(
- [await import('../src/all-badges/stars/stars.js')].map((m) => m.default),
+ [await import('#badges/stars/stars.js')].map((m) => m.default),
data,
[],
['stars-1000', 'stars-2000', 'stars-5000'],
@@ -163,28 +163,28 @@ describe('present-badges', () => {
'\n' +
"<sup>I have push, maintainer or admin permissions, so I'm definitely an author.<sup>\n",
image:
- 'https://github.com/my-badges/my-badges/blob/master/src/all-badges/stars/stars-2000.png?raw=true',
+ 'https://github.com/my-badges/my-badges/blob/master/badges/stars/stars-2000.png?raw=true',
},
])
})
it('presentBadges() keeps existing order of badges', async () => {
- const dumpPresenter1: BadgePresenter = {
- url: new URL('file:///tmp/dump.js'),
- badges: ['a-commit', 'ab-commit', 'abc-commit'],
+ const dumpPresenter1 = define({
+ url: 'file:///tmp/dump.js',
+ badges: ['a-commit', 'ab-commit', 'abc-commit'] as const,
present: (_, grant) => {
grant('a-commit', 'a')
grant('ab-commit', 'ab')
grant('abc-commit', 'abc')
},
- }
- const dumpPresenter2: BadgePresenter = {
- url: new URL('file:///tmp/dump.js'),
- badges: ['this-is-fine'],
+ })
+ const dumpPresenter2 = define({
+ url: 'file:///tmp/dump.js',
+ badges: ['this-is-fine'] as const,
present: (_, grant) => {
grant('this-is-fine', 'this is fine')
},
- }
+ })
const oldUserBadges: Badge[] = [
{
test/stars.test.ts
@@ -1,9 +1,9 @@
import * as assert from 'node:assert'
import { describe, it } from 'node:test'
-import starsPresenter from '../src/all-badges/stars/stars.js'
-import { Badge, badgeCollection } from '../src/badges.js'
-
+import starsPresenter from '#badges/stars/stars.js'
+import { badgeCollection } from '../src/present-badges.js'
import { Data } from '../src/collect/types.js'
+import { Badge } from '../src/badges.js'
describe('stars', () => {
it('counts and renders as expected', () => {
test/update-readme.test.ts
@@ -2,8 +2,8 @@ import * as assert from 'node:assert'
import { describe, it } from 'node:test'
import { generateReadme } from '../src/update-readme.js'
import type { Badge } from '../src/badges.js'
-import abcPresenter from '../src/all-badges/abc-commit/abc-commit.js'
-import { badgeCollection } from '../src/badges.js'
+import abcPresenter from '#badges/abc-commit/abc-commit.js'
+import { badgeCollection } from '../src/present-badges.js'
describe('generateReadme()', () => {
it('injects badges to md contents', () => {
CONTRIBUTING.md
@@ -2,11 +2,11 @@
If you want to contribute a badge:
-- Add your badge to the [all-badges](./src/all-badges) folder.
-- Add your badge to the [index.ts](./src/all-badges/index.ts) file.
+- Add your badge to the [badges](./badges) folder.
+- Add your badge to the [index.ts](./badges/index.ts) file.
- Any badge images are welcome (png, 256x256px).
-Here is an [example of a pull request](https://github.com/my-badges/my-badges/pull/1) adding a new badge.
+Example of a simple badge: [yeti.ts](./badges/yeti/yeti.ts).
## How to test locally?
@@ -19,14 +19,14 @@ npm run build
Run main.js with next command:
```sh
-node dist/main.js your-username
+node dist/src/main.js your-username
```
This command will collect your data and save it to `data/your-username.json` file.
You can skip recollecting the data with `--data` flag.
```sh
-node dist/main.js --data data/your-username.json
+node dist/src/main.js --data data/your-username.json
```
## How to create a badge image?
package-lock.json
@@ -15,15 +15,15 @@
"octokit": "^3.1.1"
},
"bin": {
- "update-my-badges": "dist/main.js"
+ "update-my-badges": "dist/src/main.js"
},
"devDependencies": {
"@octokit/graphql-schema": "^14.33.0",
"@types/minimist": "^1.2.3",
"@types/node": "^20.8.0",
"c8": "^8.0.1",
- "copyfiles": "^2.4.1",
"fast-glob": "^3.3.1",
+ "image-dimensions": "^2.3.0",
"prettier": "^3.0.3",
"ts-node": "^10.9.1",
"typescript": "^5.2.2"
@@ -800,17 +800,6 @@
"node": ">=6"
}
},
- "node_modules/cliui": {
- "version": "7.0.4",
- "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
- "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
- "dev": true,
- "dependencies": {
- "string-width": "^4.2.0",
- "strip-ansi": "^6.0.0",
- "wrap-ansi": "^7.0.0"
- }
- },
"node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
@@ -841,31 +830,6 @@
"integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
"dev": true
},
- "node_modules/copyfiles": {
- "version": "2.4.1",
- "resolved": "https://registry.npmjs.org/copyfiles/-/copyfiles-2.4.1.tgz",
- "integrity": "sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg==",
- "dev": true,
- "dependencies": {
- "glob": "^7.0.5",
- "minimatch": "^3.0.3",
- "mkdirp": "^1.0.4",
- "noms": "0.0.0",
- "through2": "^2.0.1",
- "untildify": "^4.0.0",
- "yargs": "^16.1.0"
- },
- "bin": {
- "copyfiles": "copyfiles",
- "copyup": "copyfiles"
- }
- },
- "node_modules/core-util-is": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
- "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
- "dev": true
- },
"node_modules/create-require": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
@@ -1075,6 +1039,22 @@
"integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
"dev": true
},
+ "node_modules/image-dimensions": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/image-dimensions/-/image-dimensions-2.3.0.tgz",
+ "integrity": "sha512-8Ar3lsO6+/JLfnUeHnR8Jp/IyQR85Jut5t4Swy1yiXNwj/xM9h5V53v5KE/m/ZSMG4qGRopnSy37uPzKyQCv0A==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "image-dimensions": "cli.js"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/indent-string": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
@@ -1146,12 +1126,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/isarray": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
- "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==",
- "dev": true
- },
"node_modules/isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
@@ -1355,33 +1329,11 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/mkdirp": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
- "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
- "dev": true,
- "bin": {
- "mkdirp": "bin/cmd.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
"node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
},
- "node_modules/noms": {
- "version": "0.0.0",
- "resolved": "https://registry.npmjs.org/noms/-/noms-0.0.0.tgz",
- "integrity": "sha512-lNDU9VJaOPxUmXcLb+HQFeUgQQPtMI24Gt6hgfuMHRJgMRHMF/qZ4HJD3GDru4sSw9IQl2jPjAYnQrdIeLbwow==",
- "dev": true,
- "dependencies": {
- "inherits": "^2.0.1",
- "readable-stream": "~1.0.31"
- }
- },
"node_modules/octokit": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/octokit/-/octokit-3.1.1.tgz",
@@ -1507,12 +1459,6 @@
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
- "node_modules/process-nextick-args": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
- "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
- "dev": true
- },
"node_modules/queue-microtask": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
@@ -1533,18 +1479,6 @@
}
]
},
- "node_modules/readable-stream": {
- "version": "1.0.34",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
- "integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==",
- "dev": true,
- "dependencies": {
- "core-util-is": "~1.0.0",
- "inherits": "~2.0.1",
- "isarray": "0.0.1",
- "string_decoder": "~0.10.x"
- }
- },
"node_modules/require-directory": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
@@ -1673,12 +1607,6 @@
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
"dev": true
},
- "node_modules/string_decoder": {
- "version": "0.10.31",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
- "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==",
- "dev": true
- },
"node_modules/string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
@@ -1731,52 +1659,6 @@
"node": ">=8"
}
},
- "node_modules/through2": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz",
- "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==",
- "dev": true,
- "dependencies": {
- "readable-stream": "~2.3.6",
- "xtend": "~4.0.1"
- }
- },
- "node_modules/through2/node_modules/isarray": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
- "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
- "dev": true
- },
- "node_modules/through2/node_modules/readable-stream": {
- "version": "2.3.8",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
- "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
- "dev": true,
- "dependencies": {
- "core-util-is": "~1.0.0",
- "inherits": "~2.0.3",
- "isarray": "~1.0.0",
- "process-nextick-args": "~2.0.0",
- "safe-buffer": "~5.1.1",
- "string_decoder": "~1.1.1",
- "util-deprecate": "~1.0.1"
- }
- },
- "node_modules/through2/node_modules/safe-buffer": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
- "dev": true
- },
- "node_modules/through2/node_modules/string_decoder": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
- "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
- "dev": true,
- "dependencies": {
- "safe-buffer": "~5.1.0"
- }
- },
"node_modules/to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
@@ -1865,21 +1747,6 @@
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz",
"integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w=="
},
- "node_modules/untildify": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz",
- "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/util-deprecate": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
- "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
- "dev": true
- },
"node_modules/v8-compile-cache-lib": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
@@ -1947,15 +1814,6 @@
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
},
- "node_modules/xtend": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
- "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
- "dev": true,
- "engines": {
- "node": ">=0.4"
- }
- },
"node_modules/y18n": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
@@ -1970,33 +1828,6 @@
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
},
- "node_modules/yargs": {
- "version": "16.2.0",
- "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
- "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
- "dev": true,
- "dependencies": {
- "cliui": "^7.0.2",
- "escalade": "^3.1.1",
- "get-caller-file": "^2.0.5",
- "require-directory": "^2.1.1",
- "string-width": "^4.2.0",
- "y18n": "^5.0.5",
- "yargs-parser": "^20.2.2"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/yargs-parser": {
- "version": "20.2.9",
- "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
- "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
- "dev": true,
- "engines": {
- "node": ">=10"
- }
- },
"node_modules/yn": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
package.json
@@ -4,7 +4,12 @@
"description": "Generate badges for your GitHub projects",
"type": "module",
"bin": {
- "update-my-badges": "dist/main.js"
+ "update-my-badges": "dist/src/main.js"
+ },
+ "imports": {
+ "#src": "./dist/src/index.js",
+ "#badges": "./dist/badges/index.js",
+ "#badges/*": "./dist/badges/*"
},
"scripts": {
"fmt": "prettier --write .",
@@ -12,7 +17,7 @@
"start": "tsc --watch",
"tsc": "tsc",
"build": "tsc",
- "check-images": "node dist/check-images.js",
+ "check-images": "node scripts/check-images.mjs",
"test": "npm run test:unit",
"test:unit": "c8 -r lcov -r text -o coverage -x scripts -x test node --loader ts-node/esm --experimental-specifier-resolution=node scripts/test.mjs"
},
@@ -28,6 +33,7 @@
"@types/node": "^20.8.0",
"c8": "^8.0.1",
"fast-glob": "^3.3.1",
+ "image-dimensions": "^2.3.0",
"prettier": "^3.0.3",
"ts-node": "^10.9.1",
"typescript": "^5.2.2"
README.md
@@ -14,71 +14,23 @@ But how does those badges look like? Take a look [here](https://github.com/anton
or [here](https://github.com/antongolub).
<p>
-<img src="src/all-badges/abc-commit/a-commit.png" alt="a-commit" width="42">
-<img src="src/all-badges/abc-commit/ab-commit.png" alt="ab-commit" width="42">
-<img src="src/all-badges/abc-commit/abc-commit.png" alt="abc-commit" width="42">
-<img src="src/all-badges/abc-commit/abcd-commit.png" alt="abcd-commit" width="42">
-<img src="src/all-badges/abc-commit/abcde-commit.png" alt="abcde-commit" width="42">
-<img src="src/all-badges/abc-commit/abcdef-commit.png" alt="abcdef-commit" width="42">
-<img src="src/all-badges/stars/stars-100.png" alt="stars-100" width="42">
-<img src="src/all-badges/stars/stars-500.png" alt="stars-500" width="42">
-<img src="src/all-badges/stars/stars-1000.png" alt="stars-1000" width="42">
-<img src="src/all-badges/stars/stars-2000.png" alt="stars-2000" width="42">
-<img src="src/all-badges/stars/stars-5000.png" alt="stars-5000" width="42">
-<img src="src/all-badges/stars/stars-10000.png" alt="stars-10000" width="42">
-<img src="src/all-badges/stars/stars-20000.png" alt="stars-20000" width="42">
-<img src="src/all-badges/time-of-commit/midnight-commits.png" alt="midnight-commits" width="42">
-<img src="src/all-badges/time-of-commit/morning-commits.png" alt="morning-commits" width="42">
-<img src="src/all-badges/time-of-commit/evening-commits.png" alt="evening-commits" width="42">
-<img src="src/all-badges/time-of-commit/sleepy-coder.png" alt="sleepy-coder" width="42">
-<img src="src/all-badges/github-anniversary/github-anniversary-5.png" alt="github-anniversary-5" width="42">
-<img src="src/all-badges/github-anniversary/github-anniversary-10.png" alt="github-anniversary-10" width="42">
-<img src="src/all-badges/github-anniversary/github-anniversary-15.png" alt="github-anniversary-15" width="42">
-<img src="src/all-badges/github-anniversary/github-anniversary-20.png" alt="github-anniversary-20" width="42">
-<img src="src/all-badges/yeti/yeti.png" alt="yeti" width="42">
-<img src="src/all-badges/star-gazer/star-gazer.png" alt="star-gazer" width="42">
-<img src="src/all-badges/dead-commit/dead-commit.png" alt="dead-commit" width="42">
-<img src="src/all-badges/bad-words/bad-words.png" alt="bad-words" width="42">
-<img src="src/all-badges/mass-delete-commit/mass-delete-commit.png" alt="mass-delete-commit" width="42">
-<img src="src/all-badges/mass-delete-commit/mass-delete-commit-10k.png" alt="mass-delete-commit-10k" width="42">
-<img src="src/all-badges/revert-revert-commit/revert-revert-commit.png" alt="revert-revert-commit" width="42">
-<img src="src/all-badges/my-badges-contributor/my-badges-contributor.png" alt="my-badges-contributor" width="42">
-<img src="src/all-badges/fix-commit/fix-2.png" alt="fix-2" width="42">
-<img src="src/all-badges/fix-commit/fix-3.png" alt="fix-3" width="42">
-<img src="src/all-badges/fix-commit/fix-4.png" alt="fix-4" width="42">
-<img src="src/all-badges/fix-commit/fix-5.png" alt="fix-5" width="42">
-<img src="src/all-badges/fix-commit/fix-6.png" alt="fix-6" width="42">
-<img src="src/all-badges/fix-commit/fix-6+.png" alt="fix-6+" width="42">
-<img src="src/all-badges/chore-commit/chore-commit.png" alt="chore-commit" width="42">
-<img src="src/all-badges/delorean/delorean.png" alt="delorean" width="42">
-<img src="src/all-badges/covid-19/covid-19.png" alt="covid-19" width="42">
-<img src="src/all-badges/pr-collaboration/pr-collaboration-5.png" alt="pr-collaboration-5" width="42">
-<img src="src/all-badges/pr-collaboration/pr-collaboration-10.png" alt="pr-collaboration-10" width="42">
-<img src="src/all-badges/pr-collaboration/pr-collaboration-15.png" alt="pr-collaboration-15" width="42">
-<img src="src/all-badges/pr-collaboration/pr-collaboration-20.png" alt="pr-collaboration-20" width="42">
-<img src="src/all-badges/pr-collaboration/pr-collaboration-25.png" alt="pr-collaboration-25" width="42">
-<img src="src/all-badges/public-keys/public-keys-1.png" alt="public-keys-1" width="42">
-<img src="src/all-badges/public-keys/public-keys-2.png" alt="public-keys-2" width="42">
-<img src="src/all-badges/public-keys/public-keys-3.png" alt="public-keys-3" width="42">
-<img src="src/all-badges/public-keys/public-keys-4.png" alt="public-keys-4" width="42">
-<img src="src/all-badges/public-keys/public-keys-5.png" alt="public-keys-5" width="42">
-<img src="src/all-badges/old-issue/old-issue-1.png" alt="old-issue-1" width="42">
-<img src="src/all-badges/old-issue/old-issue-2.png" alt="old-issue-2" width="42">
-<img src="src/all-badges/old-issue/old-issue-3.png" alt="old-issue-3" width="42">
-<img src="src/all-badges/old-issue/old-issue-4.png" alt="old-issue-4" width="42">
-<img src="src/all-badges/old-issue/old-issue-5.png" alt="old-issue-5" width="42">
-<img src="src/all-badges/old-issue/old-issue-6.png" alt="old-issue-6" width="42">
-<img src="src/all-badges/old-issue/old-issue-7.png" alt="old-issue-7" width="42">
-<img src="src/all-badges/old-issue/old-issue-8.png" alt="old-issue-8" width="42">
-<img src="src/all-badges/old-issue/old-issue-9.png" alt="old-issue-9" width="42">
-<img src="src/all-badges/old-issue/old-issue-10.png" alt="old-issue-10" width="42">
-<img src="src/all-badges/this-is-fine/this-is-fine.png" alt="this-is-fine" width="42">
-<img src="src/all-badges/the-ultimate-question/the-ultimate-question.png" alt="the-ultimate-question" width="42">
-<img src="src/all-badges/favorite-word/favorite-word.png" alt="favorite-word" width="42">
-<img src="src/all-badges/polite-coder/polite-coder.png" alt="polite-coder" width="42">
-<img src="src/all-badges/polite-coder/rebel-coder.png" alt="rebel-coder" width="42">
-<img src="src/all-badges/emoji-only-commit/emoji-only-commit.png" alt="emoji-only-commit" width="42">
-<img src="src/all-badges/spooky-commit/spooky-commit.png" alt="spooky-commit" width="42">
+<img src="badges/abc-commit/a-commit.png" alt="a-commit" width="64">
+<img src="badges/stars/stars-20000.png" alt="stars-20000" width="64">
+<img src="badges/time-of-commit/morning-commits.png" alt="morning-commits" width="64">
+<img src="badges/github-anniversary/github-anniversary-5.png" alt="github-anniversary-5" width="64">
+<img src="badges/dead-commit/dead-commit.png" alt="dead-commit" width="64">
+<img src="badges/bad-words/bad-words.png" alt="bad-words" width="64">
+<img src="badges/my-badges-contributor/my-badges-contributor.png" alt="my-badges-contributor" width="64">
+<img src="badges/delorean/delorean.png" alt="delorean" width="64">
+<img src="badges/covid-19/covid-19.png" alt="covid-19" width="64">
+<img src="badges/pr-collaboration/pr-collaboration-5.png" alt="pr-collaboration-5" width="64">
+<img src="badges/public-keys/public-keys-1.png" alt="public-keys-1" width="64">
+<img src="badges/old-issue/old-issue-1.png" alt="old-issue-1" width="64">
+<img src="badges/this-is-fine/this-is-fine.png" alt="this-is-fine" width="64">
+<img src="badges/the-ultimate-question/the-ultimate-question.png" alt="the-ultimate-question" width="64">
+<img src="badges/favorite-word/favorite-word.png" alt="favorite-word" width="64">
+<img src="badges/spooky-commit/spooky-commit.png" alt="spooky-commit" width="64">
+<img src="badges/cosmetic-commit/cosmetic-commit.png" alt="cosmetic-commit" width="64">
</p>
## Installation
tsconfig.json
@@ -7,7 +7,12 @@
"strict": true,
"outDir": "./dist",
"declaration": false,
- "allowJs": true
+ "allowJs": true,
+ "paths": {
+ "#src": ["./src/index.ts"],
+ "#badges": ["./badges/index.ts"],
+ "#badges/*": ["./badges/*"]
+ }
},
- "include": ["./src/**/*"]
+ "include": ["./src/**/*", "./badges/**/*"]
}