Skip to content

Commit

Permalink
feat: add tree.error, tree.warn && tree.dependency (Messages API)
Browse files Browse the repository at this point in the history
  • Loading branch information
michael-ciniawsky committed Dec 16, 2017
1 parent 4381164 commit 12e1f0a
Show file tree
Hide file tree
Showing 5 changed files with 243 additions and 2 deletions.
47 changes: 47 additions & 0 deletions lib/Error/frame.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
const chalk = require('chalk')

const frame = (err) => {
err.message = err.name === 'PluginError'
? `❌ ${err.name}: ${err.plugin}\n\n`
: `⚠️ ${err.name}: ${err.plugin}\n\n`

err.message += `[${err.location.line}:${err.location.column}] ${
err.message.length > 80
? `${err.message.substr(0, 70)}\n${
err.message.substr(70, err.message.length)
}`
: err.message
}\n\n`

let _ = ''
while (_.length < 80) _ += ' '

err.message += chalk.underline(
`${err.file}${_.substr(err.file.length, 80)}\n\n`
)

const frames = err.src.split('\n')

const format = (src, line) => src.slice(Math.max(0, line - 3), line + 2)

format(frames, err.location.line).forEach((frame, i) => {
const line = err.location.line + i - 2

let offset = ''
const cursor = err.location.column

while (offset.length < cursor + 5) offset += ' '

err.message += line === err.location.line
? chalk.inverse(`\n > ${err.location.line}| ${frame} \n`) + `${offset}🔺\n`
: chalk.white(`${err.location.line}| ${frame}\n`)
})

err.message += chalk.underline(`${_}\n`)

return err.name === 'PluginError'
? chalk.bold.red(`${err.message}\n`)
: chalk.bold.yellow(`${err.message}\n`)
}

module.exports = frame
16 changes: 16 additions & 0 deletions lib/Error/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
const code = require('./frame')

class PluginError extends Error {
constructor (err) {
super(err)

this.name = err.name
this.message = err.location ? code(err) : err.message

if (!err.stack) this.stack = false

Error.captureStackTrace(this, this.constructor)
}
}

module.exports = PluginError
101 changes: 100 additions & 1 deletion lib/api.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
'use strict'

const PluginError = require('./Error')

/**
* # API
* @author Ivan Voischev (@voischev),
Expand Down Expand Up @@ -104,7 +107,103 @@ module.exports = {
* }
* ```
*/
messages: []
// BUG previous messages aren't cleaned up
// messages: [],
/**
* Messages Error API
*
* push plugin errors to result.messages for reporting
*
* @memberof tree
*
* @method error
*
* @param {String} plugin Name ('posthtml-plugin')
* @param {String} message Error
*
* @return {Object} PostHTML Error Message
*
* ```js
* tree.error('posthtml-plugin', 'Error', node.location)
* ```
*/
error: function (plugin, message, location) {
const err = new PluginError({
src: this.src,
file: this.options.from,
name: 'PluginError',
plugin,
message,
location: location || false
})

return this.messages.push({
type: 'error',
file: this.options.from,
plugin,
message: err.message
})
},
/**
* Messages Warning API
*
* push plugin warnings to result.messages for reporting
*
* @memberof tree
*
* @method warning
*
* @param {String} plugin Name ('posthtml-plugin')
* @param {String} message Warning
*
* @return {Object} PostHTML Warning Message
*
* ```js
* tree.warning('posthtml-plugin', 'Warning', node.location)
* ```
*/
warn: function (plugin, message, location) {
const warning = new PluginError({
src: this.src,
file: this.options.from,
name: 'PluginWarning',
plugin,
message,
location: location || false
})

return this.messages.push({
type: 'warning',
file: this.options.from,
plugin,
message () {
return warning.message
}
})
},
/**
* Message Dependency API
*
* push dependencies added by plugins to result.messages for reporting/watching
* @memberof tree
*
* @method dependency
*
* @param {String} file File
*
* @return {Object} PostHTML Dependency Message
*
* ```js
* tree.dependency('path/to/file.ext')
* ```
*/
dependency: function (file) {
return this.messages.push({
type: 'dependency',
file,
from: this.options.from
})
}
}

/** @private */
Expand Down
10 changes: 9 additions & 1 deletion lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,13 @@ PostHTML.prototype.process = function (tree, options) {
if (options.parser) parser = options.parser
if (options.render) render = options.render

tree.src = tree

tree = options.skipParse ? tree : parser(tree, options)

tree.options = options
tree.messages = []

tree.processor = this

// sync mode
Expand Down Expand Up @@ -236,7 +240,11 @@ function tryCatch (tryFn, catchFn) {
function apiExtend (tree) {
tree.walk = api.walk
tree.match = api.match
tree.messages = api.messages
// BUG previous messages aren't cleaned up
// tree.messages = api.messages
tree.warn = api.warn
tree.error = api.error
tree.dependency = api.dependency
}

/**
Expand Down
71 changes: 71 additions & 0 deletions test/Error.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
var it = require('mocha').it
var expect = require('chai').expect
var describe = require('mocha').describe

var posthtml = require('../lib')

var html = '<div class="messages">Messages</div>'
var messages = [
{
type: 'warning',
file: './index.html',
plugin: 'posthtml-plugin',
message: "I'm a warning"
},
{
type: 'error',
file: './index.html',
plugin: 'posthtml-plugin',
message: "I'm an Error"
},
{
type: 'dependency',
file: 'path/to/1.html',
from: './index.html'
}
]

function test (html, done) {
posthtml()
.use(function (tree) {
tree.warn('posthtml-plugin', 'I\'m a warning', false)

return tree
})
.use(function (tree) {
tree.error('posthtml-plugin', 'I\'m an Error', false)

return tree
})
.use(function (tree) {
tree.dependency('path/to/1.html')

return tree
})
.process(html, { from: './index.html' })
.then(function (result) {
result.messages = result.messages.map(function (msg) {
if (msg.message) {
msg.message = typeof msg.message === 'function'
? msg.message()
: msg.message
}

return msg
})

expect(html).to.eql(result.html)
expect(messages).to.eql(result.messages)

done()
})
.catch(function (error) {
done(error)
})
}

describe('Messages', function () {
it('should expose messages via result.messages', function (done) {
test(html, done)
})
})

0 comments on commit 12e1f0a

Please sign in to comment.