openrewrite / openrewrite/rewrite

rewrite-javascript: quoted string object-literal key mis-typed as numeric J.Literal → NPE / NumberFormatException

Open
#8,203 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug javascript parser
Dominant language
Java
Stars
3.7k
Forks
570
Avg merge
13h 12m
Merged PRs (30d)
261

Description

What happens

Parsing a JS/TS object literal whose property key is a quoted string that is not numeric-parseable produces a J.Literal for the key with a numeric JavaType.Primitive (e.g. Double) instead of String. The literal's valueSource/value stays the string ("data-model") but its type is numeric.

This mistyped node then blows up downstream in two ways:

  • JavaScriptVisitor.visitPropertyAssignment throws NullPointerException (a requireNonNull at JavaScriptVisitor.java:418).
  • LST (de)serialization coerces the literal per its numeric type and throws NumberFormatException: For input string: "data-model" (Double.parseDouble("data-model")).

Any recipe that traverses such a file fails the whole source file. Found while running an unrelated Java/Maven recipe over a polyglot repo (finos/traderX) — the crash is in the JS/TS support, independent of the recipe.

Minimal reproduction

const order = {
  readme: 0,
  'data-model': 5,        // quoted string key + numeric value
  'fidelity-profile': 7,
};

The J.Literal for the key 'data-model' (and 'fidelity-profile') is typed numeric; a plain-JS unquoted key like readme: 0 is unaffected, and a string value like 'data-model': '🧱 Data Model' is also fine. The trigger is specifically a quoted, non-numeric string key paired with a numeric value.

Real-world occurrence: website/plugins/specs-sidebar-items-generator.js in finos/traderX:

const order = {
  readme: 0,
  spec: 1,
  plan: 2,
  tasks: 3,
  research: 4,
  'data-model': 5,
  quickstart: 6,
  'fidelity-profile': 7,
};

Expected

The J.Literal for a quoted string object-literal key should have JavaType.Primitive.String (its value being the key text), regardless of the sibling values' types. Parsing and traversal should not throw.

Stack traces (as observed via LST serialization)

NumberFormatException while reading the literal:

Caused by: java.lang.NumberFormatException: For input string: "data-model"
  at java.base/java.lang.Double.parseDouble(Double.java:971)
  at ...serialization...TreeReader.coerceLiteralValue(TreeReader.java:478)
  at ...GeneratedTreeReader.readFieldsInto_java_tree_j_literal(...)
  at org.openrewrite.javascript.internal.rpc.JavaScriptSender.visitPropertyAssignment(JavaScriptSender.java:256)
  at org.openrewrite.javascript.tree.JS$PropertyAssignment.acceptJavaScript(JS.java:2423)

NullPointerException on the same node during a recipe visit:

Caused by: java.lang.NullPointerException
  at java.base/java.util.Objects.requireNonNull(Objects.java:220)
  at org.openrewrite.javascript.JavaScriptVisitor.visitPropertyAssignment(JavaScriptVisitor.java:418)
  at org.openrewrite.javascript.tree.JS$PropertyAssignment.acceptJavaScript(JS.java:2423)

(The TreeReader.coerceLiteralValue frame is Moderne's LST serializer; it's a faithful downstream symptom of the parser assigning the key literal a numeric type. The root cause and the JavaScriptVisitor NPE are in this repo.)

Notes

  • Both a numeric value like 5 and the parser's type inference for the key seem entangled — the key literal appears to inherit a numeric primitive type. Confirming the key J.Literal's getType() on the minimal repro should show Double/numeric where String is expected.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the minimal JavaScript reproduction and inspect JavaScriptVisitor.visitPropertyAssignment at JavaScriptVisitor.java:418, then trace how the quoted object-literal key receives its J.Literal type. Add regression coverage for the quoted non-numeric key case; done means the key has JavaType.Primitive.String and parsing and traversal complete without exceptions.

Written by the indexing model from the issue text.

Assessment

Tech stack
java, javascript, typescript
Domain
tooling
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.