<|start_filename|>try-catch-finally.js<|end_filename|>
// try-catch-finally.js | (c) <NAME> | http://git.io/tcf
(function umd(root, factory) {
  'use strict';
  /* istanbul ignore if */
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module.
    define('try-catch-finally', [], factory);
    /* istanbul ignore else */
  } else if (typeof module === 'object' && module.exports) {
    // Node. Does not work with strict CommonJS, but
    // only CommonJS-like environments that support module.exports,
    // like Node.
    module.exports = factory();
  } else {
    // Browser globals (root is window)
    root.try = root._try = factory();
  }
}(this, (function tryCatchFinallyFactory(getBoxed) {
  'use strict';

  function hasName(obj, name) {
    if (typeof name !== 'string') { return false; }
    var className = Object.prototype.toString.call(obj).toLowerCase();
    return className === '[object ' + name.toLowerCase() + ']';
  }

  function instanceOf(obj, constructor) {
    var defined = obj !== undefined && obj !== null;
    if (defined && typeof constructor === 'function') {
      // Get the 'boxed' value so instanceof works for primitive literals
      return getBoxed(obj) instanceof constructor;
    }
  }

  return function _try(tryBlock) {
    // try-catch-finally.js
    // (c) <NAME>
    // http://git.io/tcf

    // Store error in an object so we can use 'in', which will always
    // return true if a property has been set on the object, even if it
    // was set to 'undefined'.
    var state = {};

    function isUnhandledError() { return 'error' in state; }

    function setErrorHandled() { delete state.error; }

    function caughtErrorIs(expectedErr) {
      return state.error === expectedErr
        || hasName(state.error, expectedErr)
          || instanceOf(state.error, expectedErr);
    }

    try {
      if (tryBlock) { tryBlock(); }
    }
    catch (e) {
      state.error = e;
    }

    var chain = {
      catch: function _catch(expectedErr, catchBlock) {
        /*
           there is a catchBlock
           and an error was thrown
           and either it's an indiscriminate catch
           or the error matches the expected error
           */
        var callHandler = arguments.length > 0
          && isUnhandledError()
          && (catchBlock === undefined
          || caughtErrorIs(expectedErr));

        if (callHandler) {
          catchBlock = catchBlock || expectedErr;
          catchBlock(state.error);
          setErrorHandled();
        }

        return chain;
      },
      finally: function _finally(finallyBlock) {
        if (finallyBlock) {
          finallyBlock();
        }
        if (isUnhandledError()) {
          throw state.error;
        }
      }
    };

    return chain;
  };
}).bind(null, function getBoxed(obj) {
  // Injected because boxing doesn't work in strict mode </nasty>
  // https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Strict_mode#Securing_JavaScript
  // jshint strict: false
  return (function () { return this; }).call(obj);
})));


<|start_filename|>test/catch-tests.js<|end_filename|>
'use strict';
describe('catch', function () {
  var spy, assert = chai.assert;

  var objectTypes = [
    { name: 'string', value: 'blah', ctor: String },
    { name: 'number', value: 123, ctor: Number },
    { name: 'boolean', value: true, ctor: Boolean },
    { name: 'array', value: [], ctor: Array },
    { name: 'object', value: {}, ctor: Object },
    { name: 'Error', value: new Error('bosh'), ctor: Error }
  ];

  var specialTypes = [
    { name: 'undefined', value: undefined },
    { name: 'null', value: null }
  ];

  var allTypes = objectTypes.concat(specialTypes);

  function noop() {}

  function throws(throwable) {
    return function throwThing() { throw throwable; };
  }

  function fail(err) { throw new Error('catch was called with: ' + err); }

  beforeEach(function () {
    spy = function spy() {
      spy.calls.push([].slice.call(arguments));
      spy.firstCall = spy.firstCall || arguments;
    };
    spy.calls = [];
  });

  it('chains from try', function () {
    assert.isFunction(_try().catch,
      'expected to chain catch from empty try');
    assert.isFunction(_try(noop).catch,
      'expected to chain catch from non-empty try');
  });

  it('chains recursively', function () {
    assert.isFunction(_try().catch().catch,
      'expected to chain catch from empty catch');
    assert.isFunction(_try().catch(noop).catch,
      'expected to chain catch from indiscriminate catch');
    assert.isFunction(_try().catch(123, noop).catch,
      'expected to chain catch from catch by value');
    assert.isFunction(_try().catch('string', noop).catch,
      'expected to chain catch from catch by name');
    assert.isFunction(_try().catch(Boolean, noop).catch,
      'expected to chain catch from catch by constructor');
    assert.isFunction(_try().catch.call({}).catch,
      'expected to chain catch from catch with modified context');
  });

  it('ignores errors thrown in the catch block', function () {
    var throwInCatch = _try(throws(123))
      .catch.bind(null, throws(new Error('zing')));
    assert.throws(throwInCatch, Error, 'zing');
  });

  describe('indiscriminately', function () {

    allTypes.forEach(function (type) {
      it('is called when ' + type.name + ' is thrown', function () {
        _try(throws(type.value)).catch(spy);
        assert.deepEqual(spy.calls, [[type.value]],
          'expected handler to be called with thrown error');
      });
    });

    it('is not called if try block does not throw', function () {
      _try(noop).catch(fail);
    });

    it('is not called after the first match', function () {
      _try(throws({})).catch(noop).catch(fail);
    });
  });

  describe('by value', function () {

    it('is not called if try block does not throw', function () {
      _try(noop).catch(true, fail);
    });

    it('is not called if error does not match', function () {
      _try(throws('foo')).catch('bar', fail);
    });

    it('is not called after the first match', function () {
      _try(throws(123)).catch(123, noop).catch(123, fail);
    });

    allTypes.forEach(function (type) {
      it('is called when ' + type.name + ' is thrown', function () {
        _try(throws(type.value)).catch(type.value, spy);
        assert.deepEqual(spy.calls, [[type.value]],
          'expected handler to be called with thrown error');
      });
    });
  });

  describe('by name', function () {

    it('is not called if try block does not throw', function () {
      _try(noop).catch('string', fail);
    });

    it('is not called if error does not match', function () {
      _try(throws(123)).catch('boolean', fail);
    });

    it('is not called after the first match', function () {
      _try(throws(null)).catch('null', noop).catch('null', fail);
    });

    it('is not case-sensitive', function () {
      _try(throws(null)).catch('nUlL', spy);

      assert.lengthOf(spy.calls, 1,
        'expected handler to be called once');
      assert.lengthOf(spy.firstCall, 1,
        'expected handler to be called with one argument');
      assert.equal(spy.firstCall[0], null,
        'expected handler to be called with thrown error');
    });

    allTypes.forEach(function (type) {
      it('is called when ' + type.name + ' is thrown', function () {
        _try(throws(type.value)).catch(type.name, spy);
        assert.deepEqual(spy.calls, [[type.value]],
          'expected handler to be called with thrown error');
      });
    });
  });

  describe('by constructor', function () {

    it('is not called if try block does not throw', function () {
      _try(noop).catch(Object, fail);
    });

    it('is not called if error does not match', function () {
      _try(throws(true)).catch(Number, fail);
    });

    it('is not called after the first match', function () {
      _try(throws([])).catch(Array, noop).catch(Array, fail);
    });

    specialTypes.forEach(function (type) {
      it('is not called when ' + type.name + ' is thrown', function () {
        _try(throws(type.value)).catch(Function, fail);
      });
    });

    objectTypes.forEach(function (type) {
      it('is called when ' + type.name + ' is thrown', function () {
        _try(throws(type.value)).catch(type.ctor, spy);
        assert.deepEqual(spy.calls, [[type.value]],
          'expected handler to be called with thrown error');
      });
    });
  });
});


<|start_filename|>package.json<|end_filename|>
{
  "name": "try-catch-finally",
  "version": "2.0.46",
  "description": "A very small library for more flexible error catching in JavaScript.",
  "main": "try-catch-finally.js",
  "repository": {
    "type": "git",
    "url": "<EMAIL>:c24w/try-catch-finally.js.git"
  },
  "scripts": {
    "test": "npm run test-node && npm run test-chrome-headless && AMD=y npm run test-chrome-headless",
    "test-node": "istanbul test --report lcovonly -i \"$(./main-path.js)\" _mocha test",
    "test-chrome-headless": "karma start --browsers ChromeHeadlessNoSandbox",
    "test-browsers": "karma start",
    "watch": "karma start --single-run false & _mocha test -w",
    "preversion": "npm test && ./minify.sh && git add $(MINIFIED=y ./main-path.js short)",
    "build-contents": "doctoc --maxlevel 3 --title '## Contents' readme.md"
  },
  "author": "<NAME>",
  "license": "ISC",
  "readmeFilename": "readme.md",
  "devDependencies": {
    "almond": "^0.3.2",
    "chai": "^3.5.0",
    "coveralls": "^2.11.9",
    "doctoc": "^1.0.0",
    "eslint": "^2.8.0",
    "istanbul": "^0.4.3",
    "karma": "^0.13.22",
    "karma-chrome-launcher": "^2.2.0",
    "karma-firefox-launcher": "~0.1.0",
    "karma-ie-launcher": "^0.2.0",
    "karma-mocha": "^0.2.2",
    "karma-opera-launcher": "^0.3.0",
    "lodash.assign": "^4.0.8",
    "mocha": "^2.4.5",
    "uglify-js": "*"
  }
}


<|start_filename|>test-amd-bootstrap.js<|end_filename|>
'use strict';
// Make global available for tests by attaching AMD module to browser global
window._try = require('try-catch-finally');


<|start_filename|>karma.conf.js<|end_filename|>
'use strict';
module.exports = function (config) {
  // Chai first so it doesn't know about almond and AMD itself
  var files = [require.resolve('chai/chai')];
  
  // Bit nasty...
  if (process.env.AMD) {
    console.log('Testing AMD');
    // Almond before the main module
    files.push(require.resolve('almond'));
    // Main module
    files.push(require('./main-path'));
    // AMD test 'adapter' before tests
    files.push('test-amd-bootstrap.js');
  } else {
    files.push(require('./main-path'));
  }

  files.push('test/*-tests.js');

  config.set({
    basePath: '',
    frameworks: ['mocha'],
    files: files,
    exclude: [],
    preprocessors: {},
    reporters: ['progress'],
    port: 9876,
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: true,
    customLaunchers: {
      ChromeHeadlessNoSandbox: {
        base: 'ChromeHeadless',
        flags: ['--no-sandbox'] // Rquired for non-root
      }
    },
    browsers: ['ChromeHeadlessNoSandbox', 'Firefox'],
    singleRun: true,
    concurrency: Infinity
  });
};


<|start_filename|>test/try-tests.js<|end_filename|>
'use strict';
describe('try', function () {
  var assert = chai.assert;

  it('is a function', function () {
    assert.isFunction(_try);
  });

  it('calls the try block', function (done) {
    _try(done);
  });
});


<|start_filename|>test/finally-tests.js<|end_filename|>
'use strict';
describe('finally', function () {
  var assert = chai.assert;

  function throws(throwable) {
    return function throwThing() { throw throwable; };
  }

  function noop() {}

  it('chains from try', function () {
    assert.isFunction(_try().finally,
      'expected to chain from empty try');
    assert.isFunction(_try(noop).finally,
      'expected to chain from non-empty try');
  });

  it('chains from catch', function () {
    assert.isFunction(_try().catch().finally,
      'expected to chain from non-empty catch');
    assert.isFunction(_try(noop).catch(noop).finally,
      'expected to chain from indiscriminate catch');
    assert.isFunction(_try(noop).catch(123, noop).finally,
      'expected to chain from catch by value');
    assert.isFunction(_try(noop).catch('boolean', noop).finally,
      'expected to chain from catch by name');
    assert.isFunction(_try(noop).catch(Array, noop).finally,
      'expected to chain from catch by constructor');
    assert.isFunction(_try().catch().finally,
      'expected to chain from catch');
    assert.isFunction(_try().catch.call({}).finally,
      'expected to chain catch from catch with modified context');
  });

  it('ignores errors thrown in the finally block', function () {
    var throwInFinally = _try(noop)
      .finally.bind(null, throws(new Error('zing')));
    assert.throws(throwInFinally, Error, 'zing');
  });

  it('terminates the chain', function () {
    assert.isUndefined(_try().finally(),
      'expected to terminate after try');
    assert.isUndefined(_try().catch().finally(),
      'expected to terminate after catch');
  });

  it('calls the finally block', function (done) {
    _try().finally(done);
  });

  it('re-throws any uncaught error', function () {
    var throwFn = throws(new Error('blah'));
    var tcf = _try(throwFn).catch(Number, noop).finally;
    assert.throws(tcf, Error, 'blah');
  });

  it('does not re-throw if no error was thrown', function () {
    assert.doesNotThrow(_try(noop).finally);
  });

  it('does not re-throw if error was handled', function () {
    var throwFn = throws(new Error('blah'));
    assert.doesNotThrow(_try(throwFn).catch(noop).finally);
  });
});


<|start_filename|>main-path.js<|end_filename|>
#!/usr/bin/env node 
'use strict';
var path = require('path');
var pkg = require('./package.json');
var min = process.env.MINIFIED;
var mainFile = min ? pkg.main.replace('.js', '.min.js') : pkg.main;
var full = process.argv[2] !== 'short';
var mainPath = full ? path.join(__dirname, mainFile) : mainFile;

if (require.main === module) { // Called directly
  process.stdout.write(mainPath);
} else { // Required
  console.log('Using module path:', mainPath);
  module.exports = mainPath;
}


<|start_filename|>test-node-bootstrap.js<|end_filename|>
'use strict';
var assign = require('lodash.assign');

// Make globals available for tests by attaching node modules to node global
global.chai = require('chai');
global._try = require(require('./main-path'));

// Patch mocha colours
// https://github.com/mochajs/mocha/issues/1200
assign(require('mocha/lib/reporters/base').colors, {
  'pass': 92,
  'error stack': 92,
  'fast': 92,
  'light': 92,
  'diff gutter': 92,
  'diff added': 34,
  'diff removed': 33
});
