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  }