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
|
package syntax
import "testing"
// wantJS is wantLine for JavaScript.
func wantJS(t *testing.T, src string, line int, want ...string) {
t.Helper()
wantLine(t, LanguageJavaScript, src, line, want...)
}
func TestJavaScriptColoursKeywords(t *testing.T) {
wantJS(t, "const x = 1", 0,
"const:keyword", "x:identifier", "=:operator", "1:number")
wantJS(t, "async function f() {}", 0,
"async:keyword", "function:keyword", "f:function",
"(:punctuation", "):punctuation", "{:punctuation", "}:punctuation")
}
func TestJavaScriptColoursConstantsAndGlobals(t *testing.T) {
wantJS(t, "x = true", 0, "x:identifier", "=:operator", "true:constant")
wantJS(t, "x = null", 0, "x:identifier", "=:operator", "null:constant")
wantJS(t, "console.log(1)", 0,
"console:builtin", ".:punctuation", "log:function",
"(:punctuation", "1:number", "):punctuation")
}
func TestANameBeforeAParenthesisIsACall(t *testing.T) {
wantJS(t, "doThing()", 0, "doThing:function", "(:punctuation", "):punctuation")
wantJS(t, "doThing", 0, "doThing:identifier")
}
func TestJavaScriptColoursStrings(t *testing.T) {
wantJS(t, `x = "double"`, 0, "x:identifier", "=:operator", `"double":string`)
wantJS(t, "x = 'single'", 0, "x:identifier", "=:operator", "'single':string")
}
func TestAnEscapedQuoteDoesNotEndAJavaScriptString(t *testing.T) {
wantJS(t, `x = "he said \"no\""`, 0, "x:identifier", "=:operator", `"he said \"no\"":string`)
}
func TestAnUnterminatedJavaScriptStringIsColouredToTheEndOfTheLine(t *testing.T) {
wantJS(t, `x = "half written`, 0, "x:identifier", "=:operator", `"half written:string`)
}
func TestJavaScriptColoursLineAndBlockComments(t *testing.T) {
wantJS(t, "x = 1 // a note", 0,
"x:identifier", "=:operator", "1:number", "// a note:comment")
wantJS(t, "x = /* inline */ 1", 0,
"x:identifier", "=:operator", "/* inline */:comment", "1:number")
}
func TestABlockCommentCarriesAcrossLines(t *testing.T) {
src := "/* first\n second\n third */ x = 1"
wantJS(t, src, 0, "/* first:comment")
wantJS(t, src, 1, " second:comment")
wantJS(t, src, 2, " third */:comment", "x:identifier", "=:operator", "1:number")
}
func TestCodeInsideABlockCommentIsNotColoured(t *testing.T) {
src := "/*\nconst x = 1\n*/"
wantJS(t, src, 1, "const x = 1:comment")
}
func TestJavaScriptColoursTemplateLiterals(t *testing.T) {
wantJS(t, "x = `plain`", 0, "x:identifier", "=:operator", "`plain`:string")
wantJS(t, "x = `a ${b} c`", 0, "x:identifier", "=:operator", "`a ${b} c`:string")
}
func TestATemplateLiteralCarriesAcrossLines(t *testing.T) {
src := "const html = `\n <p>hi</p>\n`\nconst x = 1"
wantJS(t, src, 1, " <p>hi</p>:string")
wantJS(t, src, 2, "`:string")
// The line after it is code again.
wantJS(t, src, 3, "const:keyword", "x:identifier", "=:operator", "1:number")
}
func TestJavaScriptColoursNumbers(t *testing.T) {
for _, value := range []string{"42", "3.14", "0x1f", "0b1010", "0o777", "1_000_000", "1e6", "10n"} {
t.Run(value, func(t *testing.T) {
got := spansOf(t, LanguageJavaScript, "x = "+value, 0)
if last := got[len(got)-1]; last != value+":number" {
t.Errorf("%q was coloured %q, want a number", value, last)
}
})
}
}
func TestJavaScriptTakesOperatorsInRuns(t *testing.T) {
wantJS(t, "a === b", 0, "a:identifier", "===:operator", "b:identifier")
wantJS(t, "a ?? b", 0, "a:identifier", "??:operator", "b:identifier")
wantJS(t, "a => b", 0, "a:identifier", "=>:operator", "b:identifier")
}
func TestARegexIsLeftAsOperatorsRatherThanGuessedAt(t *testing.T) {
// Telling /x/g from a division needs to know whether the previous token
// could end an expression. Getting it wrong colours the rest of the line
// as a string, which is worse than this.
got := spansOf(t, LanguageJavaScript, "x = /ab/g", 0)
for _, span := range got {
if len(span) > 7 && span[len(span)-7:] == ":string" {
t.Errorf("a regex was guessed at as a string: %v", got)
}
}
}
func TestJavaScriptGivesOneEntryPerLine(t *testing.T) {
if got := len(Highlight(LanguageJavaScript, "a\nb\n\nc\n")); got != 5 {
t.Errorf("Highlight() returned %d lines for a 5-line document", got)
}
}
func TestJavaScriptSpansStayInsideTheirLine(t *testing.T) {
src := "import { a } from 'b'\n/* c\nd */\nconst t = `x${y}z`\nconsole.log(0x1f)\n"
assertSpansFit(t, LanguageJavaScript, src)
}
|