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

@slimr/util

v3.2.40

Published

A set of slim JS polyfills with tree-shaking support

Downloads

93

Readme

🪶 @slimr/util npm package

A set of slim JS polyfills with tree-shaking support

Context

@slimr is a set of slim React (hence '@slimr') libs. Check them all out on github!

Exports

appendElement, appendLink, appendScript, appendStyle

Append a link, script, style, or ANY element to the head of the document if not already added

areEqualDeep, areNotEqualDeep

Deep compare methods

  • Shallow is faster than deep if it's "good enough" for your use case
  • Dependendencies: ./src/equality-deep.ts, npm:fast-deep-equal
  • Note: Imperfect on Classes
  • Tip: For debugging, try using areEqualDebug/areNotEqualDebug

areEqualShallow, areNotEqualShallow

Shallow compare methods

  • Shallow is faster than deep if it's "good enough" for your use case
  • Dependendencies: ./src/equality-deep.ts, npm:fast-shallow-equal
  • Note: Imperfect on Classes and less perfect than deep
  • Tip: For debugging, try using areEqualDebug/areNotEqualDebug

copy

Deeply copy two objects

const obj1 = [
  {foo: 'bar', arr: [2]},
  {foo: 'bar2', arr: [3]},
]
const obj2 = copy(obj1)

createUid

Generate a random string of 12 characters, provided by npm:nanoid.

const id = createUid()

debounce

Don't call a function until a certain amount of time has passed without it being called.

  • If you want more features, like arg diffing and return values, see @slimr/util/memoize
  • Dependences: ./src/debounce.ts
const fnc = async () => 2
const debounced = debounce(fnc, 250)
debounced()
debounced()
debounced()
await sleep(250)
debounced()
debounced()
debounced()
await sleep(250)
// fnc would only be called twice

diff, addedDiff, deletedDiff, updatedDiff, detailedDiff

Deep compare methods provided by npm:deep-object-diff, which return an object describing the differencees between two objs.

highlightCodeElements

Highlight code elements using highlight.js

  • Is async + lazy loaded to avoid loading highlight.js on pages that don't need it bc is large.
  • Dependendencies: ./src/code-highlight-lazy.ts, npm:highlight.js

formToValues

Extracts form values from a form element, such as e.target from form.onSubmit

  • An alternative to the FormData api, aiming to be more predictable, flexible and less awkward.
    • For example, FormData has not great way to enumerate all fields (even ones with undefined values) or multiple checkboxes or multi selects.
  • Handles text, number, checkboxes, radio buttons, textarea, select
  • Value = array if multiple inputs with same 'name', such as checkboxes
  • Converts US phone numbers to international format
  • Usage: Code Sandbox
  • Limitation: Can't handle complex forms (multipart/form-data encoding)
  • Dependencies: ./src/form-to-values.ts

Why not FormData?

  • FormData returns an iterator, vs formToJson a simple dictionary object
  • For checkbox inputs, FormData returns 'on' when checked and nothing at all when unchecked
  • For number inputs, FormData returns a string instead of a number
  • For array values such as select w/ multiple, FormData returns a seperate key/value for every value instead of key=array of values.

hash32 and hash64

Quickly converts any plain object, string, number, and more to a 32bit/64bit hash number or string

  • Uses a fast and tiny approach, which has higher likelyhood of collision than
  • Best for smaller hash tables
  • Not good enough for UUIDs
  • Dependencies: ./src/hash.ts
hash32('hello world') // 1047750623
hash32('hello world', true) // 'hbsxjz'
hash32({hello: 'world'}) // 141133545
hash64('hello world') // 927946135
hash64('hello world', true) // 'fch3tj'
hash64({hello: 'world'}) // 1139059049

NOTE hash64 is not a true 64 bit hash and has higher collision odds than a true 64 bit hash.

Collisions are possible and likelyhood increases with the number of hashes.

Ideal collision odds:

  • 100 32bit hashes = 1/1,000,000
  • 927 32bit hashes = 1/10,000
  • 1921 64bit hashes = 1/10,000,000,000,000 = 1/10 trillion = ~odds of a meteor hitting your house

References

is-whats

A set of is-type methods to easily check if a value is a type.

  • Is provided by npm:is-what, which has a full list of options.
isPositiveNumber(-2) // false
isFullArray([]) // false
isEmptyArray([]) // true

mapApplyMaxSize

Limit the size of a map by evicting the least-recently-used (aka LRU) items. Works by monkey-patching the get and set of a map instance

  • Dependencies: ./src/map-apply-max-size.ts, ./src/stringify.ts
const t = mapApplyMaxSize(new Map(), 2)
t.set('a', 1)
t.set('b', 2)
t.set('a', 3) // refreshes 'a'
t.set('c', 3) // should evict 'b'
expect(t.get('b')).toBeUndefined()
t.set('d', 4) // should evict 'a'
expect(t.get('a')).toBeUndefined()
t.get('c')
t.set('e', 5) // should evict 'd'
expect(t.get('d')).toBeUndefined()

memoize

A memoization wrapper with ttl expiration for cache hits.

  • Aka a feature rich debounce. If you only need basic debounce, see @slimr/util/debounce.
  • Compared to other memoization algs (fast-memoize, nano-memoize), is much simpler, shorter, easier to fork/enhance while less perfect and slower for primitive args.
  • Dependences: ./src/memoize.ts

merge, mergeAndCompare, mergeAndConcat

Deeply merge objects or arrays in a familiar pattern to Object.assign

merge({foo: 'bar', arr: [2]}, {foo: 'bar2', arr: [3]}) // {foo: bar2, arr: [3]}
mergeAndConcat({foo: 'bar', arr: [2]}, {foo: 'bar2', arr: [3]}) // {foo: bar2, arr: [2, 3]}

mergeAndCompare(concatStrings, {name: 'John'}, {name: 'Simth'})
// returns { name: 'JohnSmith' }

function concatStrings(originVal, newVal, key) {
  if (typeof originVal === 'string' && typeof newVal === 'string') {
    // concat logic
    return `${originVal}${newVal}`
  }
  // always return newVal as fallback!!
  return newVal
}

numericStringMask

Applies a mask to a string of numbers, helpful for phone numbers

Grabs all of the numbers out of str into an array, then assembles the mask and replaces the '#' with the numbers in order

numericStringMask('1234567890', '(###) ### - ####') // (123) 456 - 7890
numericStringMask('1234567890', '(###) ### - ####') // (123) 456 - 7890
numericStringMask('(123)abc45678-90', '(###) ### - ####') // (123) 456 - 7890
numericStringMask('1234567890', '(###) ###-####') // (123) 456-7890
numericStringMask('11900567890', '(##) #####-####') // (11) 90056-7890

// react input usage
const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
  e.currentTarget.value = numericStringMask(e.target.value, '(###) ###-####')
    // Replaces so we don't add characters past the end of the string,
    // and so the user can delete characters
    .replace(/-$/, '') // changes '(123) 456-' to '(123) 456'
    .replace(/\) $/, '') // changes '(11)' to '(11'
    .replace(/\($/, '') // changes '(' to ''
}

setPageMeta

Allows setting common page attrs.

  • Intelligently use the attrs, only setting if changed
  • Resets back to initial if omitted, based on initial introspection
  • Stores element handles in memory to remove need to query the dom on every update

Note: Set window.setPageMetaSkip=true to disable setPageMeta for testing

Parameters:

  • title - Sets title, meta:og:title. Is postfixed by ' - {siteName}'
  • siteName - Sets meta:og:site_name
  • description - Sets meta:description
  • image - Sets meta:og:image
  • locale - Sets meta:og:local

Assumption: The page should already have the following meta tags, to be used as defaults:

<title>React Template</title>
<meta property="og:title" content="React template" />
<meta property="og:site_name" content="React Template" />
<meta property="og:locale" content="en_US" />
<link rel="canonical" href="https://react-template.com" />
<meta name="description" content="A template to build tiny Preact applications" />
<meta property="og:description" content="A template to build tiny React applications" />
<meta property="og:url" content="https://github.com/bdombro/react-template" />
<meta property="og:image" content="https://preact-template.com/apple-touch-icon.png" />

Usage:

const {description} = setPageMeta({
  title: `Hello World`,
  description: 'This page is awesome',
})

stringify

A safe JSON.stringify wrapper that limits recursion

  • Dependencies: ./src/stringify.ts

toCamelCase

Convert a string to camelCase

toCamelCase('hello_world') // helloWorld

toKebabCase

Convert a string to kebab-case

toCamelCase('hello_world') // hello-world