Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

handling errors properly #62

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 42 additions & 38 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,59 +5,63 @@ export default function ({ locals = {}, filters = {}, useMetadata = false } = {}
const opts = arguments[0] || {}

return (files, metalsmith, done) => {
setImmediate(done)

// extend with metalsmith global metadata
if (useMetadata) {
locals = Object.assign({}, locals, metalsmith.metadata())
}

Object.keys(files).forEach((file) => {
if (!/\.(pug|jade)/.test(path.extname(file))) {
return
}
try {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

only wrap the actual pug calls, not the whole logic block.

Copy link
Author

@AndyOGo AndyOGo Feb 16, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that was my initial approach too.
Buuut, the nice thing about throw is that it "breaks" forEach like break does with a classic loop.
Hence I decided to wrap the whole block.
Otherwise we would need to accumulate errors in an array...

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, I prefer to bail-out on first error, but I can quickly change it to try all files.

Object.keys(files).forEach((file) => {
if (!/\.(pug|jade)/.test(path.extname(file))) {
return
}

let data = files[file]
let dir = path.dirname(file)
let name = path.basename(file, path.extname(file))
let data = files[file]
let dir = path.dirname(file)
let name = path.basename(file, path.extname(file))

// do we need to add an extension?
if (path.extname(name) === '') {
name = path.basename(file, path.extname(file)) + '.html'
}
// do we need to add an extension?
if (path.extname(name) === '') {
name = path.basename(file, path.extname(file)) + '.html'
}

if (dir !== '.') {
name = `${dir}/${name}`
}
if (dir !== '.') {
name = `${dir}/${name}`
}

const filename = path.join(metalsmith.source(), file)
const filename = path.join(metalsmith.source(), file)

// also use the file's own data
if (useMetadata) {
locals = Object.assign(locals, data)
}
// also use the file's own data
if (useMetadata) {
locals = Object.assign(locals, data)
}

// assign filters
if (filters) {
Object.keys(filters).forEach((filter) => (pug.filters[filter] = filters[filter]))
}
// assign filters
if (filters) {
Object.keys(filters).forEach((filter) => (pug.filters[filter] = filters[filter]))
}

const options = Object.assign(opts, {
filename,
locals
})
const options = Object.assign(opts, {
filename,
locals
})

// render
let str = pug.compile(data.contents.toString(), options)(locals)
// render
let str = pug.compile(data.contents.toString(), options)(locals)

// convert to a buffer
data.contents = new Buffer(str)
// convert to a buffer
data.contents = new Buffer(str)

// remove from global files object
delete files[file]
// remove from global files object
delete files[file]

// assign the newly created file
files[name] = data
})
// assign the newly created file
files[name] = data
})

setImmediate(done)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can just call done() instead of using setImmediate given the new direction

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nope, setImmediate let's other i/o operations taking place before calling the next metalsmith plugin. see: https://nodejs.org/api/timers.html#timers_setimmediate_callback_args

} catch (err) {
setImmediate(done, err)
}
}
}
1 change: 1 addition & 0 deletions test/fixtures/should-throw/should-throw.pug
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
should*throw
13 changes: 12 additions & 1 deletion test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import rimraf from 'rimraf'
import { test } from 'tap'

test('metalsmith-jade', (tap) => {
tap.plan(9)
tap.plan(10)

tap.afterEach((done) => rimraf('test/fixtures/*/build', done))

Expand Down Expand Up @@ -162,4 +162,15 @@ test('metalsmith-jade', (tap) => {
})
})
})

tap.test('should catch thrown errors', (assert) => {
let smith = new Metalsmith('test/fixtures/should-throw')

smith.use(pug())

smith.build((err) => {
assert.ok(err)
assert.end()
})
})
})