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 null (but if you pass an empty array, it will work too).




That's all there is.



Same indexes as in String.prototype.slice().

Ranges gives us the flexibility to process strings. For example, detergent taps different packages, one to strip HTML, another to remove widow words and so on — they all report ranges. They all operate on the same source string, not on the source, mutated by the previous operation.

In the end, detergent merges those ranges and processes the string, rendering the result.

That's a different approach from the old way, mutating string over and over using regexes.

§ ranges-apply

It takes the source string and the amendments described by Ranges and produces a new string.

See the package

§ 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.

See the package

§ ranges-merge

If, after sorting, any two ranges in the vicinity have the same edge value (like 2 below), merge them.

See the package

§ ranges-sort

It sorts the ranges.

See the package

§ ranges-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 package

§ ranges-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).

See the package

§ ranges-ent-decode

This is a wrapper on top of market-leading HTML entity decoder he.jsopens in a new tab 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.jsopens in a new tab unit tests were ported to node-tap and do pass.

See the package

§ ranges-invert

Inverts ranges.

See the package

§ ranges-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().

See the package

§ 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 package

§ ranges-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 package

§ Alternatives

§ magic-string

The magic-stringopens in a new tab 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.