github.com/evanw/esbuild@v0.21.4/internal/js_parser/json_parser_test.go (about) 1 package js_parser 2 3 import ( 4 "fmt" 5 "testing" 6 7 "github.com/evanw/esbuild/internal/ast" 8 "github.com/evanw/esbuild/internal/js_ast" 9 "github.com/evanw/esbuild/internal/js_printer" 10 "github.com/evanw/esbuild/internal/logger" 11 "github.com/evanw/esbuild/internal/test" 12 ) 13 14 func expectParseErrorJSON(t *testing.T, contents string, expected string) { 15 t.Helper() 16 t.Run(contents, func(t *testing.T) { 17 t.Helper() 18 log := logger.NewDeferLog(logger.DeferLogNoVerboseOrDebug, nil) 19 ParseJSON(log, test.SourceForTest(contents), JSONOptions{}) 20 msgs := log.Done() 21 text := "" 22 for _, msg := range msgs { 23 text += msg.String(logger.OutputOptions{}, logger.TerminalInfo{}) 24 } 25 test.AssertEqualWithDiff(t, text, expected) 26 }) 27 } 28 29 // Note: The input is parsed as JSON but printed as JS. This means the printed 30 // code may not be valid JSON. That's ok because esbuild always outputs JS 31 // bundles, not JSON bundles. 32 func expectPrintedJSON(t *testing.T, contents string, expected string) { 33 t.Helper() 34 expectPrintedJSONWithWarning(t, contents, "", expected) 35 } 36 37 func expectPrintedJSONWithWarning(t *testing.T, contents string, warning string, expected string) { 38 t.Helper() 39 t.Run(contents, func(t *testing.T) { 40 t.Helper() 41 log := logger.NewDeferLog(logger.DeferLogNoVerboseOrDebug, nil) 42 expr, ok := ParseJSON(log, test.SourceForTest(contents), JSONOptions{}) 43 msgs := log.Done() 44 text := "" 45 for _, msg := range msgs { 46 text += msg.String(logger.OutputOptions{}, logger.TerminalInfo{}) 47 } 48 test.AssertEqualWithDiff(t, text, warning) 49 if !ok { 50 t.Fatal("Parse error") 51 } 52 53 // Insert this expression into a statement 54 tree := js_ast.AST{ 55 Parts: []js_ast.Part{{Stmts: []js_ast.Stmt{{Data: &js_ast.SExpr{Value: expr}}}}}, 56 } 57 58 js := js_printer.Print(tree, ast.SymbolMap{}, nil, js_printer.Options{ 59 MinifyWhitespace: true, 60 }).JS 61 62 // Remove the trailing semicolon 63 if n := len(js); n > 1 && js[n-1] == ';' { 64 js = js[:n-1] 65 } 66 67 test.AssertEqualWithDiff(t, string(js), expected) 68 }) 69 } 70 71 func TestJSONAtom(t *testing.T) { 72 expectPrintedJSON(t, "false", "false") 73 expectPrintedJSON(t, "true", "true") 74 expectPrintedJSON(t, "null", "null") 75 expectParseErrorJSON(t, "undefined", "<stdin>: ERROR: Unexpected \"undefined\" in JSON\n") 76 } 77 78 func TestJSONString(t *testing.T) { 79 expectPrintedJSON(t, "\"x\"", "\"x\"") 80 expectParseErrorJSON(t, "'x'", "<stdin>: ERROR: JSON strings must use double quotes\n") 81 expectParseErrorJSON(t, "`x`", "<stdin>: ERROR: Unexpected \"`x`\" in JSON\n") 82 83 // Newlines 84 expectPrintedJSON(t, "\"\u2028\"", "\"\\u2028\"") 85 expectPrintedJSON(t, "\"\u2029\"", "\"\\u2029\"") 86 expectParseErrorJSON(t, "\"\r\"", "<stdin>: ERROR: Unterminated string literal\n") 87 expectParseErrorJSON(t, "\"\n\"", "<stdin>: ERROR: Unterminated string literal\n") 88 89 // Control characters 90 for c := 0; c < 0x20; c++ { 91 if c != '\r' && c != '\n' { 92 expectParseErrorJSON(t, fmt.Sprintf("\"%c\"", c), 93 fmt.Sprintf("<stdin>: ERROR: Syntax error \"\\x%02X\"\n", c)) 94 } 95 } 96 97 // Valid escapes 98 expectPrintedJSON(t, "\"\\\"\"", "'\"'") 99 expectPrintedJSON(t, "\"\\\\\"", "\"\\\\\"") 100 expectPrintedJSON(t, "\"\\/\"", "\"/\"") 101 expectPrintedJSON(t, "\"\\b\"", "\"\\b\"") 102 expectPrintedJSON(t, "\"\\f\"", "\"\\f\"") 103 expectPrintedJSON(t, "\"\\n\"", "\"\\n\"") 104 expectPrintedJSON(t, "\"\\r\"", "\"\\r\"") 105 expectPrintedJSON(t, "\"\\t\"", "\"\t\"") 106 expectPrintedJSON(t, "\"\\u0000\"", "\"\\0\"") 107 expectPrintedJSON(t, "\"\\u0078\"", "\"x\"") 108 expectPrintedJSON(t, "\"\\u1234\"", "\"\u1234\"") 109 expectPrintedJSON(t, "\"\\uD800\"", "\"\\uD800\"") 110 expectPrintedJSON(t, "\"\\uDC00\"", "\"\\uDC00\"") 111 112 // Invalid escapes 113 expectParseErrorJSON(t, "\"\\", "<stdin>: ERROR: Unterminated string literal\n") 114 expectParseErrorJSON(t, "\"\\0\"", "<stdin>: ERROR: Syntax error \"0\"\n") 115 expectParseErrorJSON(t, "\"\\1\"", "<stdin>: ERROR: Syntax error \"1\"\n") 116 expectParseErrorJSON(t, "\"\\'\"", "<stdin>: ERROR: Syntax error \"'\"\n") 117 expectParseErrorJSON(t, "\"\\a\"", "<stdin>: ERROR: Syntax error \"a\"\n") 118 expectParseErrorJSON(t, "\"\\v\"", "<stdin>: ERROR: Syntax error \"v\"\n") 119 expectParseErrorJSON(t, "\"\\\n\"", "<stdin>: ERROR: Syntax error \"\\x0A\"\n") 120 expectParseErrorJSON(t, "\"\\x78\"", "<stdin>: ERROR: Syntax error \"x\"\n") 121 expectParseErrorJSON(t, "\"\\u{1234}\"", "<stdin>: ERROR: Syntax error \"{\"\n") 122 expectParseErrorJSON(t, "\"\\uG\"", "<stdin>: ERROR: Syntax error \"G\"\n") 123 expectParseErrorJSON(t, "\"\\uDG\"", "<stdin>: ERROR: Syntax error \"G\"\n") 124 expectParseErrorJSON(t, "\"\\uDEG\"", "<stdin>: ERROR: Syntax error \"G\"\n") 125 expectParseErrorJSON(t, "\"\\uDEFG\"", "<stdin>: ERROR: Syntax error \"G\"\n") 126 expectParseErrorJSON(t, "\"\\u\"", "<stdin>: ERROR: Syntax error '\"'\n") 127 expectParseErrorJSON(t, "\"\\uD\"", "<stdin>: ERROR: Syntax error '\"'\n") 128 expectParseErrorJSON(t, "\"\\uDE\"", "<stdin>: ERROR: Syntax error '\"'\n") 129 expectParseErrorJSON(t, "\"\\uDEF\"", "<stdin>: ERROR: Syntax error '\"'\n") 130 } 131 132 func TestJSONNumber(t *testing.T) { 133 expectPrintedJSON(t, "0", "0") 134 expectPrintedJSON(t, "-0", "-0") 135 expectPrintedJSON(t, "123", "123") 136 expectPrintedJSON(t, "123.456", "123.456") 137 expectPrintedJSON(t, "123e20", "123e20") 138 expectPrintedJSON(t, "123e-20", "123e-20") 139 expectParseErrorJSON(t, "123.", "<stdin>: ERROR: Unexpected \"123.\" in JSON\n") 140 expectParseErrorJSON(t, "-123.", "<stdin>: ERROR: Unexpected \"123.\" in JSON\n") 141 expectParseErrorJSON(t, ".123", "<stdin>: ERROR: Unexpected \".123\" in JSON\n") 142 expectParseErrorJSON(t, "-.123", "<stdin>: ERROR: Unexpected \".123\" in JSON\n") 143 expectParseErrorJSON(t, "NaN", "<stdin>: ERROR: Unexpected \"NaN\" in JSON\n") 144 expectParseErrorJSON(t, "Infinity", "<stdin>: ERROR: Unexpected \"Infinity\" in JSON\n") 145 expectParseErrorJSON(t, "-Infinity", "<stdin>: ERROR: Unexpected \"-\" in JSON\n") 146 expectParseErrorJSON(t, "+1", "<stdin>: ERROR: Unexpected \"+\" in JSON\n") 147 expectParseErrorJSON(t, "- 1", "<stdin>: ERROR: Unexpected \"-\" in JSON\n") 148 expectParseErrorJSON(t, "01", "<stdin>: ERROR: Unexpected \"01\" in JSON\n") 149 expectParseErrorJSON(t, "0b1", "<stdin>: ERROR: Unexpected \"0b1\" in JSON\n") 150 expectParseErrorJSON(t, "0o1", "<stdin>: ERROR: Unexpected \"0o1\" in JSON\n") 151 expectParseErrorJSON(t, "0x1", "<stdin>: ERROR: Unexpected \"0x1\" in JSON\n") 152 expectParseErrorJSON(t, "0n", "<stdin>: ERROR: Unexpected \"0n\" in JSON\n") 153 expectParseErrorJSON(t, "-01", "<stdin>: ERROR: Unexpected \"01\" in JSON\n") 154 expectParseErrorJSON(t, "-0b1", "<stdin>: ERROR: Unexpected \"0b1\" in JSON\n") 155 expectParseErrorJSON(t, "-0o1", "<stdin>: ERROR: Unexpected \"0o1\" in JSON\n") 156 expectParseErrorJSON(t, "-0x1", "<stdin>: ERROR: Unexpected \"0x1\" in JSON\n") 157 expectParseErrorJSON(t, "-0n", "<stdin>: ERROR: Expected number in JSON but found \"0n\"\n") 158 expectParseErrorJSON(t, "1_2", "<stdin>: ERROR: Unexpected \"1_2\" in JSON\n") 159 expectParseErrorJSON(t, "1.e2", "<stdin>: ERROR: Unexpected \"1.e2\" in JSON\n") 160 } 161 162 func TestJSONObject(t *testing.T) { 163 expectPrintedJSON(t, "{\"x\":0}", "({x:0})") 164 expectPrintedJSON(t, "{\"x\":0,\"y\":1}", "({x:0,y:1})") 165 expectPrintedJSONWithWarning(t, 166 "{\"x\":0,\"x\":1}", 167 "<stdin>: WARNING: Duplicate key \"x\" in object literal\n<stdin>: NOTE: The original key \"x\" is here:\n", 168 "({x:0,x:1})") 169 expectParseErrorJSON(t, "{\"x\":0,}", "<stdin>: ERROR: JSON does not support trailing commas\n") 170 expectParseErrorJSON(t, "{x:0}", "<stdin>: ERROR: Expected string in JSON but found \"x\"\n") 171 expectParseErrorJSON(t, "{1:0}", "<stdin>: ERROR: Expected string in JSON but found \"1\"\n") 172 expectParseErrorJSON(t, "{[\"x\"]:0}", "<stdin>: ERROR: Expected string in JSON but found \"[\"\n") 173 } 174 175 func TestJSONArray(t *testing.T) { 176 expectPrintedJSON(t, "[]", "[]") 177 expectPrintedJSON(t, "[1]", "[1]") 178 expectPrintedJSON(t, "[1,2]", "[1,2]") 179 expectParseErrorJSON(t, "[,]", "<stdin>: ERROR: Unexpected \",\" in JSON\n") 180 expectParseErrorJSON(t, "[,1]", "<stdin>: ERROR: Unexpected \",\" in JSON\n") 181 expectParseErrorJSON(t, "[1,]", "<stdin>: ERROR: JSON does not support trailing commas\n") 182 expectParseErrorJSON(t, "[1,,2]", "<stdin>: ERROR: Unexpected \",\" in JSON\n") 183 } 184 185 func TestJSONInvalid(t *testing.T) { 186 expectParseErrorJSON(t, "({\"x\":0})", "<stdin>: ERROR: Unexpected \"(\" in JSON\n") 187 expectParseErrorJSON(t, "{\"x\":(0)}", "<stdin>: ERROR: Unexpected \"(\" in JSON\n") 188 expectParseErrorJSON(t, "#!/usr/bin/env node\n{}", "<stdin>: ERROR: Unexpected \"#!/usr/bin/env node\" in JSON\n") 189 expectParseErrorJSON(t, "{\"x\":0}{\"y\":1}", "<stdin>: ERROR: Expected end of file in JSON but found \"{\"\n") 190 } 191 192 func TestJSONComments(t *testing.T) { 193 expectParseErrorJSON(t, "/*comment*/{}", "<stdin>: ERROR: JSON does not support comments\n") 194 expectParseErrorJSON(t, "//comment\n{}", "<stdin>: ERROR: JSON does not support comments\n") 195 expectParseErrorJSON(t, "{/*comment*/}", "<stdin>: ERROR: JSON does not support comments\n") 196 expectParseErrorJSON(t, "{//comment\n}", "<stdin>: ERROR: JSON does not support comments\n") 197 expectParseErrorJSON(t, "{}/*comment*/", "<stdin>: ERROR: JSON does not support comments\n") 198 expectParseErrorJSON(t, "{}//comment\n", "<stdin>: ERROR: JSON does not support comments\n") 199 }