-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcontent.js
More file actions
97 lines (89 loc) · 3.43 KB
/
Copy pathcontent.js
File metadata and controls
97 lines (89 loc) · 3.43 KB
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
const DOMAIN_REGEX = /([^\.]+)\.\w+$/
function handleResponse(request, graphql, resolve, reject) {
if (request.readyState == 4) {
if (request.status != 200) {
reject()
} else if (graphql) {
const body = JSON.parse(request.responseText)
if (body.errors?.length > 0) {
reject()
} else {
resolve(body.data)
}
} else {
resolve(JSON.parse(request.responseText))
}
}
}
function getData(host, authorization, resource) {
return new Promise((resolve, reject) => {
const graphql = host.endsWith('/graphql')
const request = new XMLHttpRequest()
request.onreadystatechange = () => handleResponse(request, graphql, resolve, reject)
if (graphql) {
request.open('POST', host, true)
request.setRequestHeader('Authorization', authorization)
request.setRequestHeader('Content-Type', 'application/json')
request.send(`{ "query": "{ ${resource.replace(/\s+/g, ' ').replace(/"/g, '\\"')} }" }`)
} else {
request.open('GET', `${host}${resource}`, true)
request.setRequestHeader('Authorization', authorization)
request.send()
}
})
}
function appendStat(element, id, value, css) {
const span = document.createElement('span')
span.id = id
span.textContent = value
if (css.styles) {
span.style = css.styles[id]
} else {
span.className = css.classes[id]
}
element.append(span)
}
function updateStat(element, id, value) {
element.querySelector(`[id="${id}"]`).textContent = value
}
function injectStats(parent, stats, css, getParentNode) {
let element = parent.querySelector('[id="stats"]')
if (!element) {
element = document.createElement(css.type)
element.id = 'stats'
element.colSpan = 3
appendStat(element, 'files', stats.files, css)
appendStat(element, 'additions', '+' + stats.additions, css)
appendStat(element, 'deletions', '-' + stats.deletions, css)
getParentNode(parent).append(element)
} else {
updateStat(element, 'files', stats.files)
updateStat(element, 'additions', '+' + stats.additions)
updateStat(element, 'deletions', '-' + stats.deletions)
}
}
async function run() {
const [, domain] = document.location.hostname.match(DOMAIN_REGEX)
const { default: source } = await import(chrome.runtime.getURL(`sources/${domain}.js`))
const match = document.location.pathname.replace(/\/$/, '').match(source.pathRegex)
const { tokens } = await chrome.storage.sync.get('tokens')
const token = tokens?.[domain]
if (!match || !token) {
return
}
const authorization = `${source.auth} ${token}`
const elements = await source.getElements(document)
const promises = []
for (const element of elements) {
const resource = source.getResource(element, match)
const promise = getData(source.host, authorization, resource)
.then((data) => source.parseResponse(data))
.then((stats) => injectStats(element, stats, source.css, source.getParentNode))
promises.push(promise)
}
await Promise.all(promises)
.then(() => chrome.runtime.sendMessage({ success: true, domain }))
.catch(() => chrome.runtime.sendMessage({ success: false, domain }))
}
chrome.runtime.onMessage.addListener(run)
run()