Home Reference Source

parserblade

CI

A all-in-one parser for Javascript, heavily inspired by: https://github.com/nathanmac/Parser. It allows you to work with JSON, XML, CSV and YAML more without worrying about which module install. It's designed to work just as JSON.parse and JSON.stringify does, with some improvements.

See docs for more info and examples.

Installation

$ npm install --save parserblade

Usage

Every filetype has two main methods: stringify() and parse(), both receives two arguments, data containing any type of data and an options object.

CSV

const { csv } = require('parserblade')

// Parsing
const input = 'title,platform\nStardew Valley,Steam'
const result = csv.parse(input)
console.log(result) // [ { title: 'Stardew Valley', platform: 'Steam' } ]

// Stringifying
console.log(
  csv.stringify(result)
) // 'title,platform\nStardew Valley,Steam'

YAML

const { yaml } = require('parserblade')

// Parsing
const input = 'title: Stardew Valley\nplatform: Steam'
const result = yaml.parse(input)
console.log(result) // { title: 'Stardew Valley', platform: 'Steam' }

// Stringifying
console.log(
  yaml.stringify(result)
) // 'title: Stardew Valley\nplatform: Steam'

XML

const { xml } = require('parserblade')

// Parsing
const input = '<?xml version="1.0" encoding="utf-8"?><package>lodash</package>'
const result = xml.parse(input)
console.log(result) // { package: 'lodash' }

// Stringifying
console.log(
  xml.stringify(result)
) // '<?xml version="1.0" encoding="utf-8"?><package>lodash</package>'

License

MIT ©

JSON

Parse

There's no magic here. It just calls native's JSON.parse, currently there's no additional parameters.

const assert = require('assert')
const { json } = require('parserblade')
const input = '[{"game":"Stardew Valley"}]'
const result = json.parse(input)

assert.deepStrictEqual(
  result,
  [ { game: 'Stardew Valley' } ]
)

Stringify

There's no magic here. It just calls native's JSON.stringify, currently there's no additional parameters.

const assert = require('assert')
const { json } = require('parserblade')
const input = [ { game: 'Stardew Valley' } ]
const result = json.stringify(input)

assert.equal(
  result,
  '[{"game":"Stardew Valley"}]'
)

Valid

Just checks if given string is a valid JSON data

const assert = require('assert')
const { json } = require('parserblade')
const result = json.valid('{')

assert.equal(
  result,
  false
)

Stream

Stringify an array

const { json } = require('parserblade')
const { Readable } = require('stream')
const fs = require('fs')

const input = [{ game: 'Killing Floor' }, { game: 'Stardew Valley' }]
const reader = new Readable({
  objectMode: true,
  read (size) {
    const next = input.shift()

    if (!next) {
      this.push(null)
    } else {
      this.push(next)
    }
  }
})

const writer = json.pipeStringify()
const toFile = fs.createWriteStream('./data-test.json')

reader
  .pipe(writer)
  .pipe(toFile)
  .on('error', console.log)
  .on('end', () => {
    console.log('done')
  })

Stringify an object

You must pass { type: 'object' } as param. Defaults to array.

Data must be an array of [ key, value ]. Like from Object.entries({ game: 'Stardew Valley' })

const { json } = require('parserblade')
const { Readable } = require('stream')
const fs = require('fs')

const input = Object.entries({
  name: 'Rodolfo'
})

const reader = new Readable({
  objectMode: true,
  read (size) {
    const next = input.shift()

    if (!next) {
      this.push(null)
    } else {
      this.push(next)
    }
  }
})

const writer = json.pipeStringify({ type: 'object' })
const toFile = fs.createWriteStream('./data-test.json')

reader
  .pipe(writer)
  .pipe(toFile)
  .on('error', console.log)
  .on('end', () => {
    console.log('done')
  })

Parse

const { json } = require('parserblade')
const fs = require('fs')
const path = require('path')
const filepath = path.resolve(__dirname, '../data/services.json')

const reader = fs.createReadStream(filepath)
const writer = json.pipeParse()

reader
  .pipe(writer)
  .on('data', console.log)
  .on('error', console.log)
  .on('end', () => {
    console.log('done')
  })

CSV

Works with CSV data. I haven't tested with xlsx or other similar data types yet.

Usage

Both csv.parse() and csv.stringify() accepts the data to be parsed/stringified as the first argument, and an option's object as the second.

Parse

Parses CSV string to JS data, automatically uses first line as headers. Pass data as first argument.

const assert = require('assert')
const { csv } = require('parserblade')
const input = 'title,platform\nStardew Valley,Steam'
const result = csv.parse(input)

assert.deepStrictEqual(
  result,
  [ { title: 'Stardew Valley', platform: 'Steam' } ]
)

Parse headers

Don't use first line as headers. Pass { headers: false } as second parameter.

const assert = require('assert')
const { csv } = require('parserblade')
const input = 'name,email\nNetflix,contact@netflix.com'
const result = csv.parse(input, { headers: false })

assert.deepStrictEqual(
  result,
  [
    ['name', 'email'],
    ['Netflix', 'contact@netflix.com']
  ]
)

Specify headers passing { headers: ['name', 'email'] }

const assert = require('assert')
const { csv } = require('parserblade')
const input = 'name,email\nNetflix,contact@netflix.com'
const result = csv.parse(input, { headers: false })

assert.deepStrictEqual(
  result,
  [
    { name: 'Netflix', email: 'contact@netflix.com' }
  ]
)

Specify a function to transform headers passing { headers: header => header.toUpperCase() }

const assert = require('assert')
const { csv } = require('parserblade')
const input = 'name,email\nNetflix,contact@netflix.com'
const result = csv.parse(input, { headers: false })

assert.deepStrictEqual(
  result,
  [
    { NAME: 'Netflix', EMAIL: 'contact@netflix.com' }
  ]
)

Parse with custom delimiters

Uses custom delimiters. Anything you want! Pass { delimiter: ';' } as option.

const assert = require('assert')
const { csv } = require('parserblade')
const input = 'name;email\nNetflix;contact@netflix.com'
const result = csv.parse(input, { delimiter: ';' })

assert.deepStrictEqual(
  result,
  [ { name: 'Netflix', email: 'contact@netflix.com' } ]
)

Parse skipping some lines

Pass { skipLines: 2 } as option.

const assert = require('assert')
const { csv } = require('parserblade')
const input = 'coll streaming platforms\nname,email\nNetflix,contact@netflix.com'
const result = csv.parse(input, { skipLines: 2 })

assert.deepStrictEqual(
  result,
  [ { name: 'Netflix', email: 'contact@netflix.com' } ]
)

Parse offset

Pass { offset: 2 } as option.

const assert = require('assert')
const { csv } = require('parserblade')
const input = 'name,email\nNetflix,contact@netflix.com\nAmazon,contact@amazon.com'
const result = csv.parse(input, { offset: 2 })

assert.deepStrictEqual(
  result,
  [ { name: 'Netflix', email: 'contact@netflix.com' } ]
)

Stringify

Simply transforms JS array of objects into CSV

const assert = require('assert')
const { csv } = require('parserblade')
const input = [
  { name: 'Netflix', email: 'contact@netflix.com' }
]
const result = csv.stringify(input)

assert.equal(
  result,
  'name,email\nNetflix,contact@netflix.com'
)

Stringify omitting headers

Pass { headers: false } as options

const assert = require('assert')
const { csv } = require('parserblade')
const input = [
  { name: 'Netflix', email: 'contact@netflix.com' }
]
const result = csv.stringify(input)

assert.equal(
  result,
  'Netflix,contact@netflix.com'
)

Stringify with custom column names/headers

Specifying custom columns is easy in many forms, like just pass { columns: [ { key: '', header: '' } ] } as options.

Or { columns: ['name', 'email'] }.

Or { columns: { name: 'Name', email: 'Email' } }.

const assert = require('assert')
const { csv } = require('parserblade')
const input = [
  { name: 'Netflix', email: 'contact@netflix.com' }
]

const columns = [
  { key: 'name', header: 'Platform' },
  { key: 'email', header: 'e-mail' }
]

const result = csv.stringify(input, { columns })

assert.equal(
  result,
  'Platform,e-mail\nNetflix,contact@netflix.com'
)

Valid

Just checks if given string is a valid CSV

const assert = require('assert')
const { csv } = require('parserblade')
const result = csv.valid('name\nstardew,pokemon')

assert.equal(
  result,
  false
)

Stream

pipeStringify

Turns JS data into CSV

const { csv } = require('parserblade')
const { Readable } = require('stream')
const fs = require('fs')

const input = [{ game: 'Killing Floor' }, { game: 'Stardew Valley' }]
const reader = new Readable({
  objectMode: true,
  read (size) {
    const next = input.shift()
    this.push(next || null)
  }
})

const writer = csv.pipeStringify()
const toFile = fs.createWriteStream('./data-test.csv')

reader
  .pipe(writer)
  .pipe(toFile)
  .on('error', console.log)
  .on('end', () => {
    console.log('done')
  })

pipeStringify with custom delimiter

const { csv } = require('parserblade')
const { Readable } = require('stream')
const fs = require('fs')

const input = [{ game: 'Killing Floor' }, { game: 'Stardew Valley' }]
const reader = new Readable({
  objectMode: true,
  read (size) {
    const next = input.shift()
    this.push(next || null)
  }
})

const writer = csv.pipeStringify({ delimiter: ';' })
const toFile = fs.createWriteStream('./data-test.csv')

reader
  .pipe(writer)
  .pipe(toFile)
  .on('error', console.log)
  .on('end', () => {
    console.log('done')
  })

pipeStringify with custom column names

const { csv } = require('parserblade')
const { Readable } = require('stream')
const fs = require('fs')

const input = [{ game: 'Killing Floor' }, { game: 'Stardew Valley' }]
const reader = new Readable({
  objectMode: true,
  read (size) {
    const next = input.shift()
    this.push(next || null)
  }
})

const columns = [
  { key: 'game', header: 'title' }
]

const writer = csv.pipeStringify({ columns })
const toFile = fs.createWriteStream('./data-test.csv')

reader
  .pipe(writer)
  .pipe(toFile)
  .on('error', console.log)
  .on('end', () => {
    console.log('done')
  })

pipeStringify reordering columns

const { csv } = require('parserblade')
const { Readable } = require('stream')
const fs = require('fs')

const input = [{ game: 'Killing Floor', platform: 'Windows 10' }, { game: 'Stardew Valley', platform: 'Windows 10' }]
const reader = new Readable({
  objectMode: true,
  read (size) {
    const next = input.shift()
    this.push(next || null)
  }
})

const columns = [
  { key: 'platform' },
  { key: 'game' }
]

const writer = csv.pipeStringify({ columns })
const toFile = fs.createWriteStream('./data-test.csv')

reader
  .pipe(writer)
  .pipe(toFile)
  .on('error', console.log)
  .on('end', () => {
    console.log('done')
  })

pipeParse

const { csv } = require('parserblade')
const fs = require('fs')
const path = require('path')
const filepath = path.resolve(__dirname, '../data/services.csv')

const reader = fs.createReadStream(filepath)
const writer = csv.pipeParse()

reader
  .pipe(writer)
  .on('readable', console.log)
  .on('error', console.log)
  .on('end', () => {
    console.log('done')
  })

pipeParse setting custom delimiter

const { csv } = require('parserblade')
const fs = require('fs')
const path = require('path')
const filepath = path.resolve(__dirname, '../data/services.csv')

const reader = fs.createReadStream(filepath)
const writer = csv.pipeParse({ delimiter: ';' })

reader
  .pipe(writer)
  .on('readable', console.log)
  .on('error', console.log)
  .on('end', () => {
    console.log('done')
  })

pipeParse without using first line as header

const { csv } = require('parserblade')
const fs = require('fs')
const path = require('path')
const filepath = path.resolve(__dirname, '../data/services.csv')

const reader = fs.createReadStream(filepath)
const writer = csv.pipeParse({ headers: false })

reader
  .pipe(writer)
  .on('readable', console.log)
  .on('error', console.log)
  .on('end', () => {
    console.log('done')
  })

XML

Works with XML data. I haven't tested with xlsx or other similar data types yet. There's a lot of things to improve here.

Usage

Both xml.parse() and xml.stringify() accepts the data to be parsed/stringified as the first argument, and an option's object as the second.

Parse

const assert = require('assert')
const { xml } = require('parserblade')
const input = '<?xml version="1.0" encoding="utf-8"?><games><name>Naruto Shippuden Storm 3</name><platform>playstation</platform></games>'
const result = xml.parse(input)

assert.deepStrictEqual(
  result,
  {
    games: {
      name: { _text: 'Naruto Shippuden Storm 3' },
      platform: { _text: 'playstation' }
    }
  }
)
const assert = require('assert')
const { xml } = require('parserblade')
const input = '<?xml version="1.0" encoding="utf-8"?><packages><name>mongoose</name><name>sequelize</name></packages>'
const result = xml.parse(input)

assert.deepStrictEqual(
  result,
  {
    packages: {
      name: [
        { _text: 'mongoose' },
        { _text: 'sequelize' }
      ]
    }
  }
)

Parse XML including declaration

Pass { showDeclaration: true } as option.

const assert = require('assert')
const { xml } = require('parserblade')
const input = '<?xml version="1.0" encoding="utf-8"?><packages><name>mongoose</name><name>sequelize</name></packages>'
const result = xml.parse(input, { showDeclaration: true })

assert.deepStrictEqual(
  result,
  {
    _declaration: {
      _attributes: {
        encoding: 'utf-8',
        version: 1
      }
    },
    packages: {
      name: [
        { _text: 'mongoose' },
        { _text: 'sequelize' }
      ]
    }
  }
)

Parse XML in verbose mode

Pass { verbose: true } as option.

const assert = require('assert')
const { xml } = require('parserblade')
const input = '<?xml version="1.0" encoding="utf-8"?><games><name>Naruto Shippuden Storm 3</name><platform>playstation</platform></games>'
const result = xml.parse(input, { verbose: true })
const expected = {
  elements: [
    {
      type: 'element',
      name: 'games',
      elements: [
        {
          type: 'element',
          name: 'name',
          elements: [
            {
              type: 'text',
              text: 'Naruto Shippuden Storm 3'
            }
          ]
        },
        {
          type: 'element',
          name: 'platform',
          elements: [
            {
              type: 'text',
              text: 'playstation'
            }
          ]
        },
      ]
    }
  ]
}

assert.deepStrictEqual(
  result,
  expected
)

Stringify

const assert = require('assert')
const { xml } = require('parserblade')
const input = { game: 'Stardew Valley' }
const result = xml.stringify(input)

assert.deepStrictEqual(
  result,
  '<?xml version="1.0" encoding="utf-8"?><game>Stardew Valley</game>'
)

Stringify without XML declaration

const assert = require('assert')
const { xml } = require('parserblade')
const input = { game: 'Stardew Valley' }
const result = xml.stringify(input, { ignoreDeclaration: true })

assert.deepStrictEqual(
  result,
  '<game>Stardew Valley</game>'
)

Stringify array

const assert = require('assert')
const { xml } = require('parserblade')
const input = {
  packages: [
    { name: 'lodash' }
  ]
}
const result = xml.stringify(input)

assert.deepStrictEqual(
  result,
  '<?xml version="1.0" encoding="utf-8"?><packages><name>lodash</name></packages>'
)

Stringify with metadata

const assert = require('assert')
const { xml } = require('parserblade')
const input = {
  packages: [
    {
      _text: 'lodash',
      _attributes: { lang: 'nodejs' }
    },
    {
      _text: 'flash',
      _attributes: { lang: 'python' }
    }
  ]
}
const result = xml.stringify(input)

assert.deepStrictEqual(
  result,
  '<?xml version="1.0" encoding="utf-8"?><packages lang="nodejs">lodash</packages><packages lang="python">flash</packages>'
)

Valid

Just checks if given string is a valid XML

const assert = require('assert')
const { xml } = require('parserblade')
const result = xml.valid('phrase<tag />')

assert.equal(
  result,
  false
)

Stream

pipeParse

You may specify in which depth it should emit data, defaults to 0.

const { Readable } = require('stream')
const { xml } = require('parserblade')
const input = `
<?xml version="1.0" encoding="utf-8"?>
<info>
  <name>Naruto Shippuden Storm 3</name>
  <platform>
    platform
    <another>
      This is another tag
    </another>
    <another>
      Third tag another
    </another>
  </platform>
  <site url="netflix">
    Netflix
    <description>
      Possible description here
    </description>
  </site>
</info>
`.split('')

const reader = new Readable({
  read () {
    const next = input.shift()
    if (typeof next === 'string') {
      this.push(next)
    } else {
      this.push(null)
    }
  }
})

reader
  .pipe(xml.pipeParse())
  .on('data', console.log)
  .on('error', console.log)
  .on('end', () => console.log('stream ended'))

pipeStringify

You can set which tag wraps everything with { mainTag: { name, text, attributes } }

const { Readable } = require('stream')
const { xml } = require('parserblade')
const input = [{ name: 'Starcraft II' }]

const reader = new Readable({
  objectMode: true,
  read () {
    const next = input.shift()
    this.push(next || null)
  }
})

reader
  .pipe(xml.pipeParse({ mainTag: { name: 'games' } }))
  .on('data', console.log)
  .on('error', console.log)
  .on('end', () => console.log('stream ended'))

YAML

Usage

Both yaml.parse() and yaml.stringify() accepts the data to be parsed/stringified as the first argument, and an option's object as the second.

Parse

const assert = require('assert'')
const { yaml } = require('parserblade')
const input = 'series: Bleach\nseasons: 16'
const result = yaml.parse(data)
assert.deepStrictEqual(
  result,
  { series: 'Bleach', seasons: 16 }
)

Stringify

const assert = require('assert'')
const { yaml } = require('parserblade')
const input = { series: 'Bleach', seasons: 16 }
const result = yaml.parse(data)
assert.equal(
  result,
  'series: Bleach\nseasons: 16'
)

Valid

Just checks if given string is a valid YAML

const assert = require('assert')
const { yaml } = require('parserblade')
const result = yaml.valid('[name:\nStardew')

assert.equal(
  result,
  false
)