Skip to content

Commit

Permalink
forbid invalid numbers in json files
Browse files Browse the repository at this point in the history
  • Loading branch information
evanw committed Dec 13, 2022
1 parent b69ad87 commit a98ba36
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 4 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@

Node has a feature called [subpath imports](https://nodejs.org/api/packages.html#subpath-imports) where special import paths that start with `#` are resolved using the `imports` field in the `package.json` file of the enclosing package. The intent of the newly-added `--packages=external` setting is to exclude a package's dependencies from the bundle. Since a package's subpath imports are only accessible within that package, it's wrong for them to be affected by `--packages=external`. This release changes esbuild so that `--packages=external` no longer affects subpath imports.

* Forbid invalid numbers in JSON files

Previously esbuild parsed numbers in JSON files using the same syntax as JavaScript. But starting from this release, esbuild will now parse them with JSON syntax instead. This means the following numbers are no longer allowed by esbuild in JSON files:

* Legacy octal literals (non-zero integers starting with `0`)
* The `0b`, `0o`, and `0x` numeric prefixes
* Numbers containing `_` such as `1_000`
* Leading and trailing `.` such as `0.` and `.0`
* Numbers with a space after the `-` such as `- 1`

## 0.16.5

* Make it easy to exclude all packages from a bundle ([#1958](https://github.com/evanw/esbuild/issues/1958), [#1975](https://github.com/evanw/esbuild/issues/1975), [#2164](https://github.com/evanw/esbuild/issues/2164), [#2246](https://github.com/evanw/esbuild/issues/2246), [#2542](https://github.com/evanw/esbuild/issues/2542))
Expand Down
14 changes: 13 additions & 1 deletion internal/js_lexer/js_lexer.go
Original file line number Diff line number Diff line change
Expand Up @@ -1218,6 +1218,9 @@ func (lexer *Lexer) Next() {
lexer.Token = TMinusMinus
default:
lexer.Token = TMinus
if lexer.json.parse && lexer.codePoint != '.' && (lexer.codePoint < '0' || lexer.codePoint > '9') {
lexer.Unexpected()
}
}

case '*':
Expand Down Expand Up @@ -1722,6 +1725,7 @@ func (lexer *Lexer) parseNumericLiteralOrDot() {
underscoreCount := 0
lastUnderscoreEnd := 0
hasDotOrExponent := first == '.'
isMissingDigitAfterDot := false
base := 0.0
lexer.IsLegacyOctalLiteral = false

Expand Down Expand Up @@ -1889,8 +1893,11 @@ func (lexer *Lexer) parseNumericLiteralOrDot() {
if lexer.codePoint == '_' {
lexer.SyntaxError()
}
isMissingDigitAfterDot = true
for {
if lexer.codePoint < '0' || lexer.codePoint > '9' {
if lexer.codePoint >= '0' && lexer.codePoint <= '9' {
isMissingDigitAfterDot = false
} else {
if lexer.codePoint != '_' {
break
}
Expand Down Expand Up @@ -1994,6 +2001,11 @@ func (lexer *Lexer) parseNumericLiteralOrDot() {
if js_ast.IsIdentifierStart(lexer.codePoint) {
lexer.SyntaxError()
}

// None of these are allowed in JSON
if lexer.json.parse && (first == '.' || base != 0 || underscoreCount > 0 || isMissingDigitAfterDot) {
lexer.Unexpected()
}
}

func (lexer *Lexer) ScanRegExp() {
Expand Down
22 changes: 19 additions & 3 deletions internal/js_parser/json_parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,13 +133,29 @@ func TestJSONNumber(t *testing.T) {
expectPrintedJSON(t, "-0", "-0")
expectPrintedJSON(t, "123", "123")
expectPrintedJSON(t, "123.456", "123.456")
expectPrintedJSON(t, ".123", ".123")
expectPrintedJSON(t, "-.123", "-.123")
expectPrintedJSON(t, "123e20", "123e20")
expectPrintedJSON(t, "123e-20", "123e-20")
expectParseErrorJSON(t, "123.", "<stdin>: ERROR: Unexpected \"123.\" in JSON\n")
expectParseErrorJSON(t, "-123.", "<stdin>: ERROR: Unexpected \"123.\" in JSON\n")
expectParseErrorJSON(t, ".123", "<stdin>: ERROR: Unexpected \".123\" in JSON\n")
expectParseErrorJSON(t, "-.123", "<stdin>: ERROR: Unexpected \".123\" in JSON\n")
expectParseErrorJSON(t, "NaN", "<stdin>: ERROR: Unexpected \"NaN\" in JSON\n")
expectParseErrorJSON(t, "Infinity", "<stdin>: ERROR: Unexpected \"Infinity\" in JSON\n")
expectParseErrorJSON(t, "-Infinity", "<stdin>: ERROR: Expected number in JSON but found \"Infinity\"\n")
expectParseErrorJSON(t, "-Infinity", "<stdin>: ERROR: Unexpected \"-\" in JSON\n")
expectParseErrorJSON(t, "+1", "<stdin>: ERROR: Unexpected \"+\" in JSON\n")
expectParseErrorJSON(t, "- 1", "<stdin>: ERROR: Unexpected \"-\" in JSON\n")
expectParseErrorJSON(t, "01", "<stdin>: ERROR: Unexpected \"01\" in JSON\n")
expectParseErrorJSON(t, "0b1", "<stdin>: ERROR: Unexpected \"0b1\" in JSON\n")
expectParseErrorJSON(t, "0o1", "<stdin>: ERROR: Unexpected \"0o1\" in JSON\n")
expectParseErrorJSON(t, "0x1", "<stdin>: ERROR: Unexpected \"0x1\" in JSON\n")
expectParseErrorJSON(t, "0n", "<stdin>: ERROR: Unexpected \"0n\" in JSON\n")
expectParseErrorJSON(t, "-01", "<stdin>: ERROR: Unexpected \"01\" in JSON\n")
expectParseErrorJSON(t, "-0b1", "<stdin>: ERROR: Unexpected \"0b1\" in JSON\n")
expectParseErrorJSON(t, "-0o1", "<stdin>: ERROR: Unexpected \"0o1\" in JSON\n")
expectParseErrorJSON(t, "-0x1", "<stdin>: ERROR: Unexpected \"0x1\" in JSON\n")
expectParseErrorJSON(t, "-0n", "<stdin>: ERROR: Expected number in JSON but found \"0n\"\n")
expectParseErrorJSON(t, "1_2", "<stdin>: ERROR: Unexpected \"1_2\" in JSON\n")
expectParseErrorJSON(t, "1.e2", "<stdin>: ERROR: Unexpected \"1.e2\" in JSON\n")
}

func TestJSONObject(t *testing.T) {
Expand Down

0 comments on commit a98ba36

Please sign in to comment.