npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@pallad/range

v3.2.0

Published

Range structure

Downloads

749

Readme


CircleCI npm version Coverage Status License: MIT

Example code

Very simple structure with helper methods to define range of values in following scenarios

  • from A
  • to A
  • between A and B

Community

Join our discord server

Installation

npm install @pallad/range

Usage

Range consists of 3 different interfaces

Range.Start that defines only a start without an end.

interface Start<T> {
    start: T
}

Range.End that defines only an end without a start.

interface End<T> {
    end: T;
}

Range.Full that defines both a start and an end.

type Full<T> = Start<T> & End<T>

The Range type itself is an union of all of them.

type Range<T> = Range.Full<T> | Range.Start<T> | Range.End<T>;  

Creating

You can create Range from regular creation function, array or tuple.

Regular create

// full range
Range.create(1, 100);
// start range
Range.create(1);
// end range
Range.create(undefined, 100);

From array or Tuple

// start range
Range.fromArray([1])
// full range
Range.fromArray([1, 100])

// full range - other values are ignores
Range.fromArray([1, 100, 1003, 3000])
// end range
Range.fromArray([undefined, 100])

If creation fails, TypeError is thrown.

// fails - undefined values
Range.create(undefined, null)

// fails - start greater than end
Range.create(100, 1)

// fails - empty array
Range.fromArray([])
// fails - undefined values only
Range.fromArray([undefined, null])
Range.create(1, 100).value;
Range.create(null, undefined).value // 'Cannot create Range from undefined or null values'

Enchanted range

Enchanted range is a range object with extra methods. Enchanted object is immutable.

const enchantedRange = enchant(Range.create(1, 100));

enchantedRange.isWithin(40); // true
enchantedRange.isWithin(500); // false

enchantedRange.map({
    start: ({start}) => `from ${start}`,
    end: ({end}) => `to ${end}`,
    full: ({start, end}) => `between ${start} and ${end}`
}); // 'between 1 and 100`

enchantedRange.toTuple(); // [1, 100]

Checking if value is a Range

Range.is({start: 10}) // true
Range.is({end: 10}) // true
Range.is({start: 1, end: 10}) // true

Custom comparator

Boundaries comparison is a crucial feature of Range struct, therefore internally uses @pallad/compare for comparison. Sometimes it is not enough and you can provide your own comparison function.

Range.create({value: 1}, {value: 100}, (a, b) => a.value - b.value); // no fail
Range.fromArray([{value: 1}, {value: 100}], (a, b) => a.value - b.value); // no fail

Helper methods

Mapping

Mapping converts range to any other value.

Range.map accepts object with properties named start, end and full where each of it might be a function or any other value. If property value is a function then result of that function gets returned, otherwise it takes the value.

const range = Range.create(1, 100);
// mapping to simple values
Range.map(range, {start: 'start', end: 'end', full: 'full'}) // 'full'

// mapping functions
enchantedRange.map({
    start: ({start}) => `from ${start}`,
    end: ({end}) => `to ${end}`,
    full: ({start, end}) => `between ${start} and ${end}`
}); // 'between 1 and 100`

Check if value falls in range

Range.isWithin checks if given values falls in range. Internally uses @pallad/compare so custom comparison functions for value objects are supported.

Range.isWithin(Range.create(1, 100), 50) // true
Range.isWithin(Range.create(1, 100), 500) // false

Exclusivity

By default isWithin treats every range as inclusive for both edges. You can change that behavior with second argument.

const range = Range.create(1, 100);

// exclusivity = false 
Range.isWithin(range, 100, false) // true 
Range.isWithin(range, 1, false) // true

// same as above
Range.isWithin(range, 100) // true 
Range.isWithin(range, 1) // true 

// exclusivity = true 
Range.isWithin(range, 100, true) // false
Range.isWithin(range, 1, true) // false

// start exclusive 
Range.isWithin(range, 100, {start: true}) // true
Range.isWithin(range, 1, {start: true}) // false

// end exclusive 
Range.isWithin(range, 100, {end: true}) // false 
Range.isWithin(range, 1, {end: true}) // true

Converting a range of a type to another range


Range.convert(Range.create(1, 100), (value) => value + 's'); // Range<string> { start: '1s', end: '100s' }
Range.convert(Range.create(1), (value) => value + 's'); // Range<string> { start: '1s'}
Range.convert(Range.create(undefined, q00), (value) => value + 's'); // Range<string> { end: '100s'}

Sometimes you need to map to values that cannot be easily compared, therefore you need to provide custom comparison function to ensure proper creation of new range

const range = Range.create(2, 100);

// custom comparison function is needed since '2s' > '100s' using regular string comparison
Range.convert(range, (value) => value + 's', (a, b) => parseInt(a) - parseInt(b));