This repository was archived by the owner on Aug 14, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.ts
More file actions
127 lines (113 loc) · 4.33 KB
/
index.ts
File metadata and controls
127 lines (113 loc) · 4.33 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
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
127
import type { Diagnostic, FormatDiagnosticsHost } from 'typescript'
import type { PlaygroundPlugin, PluginUtils } from "./vendor/playground"
const EOL = '\n'
function getRelatedPosts(keyword: string) {
// https://api.stackexchange.com/docs/search
const endpoint = 'https://api.stackexchange.com/2.2/search/advanced'
const query = new URLSearchParams()
query.set('site', 'stackoverflow')
query.set('sort', 'votes')
query.set('order', 'desc')
query.set('accepted', 'True')
query.set('pagesize', '10')
query.set('q', 'typescript ' + keyword)
return fetch(`${endpoint}?${query.toString()}`).then(res => res.json()).then(res => res.items)
}
function formatErroredCode(code: string, diagnostic: Diagnostic): string {
const lineNumber = code.slice(0, diagnostic.start).split(EOL).length
const lineStarts = code.lastIndexOf(EOL, diagnostic.start) + 1
const lineEnds = code.indexOf(EOL, diagnostic.start)
const line = code.slice(lineStarts, lineEnds)
const offset = diagnostic.start - lineStarts
const underline = ' '.repeat(String(lineNumber).length) + ' ' + ' '.repeat(offset) + '^'.repeat(diagnostic.length)
return `${lineNumber}: ${line}\n${underline}`
}
const formatDiagnosticHost: FormatDiagnosticsHost = {
getCurrentDirectory() {
return ''
},
getCanonicalFileName(fileName: string) {
return fileName
},
getNewLine() {
return EOL
}
}
export default (utils: PluginUtils): PlaygroundPlugin => {
let postListContainer: HTMLDivElement
return {
id: 'plugin-stackoverflow',
displayName: 'Stack overflow',
shouldBeSelected: () => true,
didMount(_sandbox, container) {
utils.el('StackOverflow post similar to these errors', 'h4', container)
postListContainer = document.createElement('div')
container.append(postListContainer)
},
modelChangedDebounce(sandbox, model) {
if (!postListContainer) {
return
}
const { ts } = sandbox
const statusContainer = document.createElement('pre')
postListContainer.textContent = ''
postListContainer.append(statusContainer)
if (!sandbox.getText()) {
statusContainer.textContent = 'No errors!!'
return
}
statusContainer.textContent = 'Just minutes...'
Promise.all([
sandbox.getWorkerProcess()
]).then(([worker]) =>
Promise.all([
worker.getSemanticDiagnostics(model.uri.toString()),
worker.getSyntacticDiagnostics(model.uri.toString()),
])
)
.then(([semanticDiagnostics, syntacticDiagnostics]) =>
semanticDiagnostics.concat(syntacticDiagnostics)
)
.then(diagnostics => {
if (diagnostics.length === 0) {
statusContainer.textContent = 'No errors!!'
return
}
statusContainer.textContent = 'Fetching posts...'
const text = sandbox.getText()
return Promise.all(diagnostics.map(d => {
const similarPostsContainer = document.createElement('div')
const errorContainer = document.createElement('pre')
const erroredCode = formatErroredCode(text, d)
const errorMessage = ts.formatDiagnostic(d, formatDiagnosticHost)
errorContainer.textContent = erroredCode + '\n' + errorMessage
errorContainer.style.whiteSpace = 'break-spaces'
similarPostsContainer.append(errorContainer)
return getRelatedPosts(d.messageText.toString()).then(relatedPosts => {
const elements = relatedPosts.map(relatedPost => {
const li = document.createElement('li')
const a = document.createElement('a')
a.target = '_blank'
a.rel = 'noopener'
a.href = relatedPost.link
a.textContent = relatedPost.title
li.append(a)
return li
})
similarPostsContainer.append(...elements)
return similarPostsContainer
})
}))
})
.then(similarPostsList => {
postListContainer.append(...similarPostsList)
postListContainer.removeChild(statusContainer)
})
.catch(e => {
statusContainer.style.backgroundColor = 'oldlace'
statusContainer.style.color = 'crimson'
statusContainer.textContent = e.stack
})
},
}
}