Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

serializing Infinity creates invalid JSON #2482

Closed
MatthiasMann opened this issue Aug 1, 2024 · 5 comments
Closed

serializing Infinity creates invalid JSON #2482

MatthiasMann opened this issue Aug 1, 2024 · 5 comments
Labels

Comments

@MatthiasMann
Copy link

What version of Ajv are you using? Does the issue happen if you use the latest version?
8.17.1

Ajv options object
{}

Test case:

interface LoudnessMeasurement {
  m: number | null,
  s: number | null,
  g: number | null,
  g_seconds: number
}
const schema: JTDSchemaType<LoudnessMeasurement> = {
  properties: {
    m: { type: "float64", nullable: true },
    s: { type: "float64", nullable: true },
    g: { type: "float64", nullable: true },
    g_seconds: { type: "float64" }
  }
};
const ajv = new Ajv();
let serializer = ajv.compileSerializer(schema);
console.log(serializer({m:-Infinity, s:-12.0, g:null, g_seconds: 420.69}));

Result:
{"m":-Infinity,"s":-12,"g":null,"g_seconds":420.69}

This JSON is invalid and should instead be:
{"m":"-Infinity","s":-12,"g":null,"g_seconds":420.69}

@MatthiasMann
Copy link
Author

Setting the options object to {strictNumbers: false} did not help.

@jasoniangreen
Copy link
Collaborator

Hi @MatthiasMann thanks for raising this. It does indeed seem wrong to me that compileSerializer is able to produce a string that will throw when passed to JSON.parse but according to the JSON spec your proposal is also incorrect. In theory Infinity (and also NaN) should be be converted to null when serialised. You can try it yourself:

> JSON.stringify({"blah": Infinity})
> '{"blah":null}'

So the correct fix (though I would need to consult on this more to be sure) would be to convert to null. If you wanted "-Infinity" in your case, then that is something you would need to manage separately, for instance, by traversing your objects and swapping Infinity for "Infinity".

@MatthiasMann
Copy link
Author

Hmm you are right - this is very annoying.

As I only have very few elements which need to handle -Infinity I just replaced these with my own function and template literals for this object:

function peak_to_JSON(n: number): string {
  return (n > -190) ? n.toString() : "\"-Infinity\"";
}
function peak_to_JSON_nullable(n: number | null): string {
  return (n === null) ? "null" : peak_to_JSON(n);
}```

let serializer = (data:LoudnessMeasurement) => `{\"m\":${peak_to_JSON_nullable(data.momentary)},\
\"s\":${peak_to_JSON_nullable(data.short_term)},\
\"g\":${peak_to_JSON_nullable(data.gated)},\
\"g_ms\":${data.gated_recorded.ms()}}`;

(this also avoid to convert it to another object to change the key names)

@jasoniangreen
Copy link
Collaborator

Yeah, that should also mean when we fix this behaviour to return the standardised null your fix will not mess anything up, it will just not find any Infinity to replace.

@jasoniangreen
Copy link
Collaborator

@epoberezkin not a high priority but I wanted to flag to you that I do think this one is a legit bug. The serializer shouldn't be returning invalid JSON strings and therefore Infinity and NaN should become null.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

No branches or pull requests

2 participants