Fix an edge case bug where Oxlint was unable to handle fixes with with offset `-1`. Offset `-1` is used in files which contain a BOM to represent "before the BOM".
ESLint's `unicode-bom` rule produces a fix `{ range: [-1, 0], text: "" }` to remove BOM from a file with such a BOM.
`-1` can't be represented as a `u32`, so we have to take a rather annoying workaround - add 1 to offsets before sending them to Rust.
An alternative would have been to make `start` and `end` `i64`s so they can represent `-1`, but this would seem wasteful since we only need to represent -1, not any other negative value. So adding 1 to offsets is cheaper.
This fixes 2 ESLint conformance tests.
Previously when a rule provided a single fix or suggestion, the range of the fix was not checked to ensure it is valid.
If the fix had an invalid range (`start <= end`, `end` not out of bounds of source text) this would cause a panic when attempting to slice the source text with the invalid range.
Catch these cases earlier and produce a `MergeFixesError`, so the invalid fix is not applied, avoiding the panic.
Notes:
* The error messages for negative offsets or offsets > `u32::MAX` are not great, but I don't think it really matters. These shouldn't happen in practice, so IMO it'd be wasteful to introduce extra code paths to handle these cases. The important thing is that they don't cause panics.
* No additional validation is required when rule produces multiple fixes, as these same checks are already performed in `CompositeFix::merge_fixes_fallible`, which handles combining multiple fixes.
Alter tests for fixes and suggestions. One fix now adds text before and after a node, without altering the node itself. This checks that `CompositeFix::merge_fixes_fallible` works correctly when the combined fix includes a section of original source code.
Alter test fixtures for fixes and suggestions.
Remove trailing newline from end of fixture files, so that the last fix the plugin makes is at very end of file - makes sure fixes in this position still work.
Add checks to these tests and also the BOM test to catch if these fixture files accidentally get formatted, which would add a trailing newline and prevent the tests testing what they should do.
Implement support for suggestions.
Implementation exactly matches ESLint's.
The tests demonstrate that:
* `--fix-suggestions` applies suggestions.
* `--fix` does *not* apply suggestions.
* When a rule provides multiple suggestions, only the 1st is applied.
I've also confirmed that suggestions show up correctly in VSCode (once language server supports JS plugins).