🚧 Async data transforming with simple rules.
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
.github
build
docs
examples
src
test
.babelrc
.gitignore
.npmignore
.npmrc
.travis.yml
CHANGELOG.md
LICENSE
README.md
package.json
yarn.lock

README.md

Async data transforming with simple rules.


FeaturesWhyUsageExamplesDocumentation

Bumpover helps you writing data validation & migration script in a controllable and reliable way, which can be tedious and leaky with your bare arms.

By utilizing type annotation powered by superstruct, it's super straightforward to define your own complex data types, leaving bumpover deal with your data at runtime. Besides XML and JSON support out of the box, you can even customize bumpover with your own parser, bumping any data format interchangeable with JSON.

Features

  • Declarative XML/JSON data validating and upgrading.
  • Friendly type annotation with recursive data shape support.
  • Promise-based async node upgrading, handy for external or linked data shape. e.g., grab image by link defined in XML node, upload it to your cloud storage, then update new node's src on response ends.
  • Configurable traversing mechanism, e.g., whether returning beforehand or filtering out unknown nodes.
  • Pluggable serializer and deserializer, supporting new data format in merely tens of lines.

Why

Stable data structure is essential for a robust app, while during continual iteration, data structure always changes frequently. One common approach for compatibility is introducing more COMPAT code in business logic, which works but quickly stales codebase, sometimes with incompatible versions of data this is even not possible (Think about .doc and .docx). So here comes the necessity of data migration.

With modern web, it's trivial to ensure latest version of app code deployed on client. While for user data stored in DB, the difficulty upgrading them with script is pretty underestimated. Especially for data serialized and stored as string, parsing and migrating them can be formidable. Writing script transforming '<p>123</p>' to { paragraph: 123 } is one thing, ensuring validity for gigabytes of data is another - And this is what bumpover is designed to handle.

Another scenario utilizing bumpover is sanitizing. Say you're working with a rich content editor whose data model supports nesting, it's essential to ensure valid data structure after each user input event, e.g., pasting and dragging. Generally you'll want to write declarative rules normalizing data, and this is also what bumpover offers.

For cases mentioned above, there are existing runtime data validation tools that helps, while they're not really popularized when compared with compile time type analysis tools, e.g., TypeScript and Flow. Runtime data validation tools generally offers heavier API without much customizability, making them less friendly to work with. As an alternative, superstruct provides precise runtime data validation with a grammar closer to pure type annotations, making it powerful to express complex data types. Since bumpover relies deeply on it, it takes the advantage of superstruct to express your custom types and rules.

Usage

Before getting started, remember to install dependencies:

npm install --save bumpover superstruct

Then you can import them into your code base:

import { Bumpover } from 'bumpover'
import { struct } from 'superstruct'

With superstruct you can define your own data schema. Say you'd like to verify a node in virtual DOM tree with such shape:

const maybeNode = {
  name: 'div',
  props: { background: 'red' },
  children: []
}

We can define a struct validating this structure:

import { struct } from 'superstruct'

const Node = struct({
  name: 'string',
  props: 'object?',
  children: 'array'
})

Now we can use Node struct to validate data. You can simply call it as a function:

Node(maybeNode)

Detailed error will be thrown if data doesn't conform to the Node shape, or return the validated data when validation succeeds.

Now suppose we'd like to transform the virtual DOM data above by replacing all div tags with span tags, keeping all other nodes intact. How do we handle this with reliability? You can manually traverse data, or, simply define rules:

import { Bumpover } from 'bumpover'

const rules = [
  {
    match: node => node.name === 'div',
    update: node => Promise.resolve({
      node: { ...node, name: 'span' }
    })
  }
]

const bumper = new Bumpover(rules)
bumper.bump(data).then(console.log)

// Receive new node data.

Simply providing rules converting nodes, then bumpover will walk and transform data for you. Several points:

  • Rules are the single source of truth implementing your transform logic.
  • Use rule.match to match the node you'd like to transform.
  • Use rule.update to update node inside promise, which allows async updating.
  • Wrap new node inside node field to be resoveld.

Examples

Try out the live demo on JSFiddle to get an idea for how the API works, or to quickly verify your use case. More examples can be found in the walkthrough guide.

See examples for more working examples (WIP).

Documentation

Check out API reference for more details.

Contribution

Issues and pull requests are welcomed! This project is still in its very early age, all kinds of help are precious and appreciated.

License

This package is MIT-licensed.