Skip to content

Commit d8f9dfd

Browse files
Fix escaping HTML
1 parent c6e83fe commit d8f9dfd

File tree

16 files changed

+602
-618
lines changed

16 files changed

+602
-618
lines changed

Public/js/app.js

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -127,13 +127,7 @@ export class App {
127127
.then((response) => response.json())
128128
.then((response) => {
129129
this.response = response;
130-
this.structureData = JSON.parse(
131-
response.syntaxJSON
132-
.replace(/&/g, "&")
133-
.replace(/</g, "&lt;")
134-
.replace(/>/g, "&gt;")
135-
.replace(/'/g, "&#039;")
136-
);
130+
this.structureData = JSON.parse(response.syntaxJSON);
137131

138132
this.updateStructure();
139133
this.updateLookup();

Public/js/structure_view.js

Lines changed: 7 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -98,18 +98,10 @@ function makeTokenPopoverContent(data) {
9898

9999
makeSourceRangePopoverContent(data, dl);
100100

101-
makeDescriptionList("kind", stripHTMLTag(data.token.kind), dl);
102-
makeDescriptionList(
103-
"leadingTrivia",
104-
stripHTMLTag(data.token.leadingTrivia),
105-
dl
106-
);
107-
makeDescriptionList("text", stripHTMLTag(data.text), dl);
108-
makeDescriptionList(
109-
"trailingTrivia",
110-
stripHTMLTag(data.token.trailingTrivia),
111-
dl
112-
);
101+
makeDescriptionList("kind", data.token.kind, dl);
102+
makeDescriptionList("leadingTrivia", data.token.leadingTrivia, dl);
103+
makeDescriptionList("text", data.text, dl);
104+
makeDescriptionList("trailingTrivia", data.token.trailingTrivia, dl);
113105

114106
container.appendChild(dl);
115107

@@ -129,11 +121,11 @@ function makePropertyPopoverContent(property, list) {
129121
if (property.ref) {
130122
return `<span class="badge ref">${property.ref}</span>`;
131123
} else if (value && value.text && value.kind) {
132-
const text = stripHTMLTag(value.text);
133-
const kind = stripHTMLTag(value.kind);
124+
const text = value.text;
125+
const kind = value.kind;
134126
return `${text}<span class="badge rounded-pill">${kind}</span>`;
135127
} else if (value && value.text) {
136-
return stripHTMLTag(value.text);
128+
return value.text;
137129
}
138130
})();
139131
makeDescriptionList(property.name, details, list);
@@ -179,19 +171,3 @@ function makeSyntaxTypeBadge(type) {
179171
}
180172
return badge;
181173
}
182-
183-
function stripHTMLTag(text) {
184-
const div = document.createElement("div");
185-
div.innerHTML = text
186-
.replace(/&lt;/g, "<")
187-
.replace(/&gt;/g, ">")
188-
.replace(/&#039;/g, "'")
189-
.replace(/&amp;/g, "&");
190-
return escapeHTML(div.textContent || div.innerText || "");
191-
}
192-
193-
function escapeHTML(text) {
194-
const div = document.createElement("div");
195-
div.appendChild(document.createTextNode(text));
196-
return div.innerHTML;
197-
}

Sources/App/Controllers/TokenVisitor.swift

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ final class TokenVisitor: SyntaxRewriter {
129129
}
130130

131131
override func visit(_ token: TokenSyntax) -> TokenSyntax {
132-
current.text = token.text
132+
current.text = escapeHTML(token.text)
133133
current.token = Token(kind: "\(token.tokenKind)", leadingTrivia: "", trailingTrivia: "")
134134

135135
token.leadingTrivia.forEach { (piece) in
@@ -174,7 +174,7 @@ final class TokenVisitor: SyntaxRewriter {
174174
let endColumn = end.column ?? 1
175175
let text = token.presence == .present ? token.text : ""
176176
list.append(
177-
"<span class='token \(kind)' " +
177+
"<span class='token \(escapeHTML(kind))' " +
178178
"data-title='\(escapeHTML("\(token.withoutTrivia())"))' " +
179179
"data-content='\(escapeHTML("\(token.tokenKind)"))' " +
180180
"data-type='Token' " +
@@ -217,21 +217,21 @@ final class TokenVisitor: SyntaxRewriter {
217217
private func replaceSymbols(text: String) -> String {
218218
text.replacingOccurrences(of: "&nbsp;", with: "").replacingOccurrences(of: "<br>", with: "")
219219
}
220+
}
220221

221-
private func escapeHTML(_ string: String) -> String {
222-
var newString = string
223-
let specialCharacters = [
224-
("&", "&amp;"),
225-
("<", "&lt;"),
226-
(">", "&gt;"),
227-
("\"", "&quot;"),
228-
("'", "&apos;"),
229-
];
230-
for (unescaped, escaped) in specialCharacters {
231-
newString = newString.replacingOccurrences(of: unescaped, with: escaped, options: .literal, range: nil)
232-
}
233-
return newString
234-
.replacingOccurrences(of: " ", with: "&nbsp;")
235-
.replacingOccurrences(of: "\n", with: "<br>")
222+
func escapeHTML(_ string: String) -> String {
223+
var newString = string
224+
let specialCharacters = [
225+
("&", "&amp;"),
226+
("<", "&lt;"),
227+
(">", "&gt;"),
228+
("\"", "&quot;"),
229+
("'", "&apos;"),
230+
];
231+
for (unescaped, escaped) in specialCharacters {
232+
newString = newString.replacingOccurrences(of: unescaped, with: escaped, options: .literal, range: nil)
236233
}
234+
return newString
235+
.replacingOccurrences(of: " ", with: "&nbsp;")
236+
.replacingOccurrences(of: "\n", with: "<br>")
237237
}

Sources/App/Models/TreeNode.swift

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ final class TreeNode: Codable {
1212

1313
init(id: Int, text: String, range: Range, type: SyntaxType) {
1414
self.id = id
15-
self.text = text
15+
self.text = escapeHTML(text)
1616
self.range = range
1717
self.type = type
1818
}
@@ -43,9 +43,13 @@ struct StructureProperty: Codable, Equatable {
4343
let ref: String?
4444

4545
init(name: String, value: StructureValue? = nil, ref: String? = nil) {
46-
self.name = name
46+
self.name = escapeHTML(name)
4747
self.value = value
48-
self.ref = ref
48+
if let ref {
49+
self.ref = escapeHTML(ref)
50+
} else {
51+
self.ref = nil
52+
}
4953
}
5054
}
5155

@@ -54,8 +58,12 @@ struct StructureValue: Codable, Equatable {
5458
let kind: String?
5559

5660
init(text: String, kind: String? = nil) {
57-
self.text = text
58-
self.kind = kind
61+
self.text = escapeHTML(text)
62+
if let kind {
63+
self.kind = escapeHTML(kind)
64+
} else {
65+
self.kind = nil
66+
}
5967
}
6068
}
6169

@@ -72,4 +80,10 @@ struct Token: Codable, Equatable {
7280
var kind: String
7381
var leadingTrivia: String
7482
var trailingTrivia: String
83+
84+
init(kind: String, leadingTrivia: String, trailingTrivia: String) {
85+
self.kind = escapeHTML(kind)
86+
self.leadingTrivia = leadingTrivia
87+
self.trailingTrivia = trailingTrivia
88+
}
7589
}

Tests/AppTests/Fixtures/test-1-1.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@
342342
{
343343
"name": "identifier",
344344
"value": {
345-
"kind": "identifier(\"number\")",
345+
"kind": "identifier(&quot;number&quot;)",
346346
"text": "number␣"
347347
}
348348
},
@@ -368,7 +368,7 @@
368368
"structure": [],
369369
"text": "number",
370370
"token": {
371-
"kind": "identifier(\"number\")",
371+
"kind": "identifier(&quot;number&quot;)",
372372
"leadingTrivia": "",
373373
"trailingTrivia": ""
374374
},
@@ -457,7 +457,7 @@
457457
{
458458
"name": "digits",
459459
"value": {
460-
"kind": "integerLiteral(\"0\")",
460+
"kind": "integerLiteral(&quot;0&quot;)",
461461
"text": "0"
462462
}
463463
},
@@ -483,7 +483,7 @@
483483
"structure": [],
484484
"text": "0",
485485
"token": {
486-
"kind": "integerLiteral(\"0\")",
486+
"kind": "integerLiteral(&quot;0&quot;)",
487487
"leadingTrivia": "",
488488
"trailingTrivia": ""
489489
},

0 commit comments

Comments
 (0)