Skip to content

Commit 84f5875

Browse files
feat: warnings code popup (#317)
1 parent dd8e7ed commit 84f5875

5 files changed

Lines changed: 150 additions & 16 deletions

File tree

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@
9595
"cacache": "^18.0.0",
9696
"dotenv": "^16.3.1",
9797
"filenamify": "^6.0.0",
98+
"highlightjs-line-numbers.js": "^2.8.0",
9899
"ini": "^4.1.1",
99100
"kleur": "^4.1.5",
100101
"ms": "^2.1.3",

public/components/package/pannels/warnings/code-fetcher.js

Lines changed: 74 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,27 @@
1+
import hljs from "highlight.js/lib/core";
2+
window.hljs = hljs;
3+
require("highlightjs-line-numbers.js/dist/highlightjs-line-numbers.min.js");
4+
15
// CONSTANTS
26
const kLoadingMessage = "Loading ...";
37

8+
function removeTags(str) {
9+
if ((str === null) || (str === "")) {
10+
return false;
11+
}
12+
// eslint-disable-next-line no-param-reassign
13+
str = str.toString();
14+
15+
return str.replace(/<\/?[^>]+(>|$)/ig, "");
16+
}
17+
418
export class CodeFetcher {
519
static setupDocumentClickHandler = true;
620

721
static getLineFromFile(code, location) {
822
const [[startLine]] = location;
923

10-
return code.split("\n")[startLine - 1];
24+
return code.split("\n").slice(startLine >= 10 ? startLine - 10 : 0, startLine + 10).join("\n");
1125
}
1226

1327
static hide(event) {
@@ -17,12 +31,12 @@ export class CodeFetcher {
1731
}
1832

1933
if (
20-
(packageCodeElement.innerHTML && packageCodeElement.innerHTML !== kLoadingMessage) &&
34+
(packageCodeElement.innerText && packageCodeElement.innerText !== kLoadingMessage) &&
2135
!packageCodeElement.contains(event.target)
2236
&& packageCodeElement.style.visibility === "visible"
2337
) {
2438
packageCodeElement.style.visibility = "hidden";
25-
packageCodeElement.innerHTML = "";
39+
packageCodeElement.innerText = "";
2640
}
2741
}
2842

@@ -37,13 +51,16 @@ export class CodeFetcher {
3751
}
3852

3953
async fetchCodeLine(event, options = {}) {
40-
const { file, location, id } = options;
54+
const { file, location, id, value } = options;
4155

4256
this.container = document.querySelector(".package-code");
4357
this.container.style.visibility = "visible";
58+
const isJS = file.slice(-3) === ".js" || [".cjs", ".mjs"].includes(file.slice(-4));
59+
const isJSON = file.slice(-5) === ".json";
4460

4561
if (this.cache.has(id)) {
46-
this.container.innerText = this.cache.get(id);
62+
this.container.innerHTML = this.cache.get(id);
63+
hljs.initLineNumbersOnLoad();
4764
event.stopPropagation();
4865

4966
return;
@@ -52,10 +69,58 @@ export class CodeFetcher {
5269
this.container.innerText = kLoadingMessage;
5370
const code = await fetch(`${this.unpkgRoot}${file}`).then((response) => response.text());
5471

55-
this.container.innerText = code.length ?
56-
CodeFetcher.getLineFromFile(code, location) :
57-
"Line not found ...";
58-
this.cache.set(id, this.container.innerText);
72+
if (code.length) {
73+
this.container.innerText = "";
74+
75+
const titleElement = document.createElement("div");
76+
titleElement.classList.add("file");
77+
titleElement.innerHTML = `<a href="${this.unpkgRoot}${file}" target="_blank">${file}</a>`;
78+
79+
const preElement = document.createElement("pre");
80+
preElement.appendChild(titleElement);
81+
82+
const codeElement = document.createElement("code");
83+
codeElement.textContent = CodeFetcher.getLineFromFile(code, location);
84+
// eslint-disable-next-line no-nested-ternary
85+
codeElement.classList.add(`language-${isJS ? "js" : isJSON ? "json" : "text"}`, "hljs");
86+
codeElement.setAttribute("data-ln-start-from", location[0][0] >= 10 ? location[0][0] - 9 : 1);
87+
88+
preElement.appendChild(codeElement);
89+
this.container.appendChild(preElement);
90+
hljs.highlightElement(codeElement);
91+
hljs.initLineNumbersOnLoad();
92+
93+
// Highlight the relevant lines / code
94+
codeElement.innerHTML = codeElement.innerHTML.split("\n").map((line, index) => {
95+
const withoutTags = removeTags(line);
96+
if (withoutTags === false) {
97+
return line;
98+
}
99+
const incriminedCodeSingleLine = code.split("\n").slice(location[0][0] - 1, location[0][0]);
100+
const isMultiLine = location[0][0] < location[1][0];
101+
const [[startLine]] = location;
102+
const lineIndex = startLine >= 10 ? 9 : startLine - 1;
103+
const isRelevantLine = isMultiLine ?
104+
lineIndex <= index && index <= location[1][0] - 1 :
105+
// eslint-disable-next-line max-len
106+
incriminedCodeSingleLine.includes(value) || (!isMultiLine && lineIndex === index && withoutTags.includes(value)) || (!value && lineIndex === index);
107+
108+
if (isRelevantLine) {
109+
if (!isMultiLine && value && line.includes(value)) {
110+
return line.replace(value, `<span class="relevant-line">${value}</span>`);
111+
}
112+
113+
return `<span class="relevant-line">${line}</span>`;
114+
}
115+
116+
return line;
117+
}).join("\n");
118+
}
119+
else {
120+
this.container.innerText = "Line not found ...";
121+
}
122+
123+
this.cache.set(id, this.container.innerHTML);
59124

60125
event.stopPropagation();
61126
}

public/components/package/pannels/warnings/warnings.css

Lines changed: 73 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,85 @@
55
min-width: 120px;
66
max-width: 600px;
77
max-height: 300px;
8-
overflow-y: auto;
8+
left: calc(50% + 500px);
99
top: 50%;
10-
left: 50%;
11-
transform: translate(-50%);
12-
background: #191919;
13-
border: 1px solid #121212;
10+
transform: translate(-50%, -50%);
1411
color: #FFF;
15-
padding: 10px;
1612
border-radius: 4px;
1713
text-align: left;
1814
font-size: 14px;
1915
font-family: "mononoki";
2016
letter-spacing: 0.5px;
2117
word-wrap: break-word;
2218
}
19+
20+
.package-code pre {
21+
background: white;
22+
margin: 0;
23+
padding: 0;
24+
box-shadow: 0px 5px 3px rgba(0, 0, 0, 0.2);
25+
}
26+
27+
.package-code code {
28+
scrollbar-width: thin;
29+
}
30+
31+
.package-code pre code.hljs {
32+
padding-top: 0;
33+
}
34+
35+
.package-code pre div.file {
36+
padding: 8px;
37+
text-align: right;
38+
background: linear-gradient(to right, rgba(255,255,255,0) 0%,rgba(232,232,232,1) 100%);
39+
margin-bottom: 5px;
40+
}
41+
42+
43+
.package-code pre div a {
44+
color: var(--secondary-darker);
45+
}
46+
47+
.relevant-line {
48+
background: rgb(255 221 124 / 27%);
49+
padding: 2px 0px;
50+
}
51+
52+
.hljs-ln-numbers {
53+
-webkit-touch-callout: none;
54+
-webkit-user-select: none;
55+
-khtml-user-select: none;
56+
-moz-user-select: none;
57+
-ms-user-select: none;
58+
user-select: none;
59+
60+
text-align: center;
61+
color: #ccc;
62+
border-right: 1px solid #CCC;
63+
vertical-align: top;
64+
padding-right: 10px !important;
65+
}
66+
67+
.hljs-ln-code {
68+
padding-left: 10px;
69+
}
70+
71+
.hljs-ln-n {
72+
text-align: right;
73+
}
74+
75+
.package-code table, .package-code table tr {
76+
width: auto;
77+
background: white;
78+
height: auto;
79+
line-height: normal;
80+
}
81+
82+
.package-code table tr, .package-code table td {
83+
border: none;
84+
padding: 0;
85+
text-align: left;
86+
height: auto;
87+
line-height: normal;
88+
}
89+

public/components/package/pannels/warnings/warnings.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ export class Warnings {
7878
const location = warning.kind === "encoded-literal" ? warning.location[0] : warning.location;
7979

8080
viewMoreElement.addEventListener("click", (event) => {
81-
codeFetcher.fetchCodeLine(event, { file: warning.file, location, id });
81+
codeFetcher.fetchCodeLine(event, { file: warning.file, location, id, value: warning.value });
8282
});
8383
}
8484

public/main.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ body {
3333

3434
::-webkit-scrollbar {
3535
width: 8px;
36+
height: 8px;
3637
border-radius: 4px;
3738
}
3839

0 commit comments

Comments
 (0)