Permalink
Browse files

Initial release

  • Loading branch information...
1 parent 36222e1 commit d2e9129a1080570d45c62ce5fffa12631209ce0a @DennisKehrig committed May 3, 2012
Showing with 379 additions and 1 deletion.
  1. +1 −0 .npmignore
  2. +3 −0 CHANGELOG.md
  3. +19 −0 LICENSE
  4. +18 −1 README.md
  5. +3 −0 compile.bat
  6. +156 −0 lib/exception-handler.js
  7. +28 −0 package.json
  8. +151 −0 src/exception-handler.coffee
View
@@ -0,0 +1 @@
+.git*
View
@@ -0,0 +1,3 @@
+**v0.1.0** (2012-05-04):
+
+ - Initial release
View
19 LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2012 Dennis Kehrig <mailgithub@denniskehrig.de>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
View
@@ -1,4 +1,21 @@
ANSInception
============
-Colorful exception handler for Node.js with CoffeeScript support and improved nodemon/supervisor compatibility
+Colorful exception handler for Node.js with CoffeeScript support and improved nodemon/supervisor compatibility
+
+* Quits after a delay to prevent nodemon, supervisor, etc. from eating console.log output
+* Show up to five lines of code from each entry in the stack trace
+* Color codes the offending part of the code (based on the column number)
+* Compiles CoffeeScript to show the actual offending code (otherwise the line numbers don't make sense)
+* Highlights the file name in stack trace paths
+
+Usage
+-----
+
+__CoffeeScript:__
+
+ process.on 'uncaughtException', require 'ansinception'
+
+__JavaScript:__
+
+ process.on('uncaughtException', require('ansinception'));
View
@@ -0,0 +1,3 @@
+@echo off
+call coffee -c src\exception-handler.coffee
+move src\exception-handler.js lib
View
Oops, something went wrong.
View
@@ -0,0 +1,28 @@
+{
+ "name": "ansinception",
+ "version": "0.1.0",
+ "description": "Colorful exception handler for Node.js with CoffeeScript support and improved nodemon/supervisor compatibility",
+ "author": {
+ "name": "Dennis Kehrig"
+ },
+ "keywords": [
+ "exception",
+ "handler",
+ "node",
+ "nodemon",
+ "supervisor",
+ "coffeescript"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/DennisKehrig/ANSInception.git"
+ },
+ "bugs": "https://github.com/DennisKehrig/ANSInception/issues",
+ "engines": {
+ "node": "*"
+ },
+ "devDependencies": {
+ "coffee-script": ">=1.3.0"
+ },
+ "main": "./lib/exception-handler"
+}
@@ -0,0 +1,151 @@
+fs = require 'fs'
+# CoffeeScript is lazy loaded, so it's only a requirement if you actually use it yourself
+coffee = null
+
+# ANSI color madness
+# http://en.wikipedia.org/wiki/ANSI_escape_code
+ansi = (args...) -> "\x1B[" + args.join(';') + "m"
+
+reset = ansi 0
+bright = ansi 1, 1
+normal = ansi 1, 22
+
+red = ansi 1, 31
+green = ansi 1, 32
+yellow = ansi 1, 33
+blue = ansi 1, 34
+magenta = ansi 1, 35
+cyan = ansi 1, 36
+white = ansi 1, 37
+
+darkRed = red + normal
+darkGreen = green + normal
+darkYellow = yellow + normal
+darkBlue = blue + normal
+darkMagenta = magenta + normal
+darkCyan = cyan + normal
+darkWhite = white + normal
+
+brightRed = red + bright
+brightGreen = green + bright
+brightYellow = yellow + bright
+brightBlue = blue + bright
+brightMagenta = magenta + bright
+brightCyan = cyan + bright
+brightWhite = white + bright
+
+# Configuration
+baseColor = brightWhite
+extraLines = 2
+
+# Two formats for the stack trace:
+# at <context> (<path>:<line>:<column>)
+format1 = /^\s*at (.*) \(([^\)]+):(\d+):(\d+)\)$/
+# at <path>:<line>:<column>
+format2 = /^\s*at ()([^\)]+):(\d+):(\d+)$/
+# The exception handler
+module.exports = (exception) ->
+
+ # Start off with how the app was started in the first place
+ console.log "\n#{baseColor} ,-- $ #{brightCyan}#{process.argv.join ' '}#{reset}"
+
+ # Split the stack into lines
+ stack = exception.stack.split "\n"
+ # Remove the first line and store it as the message
+ message = stack.shift()
+
+ # Print the stack chronologically
+ for entry in stack.reverse()
+ # Try to recognize the format
+ if entry.match(format1) or entry.match(format2)
+ # Crashing exception handlers suck, right?
+ try
+ # Context, File, Line, Column
+ logStackEntry RegExp.$1, RegExp.$2, RegExp.$3, RegExp.$4
+ catch err
+ console.log "Error while printing offending stack entry:"
+ console.log err.stack
+ # Just dump the line if we don't recognize it
+ else
+ console.log "#{baseColor} `-> #{entry}#{reset}"
+
+ console.log "#{baseColor} `-> #{brightRed}#{message}#{reset}\n"
+
+ # Delay exiting when an exception occurs so console.log calls that occured
+ # just before the error are also printed by nodemon, supervisor, etc.
+ setTimeout ->
+ console.log "Now quitting"
+ process.exit 1
+ , 500
+
+logStackEntry = (context, file, lineNumber, columnNumber) ->
+ # Working directory
+ cwd = process.cwd()
+ # Regular expression to recoginize the current working directory
+ cwdPattern = new RegExp escapeRegExp(cwd)+'[\\/\\\\]'
+
+ # Use different colors for the file and offending line depending on the code location
+ [darkColor, brightColor] = if file.slice(0, cwd.length) isnt cwd
+ # Node.js internal or global library
+ [darkMagenta, brightMagenta]
+ else if file.slice(cwd.length + 1, cwd.length + 13) is 'node_modules'
+ # Local library
+ [darkYellow, brightYellow]
+ else
+ # Own code
+ [darkGreen, brightGreen]
+
+ # Make the file name brighter than the rest of the path
+ coloredFile = darkColor + file.replace(cwdPattern, '').replace(/([^\/\\]+)$/, brightColor + '$1')
+ # The context isn't always defined
+ wrappedContext = if context then " (#{context})" else ''
+
+ # Print the stack entry
+ console.log "#{baseColor} `-> #{coloredFile}#{baseColor}#{wrappedContext}#{reset}"
+
+ # Try to read the code
+ try
+ code = fs.readFileSync(file, "ascii")
+ catch err
+ # Just skip to the next stack entry if the source isn't found
+ return if err.code == 'ENOENT'
+ throw err
+
+ # Compile CoffeeScript so the line number makes sense
+ coffee ?= require 'coffee-script'
+ code = coffee.compile code if file.match /\.coffee$/
+ # Split the code into lines
+ lines = code.split "\n"
+ # Turn line into an index
+ lineIndex = lineNumber - 1
+
+ # Read two lines before and after the offending one
+ for i in [(lineIndex-extraLines)..(lineIndex+extraLines)]
+ break if i >= lines.length
+
+ numColor = darkWhite
+ num = padLeft(i+1, ' ', 5)
+ line = lines[i]
+
+ if i < lineIndex
+ sep = ' '
+ else if i is lineIndex
+ sep = ',--'
+ numColor = brightRed
+ line = darkColor + line.slice(0, columnNumber-1) + brightColor + line.slice(columnNumber-1) + reset
+ else if i > lineIndex
+ sep = '| '
+
+ console.log "#{numColor}#{num} #{baseColor}#{sep}#{reset} #{line}#{reset}"
+
+# Make a string safe to be used in a regular expression
+# http://simonwillison.net/2006/Jan/20/escape/#p-6
+escapeRegExp = (text) ->
+ text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&")
+
+# '****123' is padLeft('123', '*', 7)
+padLeft = (string, fill, length) ->
+ string = String(string)
+ string = fill + string while string.length < length
+ return string
+

0 comments on commit d2e9129

Please sign in to comment.