secondwheel

unopinionated library of functions for those tired of reinventing the wheel

Build Status Coverage Status

Philosophy:

  1. use Yarn for everything
  2. tiny, reusable, pure & side effect free functions (when possible), following a single responsibility principle
  3. no transpilation
  4. full test and type coverage
  5. tests cover contracts, not internal implementation
  6. simple, complete, automatically generated API documentation
  7. fast and minimal
  8. flexible
  9. having as few dependencies as possible
  10. no reliance on any framework
  11. fully automated release process
Templating
template
a wrapper around lodash/template , which caches compiled templates in memory

Examples

import template from 'secondwheel/template'

template('hello <%= name %>', { name: 'foo' })
template('hello <%= name %>', { name: 'bar' }) // only compiled once

Parameters

tpl: string = ''
data: Object = {}

Returns

string
markdown
markdownToArray
converts a markdown string to an array of plain objects and strings

Examples

import markdownToArray from 'secondwheel/markdownToArray'

// stringify to transmit over the network, cache, etc.
const str = JSON.stringify(markdownToArray('hello <%= name %>', { name: 'foo' }))

Parameters

tpl: string = ''
data: Object = {}

Returns

Array<(string | Object)>
markdownToJSX
converts a markdown string to HyperScript compatible nodes

Examples

import markdownToJSX from 'secondwheel/markdownToJSX'

// use with any HyperScript compatible framework
import { createElement as h } from 'react'
import { h } from 'preact'
import { h } from 'inferno-hyperscript'

markdownToJSX(h, '# hello <%= name %>', { name: 'foo' })

Parameters

h: Function
tpl: string = ''
data: Object = {}
jsx
htmlToArray
converts an html string to an array of plain objects and strings

Examples

import htmlToArray from 'secondwheel/htmlToArray'

// stringify to transmit over the network, cache, etc.
const str = JSON.stringify(htmlToArray('<b>hello <%= name %></b>', { name: 'foo' }))

Parameters

tpl: string = ''
data: Object = {}

Returns

Array<(string | Object)>
arrayToJSX
converts an array of objects and strings to HyperScript compatible nodes

Examples

import arrayToJSX from 'secondwheel/arrayToJSX'

// use with any HyperScript compatible framework
import { createElement as h } from 'react'
import { h } from 'preact'
import { h } from 'inferno-hyperscript'

// render dynamic content without `dangerouslySetInnerHTML`
(<div>{arrayToJSX(h, <result of htmlToArray>)}</div>)

Parameters

h: Function
arr: Array<(string | Object)> = []
htmlToJSX
converts an html string to HyperScript compatible nodes

Examples

import htmlToJSX from 'secondwheel/htmlToJSX'

// use with any HyperScript compatible framework
import { createElement as h } from 'react'
import { h } from 'preact'
import { h } from 'inferno-hyperscript'

// bold text without `dangerouslySetInnerHTML`
(<div>{htmlToJSX(h, '<b>hello <%= name %></b>', { name: 'foo' })}</div>)

Parameters

h: Function
tpl: string = ''
data: Object = {}
Apollo/GraphQL
ApolloClient
  • like apollo-boost, but allows for a greater degree of configurability
  • augments apollo-client with usefull defaults
  • batches requests, retries failed requests
  • works on Node.js and in the browser alike
  • subscriptions baked in
  • provides static methods, overriding which any aspect of the default functionality can be changed

Examples

import ApolloClient from 'secondwheel/ApolloClient'

// connecting to a simple "graphql-yoga" server with default options
const client = new ApolloClient({
  uri: 'http://localhost:4000',
  wsUri: 'ws://localhost:4000'
})

Extends

Client

Parameters

options: ApolloClientOptions = {}
createLink
creates the final instance of ApolloLink

Examples

// override to a default behaviour (will have no effect)
import { split } from 'apollo-link'

ApolloClient.createLink = options => {
  const wsLink = ApolloClient.createWSLink(options)
  const httpLink = ApolloClient.createHttpLink(options)

  return wsLink ? split(ApolloClient.testOperation, wsLink, httpLink) : httpLink
}

Parameters

options: ApolloClientOptions

Returns

ApolloLink
createCache
creates an instance of ApolloCache

Examples

// override to a default behaviour (will have no effect)
import { InMemoryCache } from 'apollo-cache-inmemory'

ApolloClient.createCache = ({ cache = {} }) => new InMemoryCache().restore(cache)

Parameters

options: ApolloClientOptions

Returns

ApolloCache
createHttpLink
creates an instance of ApolloLink

Examples

// override to a default behaviour (will have no effect)
import { from } from 'apollo-link'
import compact from 'lodash/compact'

ApolloClient.createHttpLink = options => from(compact(ApolloClient.getLinks(options)))

Parameters

options: ApolloClientOptions

Returns

ApolloLink
createWSLink
creates an instance of WebSocketLink

Examples

// override to a default behaviour (will have no effect)
import { NativeWebSocket } from 'secondwheel/constants'
import { WebSocketLink } from 'apollo-link-ws'

ApolloClient.createWSLink = ({ wsUri, wsOptions = { reconnect: true }, webSocketImpl = NativeWebSocket }) =>
  wsUri && webSocketImpl && new WebSocketLink({
    uri: wsUri,
    options: wsOptions,
    webSocketImpl
  })

Parameters

options: ApolloClientOptions

Returns

ApolloLink?
getLinks
returns an array of ApolloLink to be used in the creation of the final link falsy values are filtered out

Examples

// override to a default behaviour (will have no effect)
ApolloClient.getLinks = options => [
  ApolloClient.createErrorLink(options),
  ApolloClient.createRetryLink(options),
  ApolloClient.createBatchLink(options)
]

Parameters

options: ApolloClientOptions

Returns

Array<ApolloLink?>
createErrorLink
creates an instance of ErrorLink

Examples

// override to a default behaviour (will have no effect)
import noop from 'lodash/noop'
import { onError } from 'apollo-link-error'

ApolloClient.createErrorLink = ({ onError: errorCallback = noop }) => onError(errorCallback)

Parameters

options: ApolloClientOptions

Returns

ApolloLink?
createRetryLink
creates an instance of RetryLink

Examples

// override to a default behaviour (will have no effect)
import { RetryLink } from 'apollo-link-retry'

ApolloClient.createRetryLink = ({ delay, attempts }) => new RetryLink({ delay, attempts })

Parameters

options: ApolloClientOptions

Returns

ApolloLink?
createBatchLink
creates an instance of HttpLink

Examples

// override to a default behaviour (will have no effect)
import { isNode } from 'secondwheel/constants'
import { BatchHttpLink } from 'apollo-link-batch-http'

ApolloClient.createBatchLink = ({
  uri = '/graphql',
  browserUri = uri,
  serverUri = browserUri,
  includeExtensions,
  headers = {},
  credentials = 'same-origin',
  fetchOptions = {},
  useGETForQueries,
  batchMax,
  batchInterval,
  batchKey
}) =>
  new BatchHttpLink({
    uri: isNode ? serverUri : browserUri,
    includeExtensions,
    fetch,
    headers,
    credentials,
    fetchOptions,
    useGETForQueries,
    batchMax,
    batchInterval,
    batchKey
  })

Parameters

options: ApolloClientOptions

Returns

ApolloLink?
nextApollo
Apollo-Client HOC for the Next.js App component.

A simpler way to achieve the same result as in with-apollo, which does not require any boilerplate code.

The ctx object is equivalent to the one received in all getInitialProps hooks.

Examples

import React from 'react'
import App, { Container } from 'next/app'
import { ApolloProvider } from 'react-apollo'
import nextApollo from 'secondwheel/nextApollo'
import ApolloClient from 'secondwheel/ApolloClient'

class MyApp extends App {
  render () {
    const { Component, pageProps, client } = this.props

    return (
      <Container>
        <ApolloProvider client={client}>
          <Component {...pageProps} />
        </ApolloProvider>
      </Container>
    )
  }
}

export default nextApollo(
  props => new ApolloClient({ uri: 'http://localhost:4000', ...props })
)(MyApp)

Parameters

getClient: function (props: Object, ctx: Object): ApolloClient
getProps: function (ctx: Object): (Object? | Promise<Object?>) = noop
subscription
created
updates object to reflect created nodes at path

Examples

import { created } from 'secondwheel/subscription'

const newData = created(data, 'path.to.nested.list', payload)

Parameters

result: Object
path: string
payload: SubscriptionPayload

Returns

Object
updated
updates object to reflect updated nodes at path

Examples

import { updated } from 'secondwheel/subscription'

const newData = updated(data, 'path', payload)

Parameters

result: Object
path: string
payload: SubscriptionPayload

Returns

Object
deleted
updates object to reflect deleted nodes at path

Examples

import { deleted } from 'secondwheel/subscription'

const newData = deleted(data, 'path', payload)

Parameters

result: Object
path: string
payload: SubscriptionPayload

Returns

Object
Hashing/Masking
maskPassword
produces a string of the same length as the original with every character replaced by a "*"

Examples

import maskPassword from 'secondwheel/maskPassword'

maskPassword('secret') // ******

Parameters

value: string = ''
md5
produces an md5 hash on Node.js as well as in a browser

Examples

import md5 from 'secondwheel/md5'

md5('42') // a1d0c6e83f027327d8461063f4ac58a6

Parameters

value: string = ''
slug
generate a slug just like GitHub does for markdown headings

Examples

import slug from 'secondwheel/slug'

slug('hello world') // hello-world

Parameters

value: string = ''
Test Assertions
reactShallowStrictEqual
a unit testing helper for React components

performs a shallow render of actual and compares the result to expected

uses the native Node.js assert.strictEqual to perform the assertion

Examples

// MyButton.js
import classNames from 'classnames'

export default ({children, className, ...props}) => (
  <button className={classNames('my-button', className)} {...props}>{children}</button>
)
// MyButton.test.js
import reactShallowStrictEqual from 'secondwheel/reactShallowStrictEqual'
import MyButton from './MyButton'

describe('MyButton', () => {
  it('should render predictable result', () => {
    reactShallowStrictEqual(
      (<MyButton className="test-class" id="test-id">test children</MyButton>),
      (<button className="my-button test-class" id="test-id">test children</button>)
    )
  })
})

Parameters

actual: ReactElement
expected: ReactElement
message: string?

Throws

AssertionError // test failure
matching
verifies that expected is a subset of actual

Examples

import matching from 'secondwheel/matching'

describe('matching', () => {
  it('should match', () => {
    matching(
      { value: ['45'], something: 'here' },
      { value: [45] }
    )
  })
})

Parameters

actual: any
expected: any
message: string = 'expected values to match'

Throws

AssertionError // test failure
assert
verifies that executing resolver on actual results in a truthy value

Examples

import assert from 'secondwheel/assert'

describe('assert', () => {
  it('should be less than a 1000', () => {
    assert(100, value => value < 1000)
  })
})

Parameters

actual: T
resolver: function (actual: T): any = identity
message: string = 'expected value to be truthy'

Throws

AssertionError // test failure
assertArray
verifies that actual is an array

Examples

import assertArray from 'secondwheel/assertArray'

describe('assertArray', () => {
  it('should be an array', () => {
    assertArray([])
  })
})

Parameters

actual: any
message: string = 'expected value to be an array'

Throws

AssertionError // test failure
assertString
verifies that actual is a string

Examples

import assertString from 'secondwheel/assertString'

describe('assertString', () => {
  it('should be a string', () => {
    assertString('')
  })
})

Parameters

actual: any
message: string = 'expected value to be a string'

Throws

AssertionError // test failure
Misc
env
Loads environment variables from a file.

Performs validation based on the existence of variables rather than their value. Hence, a variable with no value is considered declared.

Examples

# .env.example (every key defined here must also be present in the environment)
FULL_NAME=John Doe
PASSWORD=
# .env (supports javascript-style interpolation)
AGE=30
LAST_NAME=Smith
FULL_NAME=${FIRST_NAME} ${LAST_NAME}
# EnvError: missing environment variables: FIRST_NAME, PASSWORD
import env from 'secondwheel/env'

env()

// process.env is configured

Parameters

options: EnvOptions?

Throws

EnvError // validation failure
cookie
setCookie
sets a cookie

Examples

import { setCookie } from 'secondwheel/cookie'

setCookie('cookie-name', 'cookie-value')               // browser
setCookie('cookie-name', 'cookie-value', { req, res }) // server

Parameters

name: string
value: string
options: CookieOptions?
setSessionCookie
sets a session (temporary) cookie

Examples

import { setSessionCookie } from 'secondwheel/cookie'

setSessionCookie('cookie-name', 'cookie-value')               // browser
setSessionCookie('cookie-name', 'cookie-value', { req, res }) // server

Parameters

name: string
value: string
options: CookieOptions?
getCookie
retrieves a cookie by name

Examples

import { getCookie } from 'secondwheel/cookie'

const cookieValue = getCookie('cookie-name')               // browser
const cookieValue = getCookie('cookie-name', { req, res }) // server

Parameters

name: string
options: CookieOptions?

Returns

string
removeCookie
removes a cookie

Examples

import { removeCookie } from 'secondwheel/cookie'

removeCookie('cookie-name')               // browser
removeCookie('cookie-name', { req, res }) // server

Parameters

name: string
options: CookieOptions?
setReturnTo
sets the "return to" value (current URL) into a session cookie

Examples

import { setReturnTo } from 'secondwheel/cookie'

setReturnTo()             // browser
setReturnTo({ req, res }) // server

Parameters

options: CookieOptions?
getReturnTo
returns and removes the "return to" value

Examples

import { getReturnTo } from 'secondwheel/cookie'

const cookieValue = getReturnTo()             // browser
const cookieValue = getReturnTo({ req, res }) // server

Parameters

options: CookieOptions?

Returns

string
constants
isNode
truthy when running in Node.js

Examples

import { isNode } from 'secondwheel/constants'

if (isNode) {
  // Node.js
} else {
  // not Node.js
}
isBrowser
truthy when running in a browser

Examples

import { isBrowser } from 'secondwheel/constants'

if (isBrowser) {
  // browser
} else {
  // not browser
}
NativeWebSocket
contains WebSocket or MozWebSocket from the global scope if available

Examples

import { NativeWebSocket } from 'secondwheel/constants'
theme
a documentation.js theme used to generate this documentation

Extends the @example jsdoc tag to support a language modifier (e.g. @example(scss)).
If a modifier is omitted or is not supported the language defaults to 'flow'.
Follow this link to see the full list of supported languages.

The --favicon option must be a path to an SVG file, which will be rendered in the header bar as well as automatically compiled to an ICO file and used as a favicon.

Example usage

  1. install this package - yarn add secondwheel
  2. add a script to package.json
{
  "scripts": {
    "docs": "documentation build *.js -f html -t node_modules/secondwheel/theme -o docs"
  }
}
Types
EnvOptions

Examples

import type { EnvOptions } from 'secondwheel/env'

Parameters

path: string = '<cwd>/.env' // a custom path if your file containing environment variables is located elsewhere
example: string = '<cwd>/.env.example' // path to example environment file
debug: boolean = false // turns on logging to help debug why certain keys or values are not being set as you expect
EnvError

Properties

missing: Set<string> // a list of variable names
AssertionError
A subclass of Error that indicates the failure of an assertion.

See

ReactElement
Elements are the smallest building blocks of React apps.

See

ApolloLink
ApolloLink is a standard interface for modifying control flow of GraphQL requests and fetching GraphQL results.

See

ApolloCache

See

Request
The req object represents the HTTP request and has properties for the request query string, parameters, body, HTTP headers, and so on.

See

Response
The res object represents the HTTP response that an Express app sends when it gets an HTTP request.

See

SubscriptionPayload
cookie configuration options

Examples

import type { SubscriptionPayload } from 'secondwheel/subscription'

Properties

mutation: ("CREATED" | "UPDATED" | "DELETED")
node: (Object | Array<Object>)
CookieOptions
cookie configuration options

Examples

import type { CookieOptions } from 'secondwheel/cookie'

Parameters

req: Request?
res: Response?
domain: string = req.hostname||window.location.host // see res.cookie
encode: Function? // see res.cookie
expires: Date? // see res.cookie
httpOnly: boolean? // see res.cookie
maxAge: number? // see res.cookie
path: string = '/' // see res.cookie
secure: boolean? // see res.cookie
signed: boolean? // see res.cookie
sameSite: (boolean | string)? // see res.cookie
ApolloClientOptions
ApolloClient configuration options

Examples

import type { ApolloClientOptions } from 'secondwheel/ApolloClient'

Parameters

uri: string = '/graphql'
browserUri: string = uri // used in the browser
serverUri: string = browserUri // used in Node.js
wsUri: string? // if provided a WebSocketLink will be configured
cache: Object = {} // use on the client to restore server state
onError: Function? // by default prints errors to console
ssrForceFetchDelay: number? // see apollo-client
connectToDevTools: boolean? // see apollo-client
queryDeduplication: boolean? // see apollo-client
name: string? // see apollo-client
version: string? // see apollo-client
defaultOptions: Object? // see apollo-client
wsOptions: Object = {reconnect:true} // see apollo-link-ws
webSocketImpl: WebSocket? // see apollo-link-ws
delay: Object? // see apollo-link-retry
attempts: Object? // see apollo-link-retry
includeExtensions: boolean? // see apollo-link-batch-http
headers: Object = {} // see apollo-link-batch-http
credentials: string = 'same-origin' // see apollo-link-batch-http
fetchOptions: Object = {} // see apollo-link-batch-http
useGETForQueries: boolean? // see apollo-link-batch-http
batchMax: number? // see apollo-link-batch-http
batchInterval: number? // see apollo-link-batch-http
batchKey: Function? // see apollo-link-batch-http