turbo-editors/turbo-corepublic Fork 0
28d59854361aeda8541d853093e732126f3d7bff
Commits
Clone
git clone https://git.rickub.com/turbo-editors/turbo-core.git
git clone ssh://git@rickub.com/turbo-editors/turbo-core.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

🛟 Updated. 28d5985 · on 28d59854361aeda8541d853093e732126f3d7bff · k33g · 13h ago
javascript_test.go · 118 lines · 4.2 KBGo Blame HistoryRaw
  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)
}