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

@byu-oit/cartographer

v0.0.9

Published

The art or technique of making maps

Downloads

554

Readme

Introduction

This utility provides a helpful interface for converting Javascript objects into new forms.

Install

npm i @byu-oit/cartographer

Usage

Basic Usage

import { Cartographer } from '@byu-oit/cartographer'

const sourceData = { x: '1' }
const cartographer = new Cartographer(sourceData).cpy('y', 'x')
const { result } = cartographer
// expected result: { y: '1' }

Documentation

A few setup utilities are available to help fill in some of the functionality you may need for your cartographer instance. They are

  • clone
  • dictionary
  • filter
  • transformer

clone

Clones the settings from the current cartographer instance and creates a new instance. This is helpful if you want to use the same settings for multiple different mappings.

clone (source?: Dictionary, initial?: Dictionary, options?: CartographerOptions) => Cartographer

const sourceData = { ... }
const map1 = new Cartographer(sourceData, {}, {
    filters: [
        // Filter out all empty string values
        (value: unknown) => value !== ''
    ]
})

// map2 will have all the same source data, result data, filters, transformers, and dictionaries
const map2 = map1.clone()
// expected map2.filters.length = 1

dictionary

Adds a dictionary to the cartographer configuration

dictionary (name: string, dictionary: Dictionary) => this

const sourceData = { ... }
const map = new Cartographer(sourceData)

// Add a new dictionary to convert numbers from string to number
map.dictionary('numbers', {
    one: 1,
    two: 2,
    three: 3
})

filter

Adds a filter to the cartographer configuration. Filters run in insertion order. Additional filters supplied to the set, cpy, or trl methods will run before filters in the configuration.

filter (filter: Filter) => this

const sourceData = { ... }
const map = new Cartographer(sourceData)

// Adds a filter that skips setting values in the `result` object if the value is an empty string
map.filter((value: unknown) => value !== '')

transformer

Adds a transformer to the cartographer configuration. Transformers run in insertion order. Additional transformers supplied to the set, cpy, or trl methods will run before transformers in the configuration.

transformer (transformer: Transformer) => this

const sourceData = { ... }
const map = new Cartographer(sourceData)

// Adds a transformer that casts the value to a boolean setting it in the `result` object.
map.transformer((value: unknown) => value === 'true')

The remaining methods are used to map information from the source object to the target or result object.

  • get
  • set
  • cpy
  • trl
  • trf
  • fil
  • run
  • clr
  • if

get

Retrieves data from the source object based on a property path as defined in lodash.get. The default value is the third argument passed to lodash.get.

get (from: string, defValue: unknown) => unknown

const sourceData = { x: '1' }
const map = new Cartographer(sourceData)

const x = map.get('x') // returns '1'
let y = map.get('y') // returns undefined
y = map.get('y', 2) // returns 2

set

Sets a given value in the result object at the location indicated by the property path as defined in lodash.set.

set (to: string, value: unknown, options?: SetOptions) => this

const map = new Cartographer()

// Additional filters or transformers will run before the default filters and transformers.
map.set('some.property.path', '', {
    filters: [
        // See the documentation on filters (below) for this example filter definition
        isEmptyString
    ]
})
// result: { }

map.set('some.property.path', '')
// The `isEmptyString` filter only applies for the previous operation
// result: { some: { property: { path: '' } } }

Before a value is set, any transformers or filters will run in order of insertion. The order of operations is:

  1. In-line transformers
  2. Default transformers
  3. In-line filters
  4. Default filters

In-line refers to the transformers or filters that are passed in the method invocation.

Default refers to the transformers or filters added to the cartographer configuration.

Filter

A predicate function who's resulting boolean value indicates whether the value should or should not be set.

Filter = (this: Cartographer, value: unknown) => boolean

The following example will "filter out" or not set values that are empty strings.

function isEmptyString (value: unknown): boolean {
    return value === ''
}

The example above can also be written as an arrow function. However, be aware that arrow functions don't have a this context and therefore the cartographer instance members (e.g. this.get or this.set) are not available.

NOTE: The if method on the cartographer instance implements a filter that removes itself after its first invocation.

Transformer

A predicate function who's resulting value is used in place of the selected source value. When multiple transformers are used in series, the first transformer will pass along its return value and so on till the last transformer is invoked and the value is set in the result object.

Transformer = (this: Cartographer, value: unknown, ...args: unknown[]) => unknown

The following transformer maps the source value from a string to a boolean.

function ynToBoolean (value: unknown): boolean | unknown {
    if (typeof value !== 'string' || /^Y|N$/i.test(value)) {
        return undefined
    }
    return value.toUppercase() === 'Y'
}

Like filters, transformers should not be written as an arrow function if access to the cartographer this context is required.

cpy

Copies data to the result property path from the source property path. It is functionally equivalent to invoking Cartographer.prototype.get() and then passing that value into Cartographer.prototype.set().

cpy (to: string, from: string, options?: SetOptions) => this

const sourceData = { data: { holiday: '2022-01-01' } }
const map = new Cartographer(sourceData)

map.cpy('event.date', 'data.holiday', {
    transformers: [
        function stringToDate (value: unknown): Date | undefined {
            if (typeof value !== 'string' || /^\d{4}-\d{2}-\d{2}$/.test(value) {
                return undefined
            }
            return new Date(value)
        }
    ]
})
// result: { event: { date: Sat Jan 01 2022 00:00:00 GMT-0000 (GMT) } }

trl

Translates the value at the source property path (known as a word) by looking it up in the given dictionary on the cartographer instance. If the word or dictionary is invalid, the value is set to undefined by default but an error can be thrown instead by specifying { throwErr: true } in the fourth argument of the method. Additional filters and transformers in the options will run after the value has been translated. This method is functionally equivalent to adding an in-line transformer.

trl (to: string, from: string, dictionary: string, options?: SetOptions & { throwErr?: boolean }) => this

const sourceData = { first: 'one', second: 'two' }
const map = new Cartographer(sourceData)

map.trl('first', 'first', 'numbers', { throwErr: true })
// throws an error because the dictionary "numbers" is not found on the instance

map.dictionary('numbers', { one: 1 })
// adds the "numbers" dictionary
// note that the numbers dictionary does not define the word 'two'

map.trl('first', 'first', 'numbers')
// result: { first: 1 }

map.trl('second', 'second', 'numbers', { throwErr: true })
// throws an error because the word "two" is not found in the "numbers" dictionary

trf

This is an alias operation for cpy that simplifies applying inline transformations. Multiple inline transformations may be supplied as additional arguments and will be executed in the order they are written (from left to right). For more intricate copies, please refer to the cpy operation.

trf (to: string, from: string, ...transformers: Transform[]) => this

import { Cartographer } from './cartographer'

const sourceData = { x: '1', y: 2 }
const map = new Cartographer(sourceData)

const toNum = (v: unknown) => {
 if (typeof v === 'string') {
  const result = parseFloat(v)
  if (isNaN(result)) return -1
  return result
 }
 if (typeof v !== 'number') return -1
 return v
}

map
  .trf('x', 'x', toNum)
  .trf('y', 'y', toNum)
// result: { x: 1, y: 2 }

fil

This is an alias operation for cpy that simplifies applying inline filters. Multiple inline filters may be supplied as additional arguments and will be executed in the order they are written (from left to right). For more intricate copies, please refer to the cpy operation.

fil (to: string, from: string, ...filters: Filter[]) => this

import { Cartographer } from './cartographer'

const sourceData = { x: '1', y: 2, z: '1996-04-26' }
const map = new Cartographer(sourceData)

const isDateString = (v: unknown) => {
 return typeof v === 'string' && /^\d{4}-\d{2}-\d{2}$/.test(v)
}

map
 .fil('x', 'x', isDateString)
 .fil('y', 'y', isDateString)
 .fil('z', 'z', isDateString)
// result: { z: '1996-04-26' }

run

Executes a runner function who's return value is set on the result object. Like filters and transformers, runners should not be written as an arrow function if access to the cartographer this context is required.

run (to: string, runner: Runner) => this

const sourceData = { x: '1' }
const map = new Cartographer(sourceData)

map.run('value', function () {
    return this.get('x')
})
// result: { value: '1' }

clr

Resets the result object to the given initial value (defaults to an empty object).

clr (initial?: Dictionary | null) => this

const map = new Cartographer({}, { some: 'data' })

map.clr({ other: 'data' })
// result: { other: 'data' }

map.clr()
// result: { }

Note: if null is given as the initial argument, the default is used.

if

Sets a filter that will skip the next set action (i.e. set, cpy, trl, or run) if the condition resolves to false. The condition can be a boolean expression or value, or it can be a function that resolves to a boolean value.

if (condition: boolean | Runner) => this

const map = new Cartographer()

map.if(false).set('skipped', true)
// result: { }

map.if(() => false).set('skipped', true)
// result: { }

map.if(true).set('skipped', false)
// result: { skipped: false }