So-called Ranges
We invented the term, but it’s just a fancy way to describe arrays of “from” — “to” string index ranges:
[
[3, 7],
[10, 15, "replacement"],
[4, 7],
];
[3, 7]
means delete characters from index 3
to 7
.
[10, 15, "replacement"]
means replace characters from index 10
to 15
with "replacement"
.
A case of no ranges is marked by a falsy null
(but if you pass a truthy
empty array, it will work too).
That’s all there is.
Same indexes as in String.prototype.slice()
.
Ranges-based packages allow us to perform composable operations on a string: you gather what needs to be done, then, in the end, “render” the result. Ranges are also portable between packages and each amendment can be tweaked or discarded later.
As you know, strings in JavaScript are immutable, which means, each time you amend a string, a new value is written to the memory and the old value is left for garbage collector to clean up. Now, if the string is larger, if there are many .replace()
chained, it gets out of control very quick (both in terms of performance and in DX). That’s where Ranges step in.
Range Libraries
ranges-apply
ranges-push
ranges-merge
ranges-sort
ranges-crop
ranges-regex
ranges-ent-decode
ranges-invert
ranges-offset
ranges-is-index-within
ranges-iterate
ranges-process-outside
ranges-apply
It performs all the amendments described by the ranges (array or null
) on a given string, returning a new string.
ranges-push
When we want to gather ranges, instead of pushing them into an array, we can push them into this helper Class (for example, gatheredRanges
below). That gives us automatic merging and sorting.
ranges-push
also checks the types so it acts like a safeguard.
ranges-merge
If, after sorting, any two ranges in the vicinity have the same edge value (like 2
below), merge them.
ranges-sort
It sorts the ranges.
See the packageranges-crop
It crops the ranges, ensuring no range from an array goes beyond a given index.
Along the way, it will also merge and sort ranges.
See the packageranges-regex
Takes a string, matches the given regex on it and returns ranges which would do the same thing.
Similarly to String.prototype.match()
, a no-results case will yield null
(which ranges-merge and others would gladly accept).
ranges-ent-decode
This is a wrapper on top of market-leading HTML entity decoder he.js decode()
which returns ranges instead of string.
We tested the hell out of the code, directly and up-the-dependency-stream but as a cherry on top, all he.js
unit tests were ported to our uvu
-based test suite and they do pass.
ranges-invert
Inverts ranges.
See the packageranges-offset
Offsets all indexes in every range.
See the packageranges-is-index-within
Tells, is a given natural number index within any of the ranges. It’s a wrapper on top of Array.prototype.find()
.
ranges-iterate
It iterates all characters in a string, as if given ranges were already applied.
Sometimes certain operations on a string aren’t really composable — sometimes we want to traverse the string as if ranges were applied, as if we already had the final result.
See the packageranges-process-outside
Processes the string outside the given ranges. Each “gap” in the string between ranges will be fed into callback you supply — same like in Array.prototype.forEach()
.
This program makes the life easier because if you did it manually, you’d have to invert ranges and loop over each inverted chunk. Finally, you’d have to write unit tests of all that.
See the packageAlternatives — magic-string
The magic-string
by Rich Harris, the Rollup creator.
It is an all-in-one program to perform operations on strings in a controllable manner. It’s oriented at operations on code, and its produced sourcemaps are aimed at browsers.
Range libraries are best used for when you want to:
- transfer string amendment instructions between programs
- gather string amendment instructions and discard some, conditionally, or tweak them
- when string processing is complex
magic-string
is best used in programs similar to Rollup: you process code and generate sourcemaps for browsers.
In comparison:
magic-string
method .overwrite
— equivalent to ranges-push
and ranges-apply
.