From 045c38a2be03fed0426f13de72cf52101c5171a7 Mon Sep 17 00:00:00 2001 From: Steve Senbud Date: Wed, 30 Dec 2015 10:01:24 -0800 Subject: [PATCH 01/17] Update credentials for Travis CI. --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index b976e10..3d5a3dd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,5 +9,5 @@ addons: sauce_connect: true env: global: - - secure: WrorXhIe0hgRgvaBzNK6PSQEw2VTHKCxqkkNXqIY80eESXETC9nw0WkeALa6Neu06G2K6PxCXuVnaDAAtEarkawiY2OD1jrQEeYm9/2Mnqj8K2f92y57a3uVmUmo4+sqRTj6Ub3q0+/hLhluRWGTNia3kmW8cJKKG6cyWxCwb/o= - - secure: WwBqBCm1q/iIM11n3cBPCwt5X+q62WxlfQGK4KPHlikjUExgLgksc5/ae8TwFwHpL3cL5P4h4I5MfrIK++9vFrn7CICVMkI0LeLTgXCaeUThWP43FsPvG1GrWAJYeXeRk8kc/5gBT+/8x5FxZUunvivIu+gYrqX+Ip7xwfcbGlo= + - secure: VGFNdtgz47pAI9fgXyej0Z10qdcHMjYBgCrHQQLdxDnsEtPqQL77H/TTGgw9xq1wF9BmVM2AS3bCrmHmgZboHaG0QSx813eiNs5ewQvSutrDMpBVqyKcnHvYf3L5WSeOvW8nCcKlh8TTaNSGc27+x0x6UGppI8NfVbZQvjcef5g= + - secure: iEbcv7NrXQtl91xn10xl2z+s76a0Isg5WO6RqCAqeXS9/OWgxgbubLFCPZwfdIMYOpdj7U03iaKL1CzOmT5rFOjM/nxyVu9k7q5WYXwW9HnecVPbXGWEQv6VDDV9QH1Lbh/KtwFKl5YJw7nFTzhCnT6g33aocywwAKL6cwjSQn4= From 085e75879c6e1038d4e1a4f91fea560f6b31efac Mon Sep 17 00:00:00 2001 From: Steve Senbud Date: Wed, 30 Dec 2015 10:01:47 -0800 Subject: [PATCH 02/17] Allow functions created in a loop. --- .jshintrc | 1 + 1 file changed, 1 insertion(+) diff --git a/.jshintrc b/.jshintrc index c1aba6e..a0a38db 100644 --- a/.jshintrc +++ b/.jshintrc @@ -13,6 +13,7 @@ "immed": true, "browser": true, "es3": true, + "loopfunc": true, "camelcase": true, "nonbsp": true, "freeze": true, From 93c2d7f1bb1898c746c061704961e9a59dd620ed Mon Sep 17 00:00:00 2001 From: Steve Senbud Date: Wed, 30 Dec 2015 10:02:16 -0800 Subject: [PATCH 03/17] Add a bunch of browsers to CI. --- karma.conf.ci.js | 125 +++++++++++++++++++++++++++-------------------- 1 file changed, 71 insertions(+), 54 deletions(-) diff --git a/karma.conf.ci.js b/karma.conf.ci.js index 792414a..0976985 100644 --- a/karma.conf.ci.js +++ b/karma.conf.ci.js @@ -4,92 +4,109 @@ module.exports = function (config) { process.exit(1); } - // Commented some of these out just so CI doesn't take forever. // Check out https://saucelabs.com/platforms for all browser/platform combos var customLaunchers = { - //slIOS7: { - // base: 'SauceLabs', - // browserName: 'iPhone', - // platform: 'OS X 10.9', - // version: '7.1' - //}, slIOS8: { base: 'SauceLabs', browserName: 'iPhone', - platform: 'OS X 10.9', - version: '8.1' + platform: 'OS X 10.10', + version: '8.4' + }, + slIOS9: { + base: 'SauceLabs', + browserName: 'iPhone', + platform: 'OS X 10.11', + version: '9.1' + }, + slAndroid4: { + base: 'SauceLabs', + browserName: 'Android', + platform: 'Linux', + version: '4.4' + }, + slAndroid5: { + base: 'SauceLabs', + browserName: 'Android', + platform: 'Linux', + version: '5.1' }, - //slAndroid4: { - // base: 'SauceLabs', - // browserName: 'Android', - // platform: 'Linux', - // version: '4.0' - //}, slChrome: { base: 'SauceLabs', browserName: 'chrome' }, - slFirefox: { + slChromeBeta: { + base: 'SauceLabs', + browserName: 'chrome', + version: 'beta' + }, + slChromeCanary: { base: 'SauceLabs', - browserName: 'firefox' + browserName: 'chrome', + version: 'dev' }, - slSafari6: { + slFirefox43: { + base: 'SauceLabs', + browserName: 'firefox', + platform: 'Windows 8.1', + version: '43.0' + }, + slFirefoxDev: { + base: 'SauceLabs', + browserName: 'firefox', + version: 'dev' + }, + slSafari8: { base: 'SauceLabs', browserName: 'safari', - platform: 'OS X 10.8', - version: '6' + platform: 'OS X 10.10', + version: '8' + }, + slSafari9: { + base: 'SauceLabs', + browserName: 'safari', + platform: 'OS X 10.11', + version: '9' }, - //slSafari7: { - // base: 'SauceLabs', - // browserName: 'safari', - // platform: 'OS X 10.9', - // version: '7' - //}, - //slSafari8: { - // base: 'SauceLabs', - // browserName: 'safari', - // platform: 'OS X 10.10', - // version: '8' - //} slOpera: { base: 'SauceLabs', browserName: 'opera' }, + slEdge20: { + base: 'SauceLabs', + browserName: 'microsoftedge', + platform: 'Windows 10', + version: '20.10240' + }, slIE11: { base: 'SauceLabs', browserName: 'internet explorer', platform: 'Windows 8.1', version: '11' }, - //slIE10: { - // base: 'SauceLabs', - // browserName: 'internet explorer', - // platform: 'Windows 8', - // version: '10' - //}, - //slIE9: { - // base: 'SauceLabs', - // browserName: 'internet explorer', - // platform: 'Windows 7', - // version: '9' - //} - //slIE8: { - // base: 'SauceLabs', - // browserName: 'internet explorer', - // platform: 'Windows XP', - // version: '8' - //} - slIE7: { + slIE10: { + base: 'SauceLabs', + browserName: 'internet explorer', + platform: 'Windows 8', + version: '10' + }, + slIE9: { + base: 'SauceLabs', + browserName: 'internet explorer', + platform: 'Windows 7', + version: '9' + }, + slIE8: { base: 'SauceLabs', browserName: 'internet explorer', platform: 'Windows XP', - version: '7' + version: '8' } - //slIE6: { + // Too unreliable on Sauce :( + //slIE7: { // base: 'SauceLabs', // browserName: 'internet explorer', // platform: 'Windows XP', - // version: '6' + // version: '7' //} }; From 7fea06d2f74706cde5b8c4ebfcf2ddc7c4e9ca25 Mon Sep 17 00:00:00 2001 From: Steve Senbud Date: Wed, 30 Dec 2015 10:03:06 -0800 Subject: [PATCH 04/17] API Changes for v1.0. Fixes #4 and #8. StackFrames can be optionally constructed with an Object. This is necessary in order to avoid an explosion of constructor params. eval() origin information can now be represented in a StackFrame. This is done through setEvalOrigin() where one can store a "child" StackFrame that represents location information within the eval'd String or Function. --- README.md | 23 ++++++- gulpfile.js | 10 +-- package.json | 37 ++++++----- spec/stackframe-spec.js | 72 +++++++++++++++++++-- stackframe.js | 137 +++++++++++++++++++++++----------------- 5 files changed, 191 insertions(+), 88 deletions(-) diff --git a/README.md b/README.md index 0a0b4d8..954b2a8 100644 --- a/README.md +++ b/README.md @@ -3,14 +3,23 @@ stackframe ## JS Object representation of a stack frame [![Build Status](https://travis-ci.org/stacktracejs/stackframe.svg?branch=master)](https://travis-ci.org/stacktracejs/stackframe) [![Coverage Status](https://img.shields.io/coveralls/stacktracejs/stackframe.svg)](https://coveralls.io/r/stacktracejs/stackframe?branch=master) [![Code Climate](https://codeclimate.com/github/stacktracejs/stackframe/badges/gpa.svg)](https://codeclimate.com/github/stacktracejs/stackframe) -Underlies functionality of other modules within [stacktrace.js](http://www.stacktracejs.com). +Underlies functionality of other modules within [stacktrace.js](https://www.stacktracejs.com). -Written to closely resemble StackFrame representations in [Gecko](http://mxr.mozilla.org/mozilla-central/source/xpcom/base/nsIException.idl#14) and [V8](https://code.google.com/p/v8-wiki/wiki/JavaScriptStackTraceApi) +Written to closely resemble StackFrame representations in [Gecko](http://mxr.mozilla.org/mozilla-central/source/xpcom/base/nsIException.idl#14) and [V8](https://github.com/v8/v8/wiki/Stack%20Trace%20API) ## Usage ```js // Create StackFrame and set properties -var stackFrame = new StackFrame('funName', ['args'], 'http://localhost:3000/file.js', 1, 3288, 'ORIGINAL_STACK_LINE'); +var stackFrame = new StackFrame({ + functionName: 'funName', + args: ['args'], + fileName: 'http://localhost:3000/file.js', + lineNumber: 1, + columnNumber: 3288, + isEval: true, + isNative: false, + source: 'ORIGINAL_STACK_LINE' +}); stackFrame.functionName // => "funName" stackFrame.setFunctionName('newName') @@ -36,6 +45,14 @@ stackFrame.source // => 'ORIGINAL_STACK_LINE' stackFrame.setSource('NEW_SOURCE') stackFrame.getSource() // => 'NEW_SOURCE' +stackFrame.isEval // => true +stackFrame.setIsEval(false) +stackFrame.getIsEval() // => false + +stackFrame.isNative // => false +stackFrame.setIsNative(true) +stackFrame.getIsNative() // => true + stackFrame.toString() // => 'funName(args)@http://localhost:3000/file.js:325:20' ``` diff --git a/gulpfile.js b/gulpfile.js index 8c023a5..a51c5f0 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -2,7 +2,7 @@ var coveralls = require('gulp-coveralls'); var del = require('del'); var gulp = require('gulp'); var jshint = require('gulp-jshint'); -var karma = require('karma').server; +var karma = require('karma'); var rename = require('gulp-rename'); var runSequence = require('run-sequence'); var sourcemaps = require('gulp-sourcemaps'); @@ -19,17 +19,17 @@ gulp.task('lint', function () { }); gulp.task('test', function (done) { - karma.start({ + new karma.Server({ configFile: __dirname + '/karma.conf.js', singleRun: true - }, done); + }, done).start(); }); gulp.task('test-ci', ['copy', 'dist'], function (done) { - karma.start({ + new karma.Server({ configFile: __dirname + '/karma.conf.ci.js', singleRun: true - }, done); + }, done).start(); }); gulp.task('copy', function () { diff --git a/package.json b/package.json index ff6d019..ec88952 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "Victor Homyakov (https://github.com/victor-homyakov)", "Oliver Salzburg (https://github.com/oliversalzburg)" ], - "version": "0.3.1", + "version": "1.0.0", "license": "SEE LICENSE IN LICENSE", "keywords": [ "stacktrace", @@ -14,32 +14,34 @@ "debugger", "stack frame" ], - "homepage": "http://www.stacktracejs.com", + "homepage": "https://www.stacktracejs.com", "repository": { "type": "git", "url": "git://github.com/stacktracejs/stackframe.git" }, "devDependencies": { "colors": "^1.1.2", - "del": "^1.2.0", + "del": "^2.2.0", "gulp": "^3.9.0", "gulp-coveralls": "^0.1.4", - "gulp-jshint": "^1.11.2", + "gulp-jshint": "^2.0.0", "gulp-rename": "^1.2.2", - "gulp-sourcemaps": "^1.5.2", - "gulp-uglify": "^1.2.0", - "jasmine-node": "~1.14", - "karma": "~0.12", - "karma-chrome-launcher": "^0.1.5", - "karma-coverage": "^0.2.6", - "karma-firefox-launcher": "^0.1.3", - "karma-ie-launcher": "^0.1.5", - "karma-jasmine": "^0.2.3", - "karma-opera-launcher": "^0.1.0", - "karma-phantomjs2-launcher": "^0.3.0", + "gulp-sourcemaps": "^1.6.0", + "gulp-uglify": "^1.5.1", + "jasmine": "^2.4.1", + "jasmine-core": "^2.4.1", + "jshint": "^2.8.0", + "karma": "^0.13.15", + "karma-chrome-launcher": "^0.2.2", + "karma-coverage": "^0.5.3", + "karma-firefox-launcher": "^0.1.7", + "karma-ie-launcher": "^0.2.0", + "karma-jasmine": "^0.3.6", + "karma-opera-launcher": "^0.3.0", + "karma-phantomjs2-launcher": "^0.3.2", "karma-safari-launcher": "^0.1.1", - "karma-sauce-launcher": "^0.2.10", - "run-sequence": "^1.1.2" + "karma-sauce-launcher": "^0.3.0", + "run-sequence": "^1.1.5" }, "bugs": { "url": "https://github.com/stacktracejs/stackframe/issues" @@ -49,3 +51,4 @@ "test": "gulp test" } } + diff --git a/spec/stackframe-spec.js b/spec/stackframe-spec.js index b3f3ae1..81ee17b 100644 --- a/spec/stackframe-spec.js +++ b/spec/stackframe-spec.js @@ -8,7 +8,7 @@ describe('StackFrame', function () { it('throws an error given an illogical line number', function() { var fn = function () { - new StackFrame('foo', [], 'path/to/file.js', 'BOGUS'); + new StackFrame({lineNumber: 'BOGUS'}); }; expect(fn).toThrow(); }); @@ -38,6 +38,26 @@ describe('StackFrame', function () { }); }); + describe('#setEvalOrigin', function() { + var unit = new StackFrame(); + + it('throws an error given a non-Object', function() { + expect(function() { + unit.setEvalOrigin('BOGUS'); + }).toThrow(new TypeError('Eval Origin must be an Object or StackFrame')); + }); + + it('handles given StackFrame', function() { + unit.setEvalOrigin(new StackFrame({lineNumber: 2})); + expect(unit.getEvalOrigin().getLineNumber()).toEqual(2); + }); + + it('handles given Object', function() { + unit.setEvalOrigin({functionName: 'evalFn'}); + expect(unit.getEvalOrigin().getFunctionName()).toEqual('evalFn'); + }); + }); + describe('#setFileName', function() { var unit = new StackFrame(); it('coerces input to String', function() { @@ -57,7 +77,7 @@ describe('StackFrame', function () { }); it('throws an error given input that cannot be coerced', function() { - expect(function() { unit.setLineNumber('BOGUS'); }).toThrow(new TypeError('Line Number must be a Number')); + expect(function() { unit.setLineNumber('BOGUS'); }).toThrow(new TypeError('lineNumber must be a Number')); }); }); @@ -69,7 +89,42 @@ describe('StackFrame', function () { }); it('throws an error given input that cannot be coerced', function() { - expect(function() { unit.setColumnNumber('BOGUS'); }).toThrow(new TypeError('Column Number must be a Number')); + expect(function() { unit.setColumnNumber('BOGUS'); }).toThrow(new TypeError('columnNumber must be a Number')); + }); + }); + + describe('#setIsEval', function() { + var unit = new StackFrame(); + it('coerces input to Boolean', function() { + unit.setIsEval('true'); + expect(unit.getIsEval()).toBe(true); + }); + }); + + describe('#setIsConstructor', function() { + var unit = new StackFrame(); + it('coerces input to Boolean', function() { + unit.setIsConstructor(0); + expect(unit.getIsConstructor()).toBe(false); + expect(unit.isConstructor).toBe(false); + }); + }); + + describe('#setIsNative', function() { + var unit = new StackFrame(); + it('coerces input to Boolean', function() { + unit.setIsNative(undefined); + expect(unit.getIsNative()).toBe(false); + expect(unit.isNative).toBe(false); + }); + }); + + describe('#setIsToplevel', function() { + var unit = new StackFrame(); + it('coerces input to Boolean', function() { + unit.setIsToplevel(null); + expect(unit.getIsToplevel()).toBe(false); + expect(unit.isToplevel).toBe(false); }); }); @@ -86,7 +141,16 @@ describe('StackFrame', function () { expect(new StackFrame().toString()).toEqual('{anonymous}()'); }); it('represents complete StackFrame same as old stacktrace.js', function() { - var unit = new StackFrame('fun', [1, 2], 'http://site.com/path.js', 1, 4567, 'SOURCE'); + var unit = new StackFrame({ + functionName: 'fun', + args: [1, 2], + fileName: 'http://site.com/path.js', + lineNumber: 1, + columnNumber: 4567, + isEval: false, + isNative: false, + source: 'SOURCE' + }); expect(unit.toString()).toEqual('fun(1,2)@http://site.com/path.js:1:4567'); }); }); diff --git a/stackframe.js b/stackframe.js index 9a240f0..5a8ee63 100644 --- a/stackframe.js +++ b/stackframe.js @@ -16,35 +16,37 @@ return !isNaN(parseFloat(n)) && isFinite(n); } - function StackFrame(functionName, args, fileName, lineNumber, columnNumber, source) { - if (functionName !== undefined) { - this.setFunctionName(functionName); + function _capitalize(str) { + if (str.length > 0) { + return str[0].toUpperCase() + str.substring(1); + } else { + return str; } - if (args !== undefined) { - this.setArgs(args); - } - if (fileName !== undefined) { - this.setFileName(fileName); - } - if (lineNumber !== undefined) { - this.setLineNumber(lineNumber); - } - if (columnNumber !== undefined) { - this.setColumnNumber(columnNumber); - } - if (source !== undefined) { - this.setSource(source); + } + + var booleanProps = ['constructor', 'eval', 'native', 'toplevel']; + var numericProps = ['columnNumber', 'lineNumber']; + var stringProps = ['fileName', 'functionName', 'source']; + var arrayProps = ['args']; + + function StackFrame(obj) { + if (obj instanceof Object) { + var props = numericProps.concat(stringProps.concat(arrayProps)); + for (var i = 0; i < props.length; i++) { + if (obj.hasOwnProperty(props[i])) { + this['set' + _capitalize(props[i])](obj[props[i]]); + } + } + + for (var j = 0; j < booleanProps.length; j++) { + if (obj.hasOwnProperty(booleanProps[j])) { + this['setIs' + _capitalize(booleanProps[j])](obj[booleanProps[j]]); + } + } } } StackFrame.prototype = { - getFunctionName: function () { - return this.functionName; - }, - setFunctionName: function (v) { - this.functionName = String(v); - }, - getArgs: function () { return this.args; }, @@ -55,45 +57,20 @@ this.args = v; }, - // NOTE: Property name may be misleading as it includes the path, - // but it somewhat mirrors V8's JavaScriptStackTraceApi - // https://code.google.com/p/v8/wiki/JavaScriptStackTraceApi and Gecko's - // http://mxr.mozilla.org/mozilla-central/source/xpcom/base/nsIException.idl#14 - getFileName: function () { - return this.fileName; - }, - setFileName: function (v) { - this.fileName = String(v); + getEvalOrigin: function () { + return this.evalOrigin; }, - - getLineNumber: function () { - return this.lineNumber; - }, - setLineNumber: function (v) { - if (!_isNumber(v)) { - throw new TypeError('Line Number must be a Number'); + setEvalOrigin: function (v) { + if (v instanceof StackFrame) { + this.evalOrigin = v; + } else if (v instanceof Object) { + this.evalOrigin = new StackFrame(v); + } else { + throw new TypeError('Eval Origin must be an Object or StackFrame'); } - this.lineNumber = Number(v); - }, - - getColumnNumber: function () { - return this.columnNumber; - }, - setColumnNumber: function (v) { - if (!_isNumber(v)) { - throw new TypeError('Column Number must be a Number'); - } - this.columnNumber = Number(v); - }, - - getSource: function () { - return this.source; - }, - setSource: function (v) { - this.source = String(v); }, - toString: function() { + toString: function () { var functionName = this.getFunctionName() || '{anonymous}'; var args = '(' + (this.getArgs() || []).join(',') + ')'; var fileName = this.getFileName() ? ('@' + this.getFileName()) : ''; @@ -103,5 +80,47 @@ } }; + for (var i = 0; i < booleanProps.length; i++) { + StackFrame.prototype['getIs' + _capitalize(booleanProps[i])] = (function (p) { + return function () { + return this['is' + p]; + }; + })(_capitalize(booleanProps[i])); + StackFrame.prototype['setIs' + _capitalize(booleanProps[i])] = (function (p) { + return function (v) { + this['is' + p] = !!v; + }; + })(_capitalize(booleanProps[i])); + } + + for (var j = 0; j < numericProps.length; j++) { + StackFrame.prototype['get' + _capitalize(numericProps[j])] = (function (p) { + return function () { + return this[p]; + }; + })(numericProps[j]); + StackFrame.prototype['set' + _capitalize(numericProps[j])] = (function (p) { + return function (v) { + if (!_isNumber(v)) { + throw new TypeError(p + ' must be a Number'); + } + this[p] = Number(v); + }; + })(numericProps[j], j); + } + + for (var k = 0; k < stringProps.length; k++) { + StackFrame.prototype['get' + _capitalize(stringProps[k])] = (function (p) { + return function () { + return this[p]; + }; + })(stringProps[k]); + StackFrame.prototype['set' + _capitalize(stringProps[k])] = (function (p) { + return function (v) { + this[p] = String(v); + }; + })(stringProps[k]); + } + return StackFrame; })); From 834558794be4046f1bc94439033e9e75096bcafc Mon Sep 17 00:00:00 2001 From: Steve Senbud Date: Wed, 30 Dec 2015 10:54:22 -0800 Subject: [PATCH 05/17] Fix and standardize handling of boolean parameters during Construction. --- stackframe.js | 48 ++++++++++++++++-------------------------------- 1 file changed, 16 insertions(+), 32 deletions(-) diff --git a/stackframe.js b/stackframe.js index 5a8ee63..e1983f4 100644 --- a/stackframe.js +++ b/stackframe.js @@ -17,32 +17,28 @@ } function _capitalize(str) { - if (str.length > 0) { - return str[0].toUpperCase() + str.substring(1); - } else { - return str; - } + return str[0].toUpperCase() + str.substring(1); + } + + function _getter(p) { + return function () { + return this[p]; + }; } - var booleanProps = ['constructor', 'eval', 'native', 'toplevel']; + var booleanProps = ['isConstructor', 'isEval', 'isNative', 'isToplevel']; var numericProps = ['columnNumber', 'lineNumber']; var stringProps = ['fileName', 'functionName', 'source']; var arrayProps = ['args']; function StackFrame(obj) { if (obj instanceof Object) { - var props = numericProps.concat(stringProps.concat(arrayProps)); + var props = booleanProps.concat(numericProps.concat(stringProps.concat(arrayProps))); for (var i = 0; i < props.length; i++) { if (obj.hasOwnProperty(props[i])) { this['set' + _capitalize(props[i])](obj[props[i]]); } } - - for (var j = 0; j < booleanProps.length; j++) { - if (obj.hasOwnProperty(booleanProps[j])) { - this['setIs' + _capitalize(booleanProps[j])](obj[booleanProps[j]]); - } - } } } @@ -81,24 +77,16 @@ }; for (var i = 0; i < booleanProps.length; i++) { - StackFrame.prototype['getIs' + _capitalize(booleanProps[i])] = (function (p) { - return function () { - return this['is' + p]; - }; - })(_capitalize(booleanProps[i])); - StackFrame.prototype['setIs' + _capitalize(booleanProps[i])] = (function (p) { + StackFrame.prototype['get' + _capitalize(booleanProps[i])] = _getter(booleanProps[i]); + StackFrame.prototype['set' + _capitalize(booleanProps[i])] = (function (p) { return function (v) { - this['is' + p] = !!v; + this[p] = Boolean(v); }; - })(_capitalize(booleanProps[i])); + })(booleanProps[i]); } for (var j = 0; j < numericProps.length; j++) { - StackFrame.prototype['get' + _capitalize(numericProps[j])] = (function (p) { - return function () { - return this[p]; - }; - })(numericProps[j]); + StackFrame.prototype['get' + _capitalize(numericProps[j])] = _getter(numericProps[j]); StackFrame.prototype['set' + _capitalize(numericProps[j])] = (function (p) { return function (v) { if (!_isNumber(v)) { @@ -106,15 +94,11 @@ } this[p] = Number(v); }; - })(numericProps[j], j); + })(numericProps[j]); } for (var k = 0; k < stringProps.length; k++) { - StackFrame.prototype['get' + _capitalize(stringProps[k])] = (function (p) { - return function () { - return this[p]; - }; - })(stringProps[k]); + StackFrame.prototype['get' + _capitalize(stringProps[k])] = _getter(stringProps[k]); StackFrame.prototype['set' + _capitalize(stringProps[k])] = (function (p) { return function (v) { this[p] = String(v); From 04f0bdbe84933d423ae68c795477c6035aa26e6e Mon Sep 17 00:00:00 2001 From: Steve Senbud Date: Wed, 30 Dec 2015 10:55:08 -0800 Subject: [PATCH 06/17] Release v1.0.1. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ec88952..c028c8e 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "Victor Homyakov (https://github.com/victor-homyakov)", "Oliver Salzburg (https://github.com/oliversalzburg)" ], - "version": "1.0.0", + "version": "1.0.1", "license": "SEE LICENSE IN LICENSE", "keywords": [ "stacktrace", From ecfb51120eb4496cb1580d5d03028f5ecde51735 Mon Sep 17 00:00:00 2001 From: Steve Senbud Date: Wed, 30 Dec 2015 11:00:12 -0800 Subject: [PATCH 07/17] Update dist for v1.0. --- dist/stackframe.min.js | 4 ++-- dist/stackframe.min.js.map | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dist/stackframe.min.js b/dist/stackframe.min.js index 2deae4d..ca070a1 100644 --- a/dist/stackframe.min.js +++ b/dist/stackframe.min.js @@ -1,2 +1,2 @@ -!function(e,t){"use strict";"function"==typeof define&&define.amd?define("stackframe",[],t):"object"==typeof exports?module.exports=t():e.StackFrame=t()}(this,function(){"use strict";function e(e){return!isNaN(parseFloat(e))&&isFinite(e)}function t(e,t,i,n,r,u){void 0!==e&&this.setFunctionName(e),void 0!==t&&this.setArgs(t),void 0!==i&&this.setFileName(i),void 0!==n&&this.setLineNumber(n),void 0!==r&&this.setColumnNumber(r),void 0!==u&&this.setSource(u)}return t.prototype={getFunctionName:function(){return this.functionName},setFunctionName:function(e){this.functionName=String(e)},getArgs:function(){return this.args},setArgs:function(e){if("[object Array]"!==Object.prototype.toString.call(e))throw new TypeError("Args must be an Array");this.args=e},getFileName:function(){return this.fileName},setFileName:function(e){this.fileName=String(e)},getLineNumber:function(){return this.lineNumber},setLineNumber:function(t){if(!e(t))throw new TypeError("Line Number must be a Number");this.lineNumber=Number(t)},getColumnNumber:function(){return this.columnNumber},setColumnNumber:function(t){if(!e(t))throw new TypeError("Column Number must be a Number");this.columnNumber=Number(t)},getSource:function(){return this.source},setSource:function(e){this.source=String(e)},toString:function(){var t=this.getFunctionName()||"{anonymous}",i="("+(this.getArgs()||[]).join(",")+")",n=this.getFileName()?"@"+this.getFileName():"",r=e(this.getLineNumber())?":"+this.getLineNumber():"",u=e(this.getColumnNumber())?":"+this.getColumnNumber():"";return t+i+n+r+u}},t}); -//# sourceMappingURL=stackframe.min.js.map \ No newline at end of file +!function(t,e){"use strict";"function"==typeof define&&define.amd?define("stackframe",[],e):"object"==typeof exports?module.exports=e():t.StackFrame=e()}(this,function(){"use strict";function t(t){return!isNaN(parseFloat(t))&&isFinite(t)}function e(t){return t[0].toUpperCase()+t.substring(1)}function n(t){return function(){return this[t]}}function r(t){if(t instanceof Object)for(var n=i.concat(o.concat(s.concat(u))),r=0;r Date: Wed, 30 Dec 2015 11:05:01 -0800 Subject: [PATCH 08/17] Yay, SPDX finally added Unlicense - https://spdx.org/licenses/Unlicense.html --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c028c8e..26f6121 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "Oliver Salzburg (https://github.com/oliversalzburg)" ], "version": "1.0.1", - "license": "SEE LICENSE IN LICENSE", + "license": "Unlicense", "keywords": [ "stacktrace", "error", From d30b3c8784a5e0bf6c1e4360fc22e2db1fb9e15d Mon Sep 17 00:00:00 2001 From: Steve Senbud Date: Wed, 30 Dec 2015 11:54:25 -0800 Subject: [PATCH 09/17] Update dist for v1.0.1. --- dist/stackframe.js | 123 +++++++++++++++++++++++---------------------- gulpfile.js | 2 +- 2 files changed, 64 insertions(+), 61 deletions(-) diff --git a/dist/stackframe.js b/dist/stackframe.js index 9a240f0..e1983f4 100644 --- a/dist/stackframe.js +++ b/dist/stackframe.js @@ -16,35 +16,33 @@ return !isNaN(parseFloat(n)) && isFinite(n); } - function StackFrame(functionName, args, fileName, lineNumber, columnNumber, source) { - if (functionName !== undefined) { - this.setFunctionName(functionName); - } - if (args !== undefined) { - this.setArgs(args); - } - if (fileName !== undefined) { - this.setFileName(fileName); - } - if (lineNumber !== undefined) { - this.setLineNumber(lineNumber); - } - if (columnNumber !== undefined) { - this.setColumnNumber(columnNumber); - } - if (source !== undefined) { - this.setSource(source); + function _capitalize(str) { + return str[0].toUpperCase() + str.substring(1); + } + + function _getter(p) { + return function () { + return this[p]; + }; + } + + var booleanProps = ['isConstructor', 'isEval', 'isNative', 'isToplevel']; + var numericProps = ['columnNumber', 'lineNumber']; + var stringProps = ['fileName', 'functionName', 'source']; + var arrayProps = ['args']; + + function StackFrame(obj) { + if (obj instanceof Object) { + var props = booleanProps.concat(numericProps.concat(stringProps.concat(arrayProps))); + for (var i = 0; i < props.length; i++) { + if (obj.hasOwnProperty(props[i])) { + this['set' + _capitalize(props[i])](obj[props[i]]); + } + } } } StackFrame.prototype = { - getFunctionName: function () { - return this.functionName; - }, - setFunctionName: function (v) { - this.functionName = String(v); - }, - getArgs: function () { return this.args; }, @@ -55,45 +53,20 @@ this.args = v; }, - // NOTE: Property name may be misleading as it includes the path, - // but it somewhat mirrors V8's JavaScriptStackTraceApi - // https://code.google.com/p/v8/wiki/JavaScriptStackTraceApi and Gecko's - // http://mxr.mozilla.org/mozilla-central/source/xpcom/base/nsIException.idl#14 - getFileName: function () { - return this.fileName; - }, - setFileName: function (v) { - this.fileName = String(v); - }, - - getLineNumber: function () { - return this.lineNumber; - }, - setLineNumber: function (v) { - if (!_isNumber(v)) { - throw new TypeError('Line Number must be a Number'); - } - this.lineNumber = Number(v); - }, - - getColumnNumber: function () { - return this.columnNumber; + getEvalOrigin: function () { + return this.evalOrigin; }, - setColumnNumber: function (v) { - if (!_isNumber(v)) { - throw new TypeError('Column Number must be a Number'); + setEvalOrigin: function (v) { + if (v instanceof StackFrame) { + this.evalOrigin = v; + } else if (v instanceof Object) { + this.evalOrigin = new StackFrame(v); + } else { + throw new TypeError('Eval Origin must be an Object or StackFrame'); } - this.columnNumber = Number(v); }, - getSource: function () { - return this.source; - }, - setSource: function (v) { - this.source = String(v); - }, - - toString: function() { + toString: function () { var functionName = this.getFunctionName() || '{anonymous}'; var args = '(' + (this.getArgs() || []).join(',') + ')'; var fileName = this.getFileName() ? ('@' + this.getFileName()) : ''; @@ -103,5 +76,35 @@ } }; + for (var i = 0; i < booleanProps.length; i++) { + StackFrame.prototype['get' + _capitalize(booleanProps[i])] = _getter(booleanProps[i]); + StackFrame.prototype['set' + _capitalize(booleanProps[i])] = (function (p) { + return function (v) { + this[p] = Boolean(v); + }; + })(booleanProps[i]); + } + + for (var j = 0; j < numericProps.length; j++) { + StackFrame.prototype['get' + _capitalize(numericProps[j])] = _getter(numericProps[j]); + StackFrame.prototype['set' + _capitalize(numericProps[j])] = (function (p) { + return function (v) { + if (!_isNumber(v)) { + throw new TypeError(p + ' must be a Number'); + } + this[p] = Number(v); + }; + })(numericProps[j]); + } + + for (var k = 0; k < stringProps.length; k++) { + StackFrame.prototype['get' + _capitalize(stringProps[k])] = _getter(stringProps[k]); + StackFrame.prototype['set' + _capitalize(stringProps[k])] = (function (p) { + return function (v) { + this[p] = String(v); + }; + })(stringProps[k]); + } + return StackFrame; })); diff --git a/gulpfile.js b/gulpfile.js index a51c5f0..61a15af 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -37,7 +37,7 @@ gulp.task('copy', function () { .pipe(gulp.dest('dist')); }); -gulp.task('dist', function() { +gulp.task('dist', ['copy'], function() { return gulp.src(sources) .pipe(sourcemaps.init()) .pipe(uglify()) From 07b8c756f76323a2cf001d72985026a840f0538e Mon Sep 17 00:00:00 2001 From: Steve Senbud Date: Wed, 30 Dec 2015 11:55:51 -0800 Subject: [PATCH 10/17] Release v1.0.2. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 26f6121..6793f56 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "Victor Homyakov (https://github.com/victor-homyakov)", "Oliver Salzburg (https://github.com/oliversalzburg)" ], - "version": "1.0.1", + "version": "1.0.2", "license": "Unlicense", "keywords": [ "stacktrace", From 73f58c28eafd8ba0db92f40d99d461059626fef4 Mon Sep 17 00:00:00 2001 From: Steve Senbud Date: Wed, 30 Dec 2015 12:04:32 -0800 Subject: [PATCH 11/17] Make new constructor a little less annoying. --- dist/stackframe.js | 2 +- dist/stackframe.min.js | 2 +- dist/stackframe.min.js.map | 2 +- stackframe.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dist/stackframe.js b/dist/stackframe.js index e1983f4..35e2c0e 100644 --- a/dist/stackframe.js +++ b/dist/stackframe.js @@ -35,7 +35,7 @@ if (obj instanceof Object) { var props = booleanProps.concat(numericProps.concat(stringProps.concat(arrayProps))); for (var i = 0; i < props.length; i++) { - if (obj.hasOwnProperty(props[i])) { + if (obj.hasOwnProperty(props[i]) && obj[props[i]] !== undefined) { this['set' + _capitalize(props[i])](obj[props[i]]); } } diff --git a/dist/stackframe.min.js b/dist/stackframe.min.js index ca070a1..41429d0 100644 --- a/dist/stackframe.min.js +++ b/dist/stackframe.min.js @@ -1,2 +1,2 @@ -!function(t,e){"use strict";"function"==typeof define&&define.amd?define("stackframe",[],e):"object"==typeof exports?module.exports=e():t.StackFrame=e()}(this,function(){"use strict";function t(t){return!isNaN(parseFloat(t))&&isFinite(t)}function e(t){return t[0].toUpperCase()+t.substring(1)}function n(t){return function(){return this[t]}}function r(t){if(t instanceof Object)for(var n=i.concat(o.concat(s.concat(u))),r=0;r Date: Fri, 1 Jan 2016 16:38:57 -0800 Subject: [PATCH 12/17] Add Browser Support section --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 954b2a8..3223de2 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,9 @@ stackFrame.getIsNative() // => true stackFrame.toString() // => 'funName(args)@http://localhost:3000/file.js:325:20' ``` +## Browser Support +[![Sauce Test Status](https://saucelabs.com/browser-matrix/stacktracejs.svg)](https://saucelabs.com/u/stacktracejs) + ## Installation ``` npm install stackframe From 8e0502edb6a016539a3497a3450477858634d2fe Mon Sep 17 00:00:00 2001 From: Steve Senbud Date: Fri, 1 Jan 2016 16:39:33 -0800 Subject: [PATCH 13/17] Add test task for PRs --- gulpfile.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/gulpfile.js b/gulpfile.js index 61a15af..e58b888 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -25,6 +25,14 @@ gulp.task('test', function (done) { }, done).start(); }); +gulp.task('test-pr', ['copy', 'dist'], function (done) { + new karma.Server({ + configFile: __dirname + '/karma.conf.js', + browsers: ['Firefox', 'Chrome'], + singleRun: true + }, done).start(); +}); + gulp.task('test-ci', ['copy', 'dist'], function (done) { new karma.Server({ configFile: __dirname + '/karma.conf.ci.js', @@ -48,6 +56,8 @@ gulp.task('dist', ['copy'], function() { gulp.task('clean', del.bind(null, ['build', 'coverage', 'dist'])); +gulp.task('pr', ['lint', 'test-pr']); + gulp.task('ci', ['lint', 'test-ci'], function () { gulp.src('./coverage/**/lcov.info') .pipe(coveralls()); From d131cbd5f015edbba0056cfbc99f0b5b5d7547ac Mon Sep 17 00:00:00 2001 From: Steve Senbud Date: Fri, 1 Jan 2016 16:40:31 -0800 Subject: [PATCH 14/17] Don't use Sauce for PRs, use local browsers. --- .travis.yml | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3d5a3dd..a8aa39b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,12 +1,18 @@ language: node_js -node_js: -- '0.12' -script: gulp ci -install: -- npm install sudo: false +node_js: stable addons: sauce_connect: true + firefox: latest + apt: + sources: + - google-chrome + packages: + - google-chrome-stable +before_script: +- npm install +script: +- if ["${TRAVIS_PULL_REQUEST}" = "false"]; then gulp ci; else gulp pr; fi env: global: - secure: VGFNdtgz47pAI9fgXyej0Z10qdcHMjYBgCrHQQLdxDnsEtPqQL77H/TTGgw9xq1wF9BmVM2AS3bCrmHmgZboHaG0QSx813eiNs5ewQvSutrDMpBVqyKcnHvYf3L5WSeOvW8nCcKlh8TTaNSGc27+x0x6UGppI8NfVbZQvjcef5g= From 16c65538e490ae2a29447609c8e2fe2a6c519f78 Mon Sep 17 00:00:00 2001 From: Steve Senbud Date: Fri, 1 Jan 2016 16:41:48 -0800 Subject: [PATCH 15/17] Use spec reporter for PRs and local testing. --- karma.conf.ci.js | 8 ++++---- karma.conf.js | 10 +--------- package.json | 2 +- 3 files changed, 6 insertions(+), 14 deletions(-) diff --git a/karma.conf.ci.js b/karma.conf.ci.js index 0976985..901cdc5 100644 --- a/karma.conf.ci.js +++ b/karma.conf.ci.js @@ -16,7 +16,7 @@ module.exports = function (config) { base: 'SauceLabs', browserName: 'iPhone', platform: 'OS X 10.11', - version: '9.1' + version: '9.2' }, slAndroid4: { base: 'SauceLabs', @@ -119,9 +119,9 @@ module.exports = function (config) { ], exclude: [], port: 9876, - colors: true, + colors: false, logLevel: config.LOG_INFO, - autoWatch: true, + autoWatch: false, browserDisconnectTimeout : 10000, browserDisconnectTolerance : 1, browserNoActivityTimeout : 240000, @@ -136,7 +136,7 @@ module.exports = function (config) { }, customLaunchers: customLaunchers, browsers: Object.keys(customLaunchers), - reporters: ['progress', 'saucelabs', 'coverage'], + reporters: ['dots', 'saucelabs', 'coverage'], preprocessors: { 'stackframe.js': 'coverage' }, diff --git a/karma.conf.js b/karma.conf.js index 75d0e34..9c28eac 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -6,19 +6,11 @@ module.exports = function (config) { 'stackframe.js', 'spec/*-spec.js' ], - reporters: ['progress', 'coverage'], - preprocessors: { - '*.js': 'coverage' - }, - coverageReporter: { - type: 'lcov', - dir: 'coverage' - }, + reporters: ['spec'], port: 9876, colors: true, logLevel: config.LOG_INFO, autoWatch: true, - // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher //browsers: ['Firefox', 'ChromeCanary', 'Opera', 'Safari'], browsers: ['PhantomJS2'], singleRun: false diff --git a/package.json b/package.json index 6793f56..e473410 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "karma-phantomjs2-launcher": "^0.3.2", "karma-safari-launcher": "^0.1.1", "karma-sauce-launcher": "^0.3.0", + "karma-spec-reporter": "0.0.23", "run-sequence": "^1.1.5" }, "bugs": { @@ -51,4 +52,3 @@ "test": "gulp test" } } - From 08ccb30d44e048a499db3f4ab4d796d148c23f22 Mon Sep 17 00:00:00 2001 From: Steve Senbud Date: Fri, 1 Jan 2016 16:50:54 -0800 Subject: [PATCH 16/17] Update version for component(1). Fix Travis CI config. Remove .nvmrc --- .nvmrc | 1 - .travis.yml | 2 +- component.json | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) delete mode 100644 .nvmrc diff --git a/.nvmrc b/.nvmrc deleted file mode 100644 index d0e8c69..0000000 --- a/.nvmrc +++ /dev/null @@ -1 +0,0 @@ -0.10.32 diff --git a/.travis.yml b/.travis.yml index a8aa39b..857558c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,7 +12,7 @@ addons: before_script: - npm install script: -- if ["${TRAVIS_PULL_REQUEST}" = "false"]; then gulp ci; else gulp pr; fi +- if [ "${TRAVIS_PULL_REQUEST}" = "false" ]; then gulp ci; else gulp pr; fi env: global: - secure: VGFNdtgz47pAI9fgXyej0Z10qdcHMjYBgCrHQQLdxDnsEtPqQL77H/TTGgw9xq1wF9BmVM2AS3bCrmHmgZboHaG0QSx813eiNs5ewQvSutrDMpBVqyKcnHvYf3L5WSeOvW8nCcKlh8TTaNSGc27+x0x6UGppI8NfVbZQvjcef5g= diff --git a/component.json b/component.json index 6363c7e..1b63f8a 100644 --- a/component.json +++ b/component.json @@ -2,7 +2,7 @@ "name": "stackframe", "repository": "stacktracejs/stackframe", "description": "JS Object representation of a stack frame", - "version": "0.3.1", + "version": "1.0.2", "keywords": [ "stacktrace", "error", From bfee796138b9f13be662471ac331b58dda5f5ea1 Mon Sep 17 00:00:00 2001 From: Denis Bardadym Date: Tue, 5 Jan 2016 15:00:31 +0300 Subject: [PATCH 17/17] Do not need to concat all properties names each time --- stackframe.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/stackframe.js b/stackframe.js index 35e2c0e..b54524d 100644 --- a/stackframe.js +++ b/stackframe.js @@ -30,10 +30,11 @@ var numericProps = ['columnNumber', 'lineNumber']; var stringProps = ['fileName', 'functionName', 'source']; var arrayProps = ['args']; + + var props = booleanProps.concat(numericProps.concat(stringProps.concat(arrayProps))); function StackFrame(obj) { if (obj instanceof Object) { - var props = booleanProps.concat(numericProps.concat(stringProps.concat(arrayProps))); for (var i = 0; i < props.length; i++) { if (obj.hasOwnProperty(props[i]) && obj[props[i]] !== undefined) { this['set' + _capitalize(props[i])](obj[props[i]]);