1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
|
import twas from 'twas';
import cache from 'webext-storage-cache';
import React from 'dom-chef';
import select from 'select-dom';
import RepoIcon from 'octicon/repo.svg';
import elementReady from 'element-ready';
import * as pageDetect from 'github-url-detection';
import features from '.';
import * as api from '../github-helpers/api';
import {getRepoGQL, getRepo} from '../github-helpers';
const dateFormatter = new Intl.DateTimeFormat('en-US', {
year: 'numeric',
month: 'long',
day: 'numeric'
});
const getRepoAge = async (commitSha: string, commitsCount: number): Promise<[committedDate: string, resourcePath: string]> => {
const {repository} = await api.v4(`
repository(${getRepoGQL()}) {
defaultBranchRef {
target {
... on Commit {
history(first: 5, after: "${commitSha} ${commitsCount - Math.min(6, commitsCount)}") {
nodes {
committedDate
resourcePath
}
}
}
}
}
}
`);
const {committedDate, resourcePath} = repository.defaultBranchRef.target.history.nodes
.reverse()
// Filter out any invalid commit dates #3185
.find((commit: AnyObject) => new Date(commit.committedDate).getFullYear() > 1970);
return [committedDate, resourcePath];
};
const getFirstCommit = cache.function(async (): Promise<[committedDate: string, resourcePath: string]> => {
const {repository} = await api.v4(`
repository(${getRepoGQL()}) {
defaultBranchRef {
target {
... on Commit {
oid
committedDate
resourcePath
history {
totalCount
}
}
}
}
}
`);
const {oid: commitSha, history, committedDate, resourcePath} = repository.defaultBranchRef.target;
const commitsCount = history.totalCount;
if (commitsCount === 1) {
return [committedDate, resourcePath];
}
return getRepoAge(commitSha, commitsCount);
}, {
cacheKey: () => __filebasename + ':' + getRepo()!.nameWithOwner
});
async function init(): Promise<void> {
const [firstCommitDate, firstCommitHref] = await getFirstCommit()!;
const date = new Date(firstCommitDate);
// `twas` could also return `an hour ago` or `just now`
const [value, unit] = twas(date.getTime())
.replace('just now', '1 second')
.replace(/^an?/, '1')
.split(' ');
// TODO: simplify selector after https://github.com/sindresorhus/element-ready/issues/29
const secondSidebarSection = await elementReady('.repository-content .BorderGrid-row + .BorderGrid-row');
if (secondSidebarSection) {
const sidebarAboutSection = secondSidebarSection.previousElementSibling!;
select('.BorderGrid-cell', sidebarAboutSection)!.append(
<h3 className="sr-only">Repository age</h3>,
<div className="mt-3">
<a href={firstCommitHref} className="muted-link" title={`First commit dated ${dateFormatter.format(date)}`}>
<RepoIcon className="mr-2"/> {value} {unit} old
</a>
</div>
);
return;
}
// Pre "Repository refresh" layout
const element = (
<li className="text-gray" title={`First commit dated ${dateFormatter.format(date)}`}>
<a href={firstCommitHref}>
<RepoIcon/> <span className="num text-emphasized">{value}</span> {unit} old
</a>
</li>
);
const license = select('.numbers-summary .octicon-law');
if (license) {
license.closest('li')!.before(element);
} else {
select('.numbers-summary')!.append(element);
}
}
void features.add(__filebasename, {
include: [
pageDetect.isRepoRoot
],
exclude: [
pageDetect.isEmptyRepoRoot
],
awaitDomReady: false,
init
});
|