diff --git a/History.md b/History.md index c0fb137..ae22840 100644 --- a/History.md +++ b/History.md @@ -1,6 +1,7 @@ unreleased ========== + * Fix `TypeError`s when under `'use strict'` code * Fix useless type name on auto-generated messages * Support io.js 1.x * Support Node.js 0.12 diff --git a/index.js b/index.js index f44905a..d183b0a 100644 --- a/index.js +++ b/index.js @@ -280,13 +280,15 @@ function callSiteLocation(callSite) { function defaultMessage(site) { var callSite = site.callSite var funcName = site.name - var typeName = callSite.getTypeName() // make useful anonymous name if (!funcName) { funcName = '' } + var context = callSite.getThis() + var typeName = context && callSite.getTypeName() + // ignore useless type name if (typeName === 'Object') { typeName = undefined @@ -294,7 +296,7 @@ function defaultMessage(site) { // make useful type name if (typeName === 'Function') { - typeName = callSite.getThis().name || typeName + typeName = context.name || typeName } return typeName && callSite.getMethodName() diff --git a/test/fixtures/strict-lib.js b/test/fixtures/strict-lib.js new file mode 100644 index 0000000..f4f0201 --- /dev/null +++ b/test/fixtures/strict-lib.js @@ -0,0 +1,51 @@ + +'use strict' + +var deprecate = require('../..')('strict-lib') + +exports.old = function () { + deprecate('old') +} + +exports.oldfn = deprecate.function(fn, 'oldfn') + +exports.oldfnauto = deprecate.function(fn) + +exports.oldfnautoanon = deprecate.function(function () {}) + +exports.propa = 'thingie' +exports.propauto = 'thingie' + +deprecate.property(exports, 'propa', 'propa gone') +deprecate.property(exports, 'propauto') + +exports.automsg = function () { + deprecate() +} + +exports.automsgnamed = function automsgnamed() { + deprecate() +} + +exports.automsganon = function () { + (function () { deprecate() }()) +} + +exports.fnprop = function thefn() {} +exports.fnprop.propa = 'thingie' +exports.fnprop.propautomsg = 'thingie' + +deprecate.property(exports.fnprop, 'propa', 'fn propa gone') +deprecate.property(exports.fnprop, 'propautomsg') + +exports.layerfn = function () { + exports.oldfn() +} + +exports.layerprop = function () { + exports.propa +} + +function fn(a1, a2) { + return a2 +} diff --git a/test/test.js b/test/test.js index 3be4762..388ae94 100644 --- a/test/test.js +++ b/test/test.js @@ -7,6 +7,7 @@ var mylib = require('./fixtures/my-lib') var path = require('path') var script = path.join(__dirname, 'fixtures', 'script.js') var spawn = require('child_process').spawn +var strictlib = require('./fixtures/strict-lib') describe('depd(namespace)', function () { it('creates deprecated function', function () { @@ -41,6 +42,13 @@ describe('deprecate(message)', function () { assert.ok(/\.js:[0-9]+:[0-9]+/.test(stderr)) }) + it('should log call site from strict lib', function () { + function callold() { strictlib.old() } + var stderr = captureStderr(callold) + assert.ok(stderr.indexOf(basename(__filename)) !== -1) + assert.ok(/\.js:[0-9]+:[0-9]+/.test(stderr)) + }) + it('should log call site regardless of Error.stackTraceLimit', function () { function callold() { mylib.old() } var limit = Error.stackTraceLimit @@ -62,6 +70,13 @@ describe('deprecate(message)', function () { assert.ok(/\.js:[0-9]+:[0-9]+/.test(stderr)) }) + it('should log call site within strict', function () { + function callold() { 'use strict'; mylib.old() } + var stderr = captureStderr(callold) + assert.ok(stderr.indexOf(basename(__filename)) !== -1) + assert.ok(/\.js:[0-9]+:[0-9]+/.test(stderr)) + }) + it('should only warn once per call site', function () { function callold() { for (var i = 0; i < 5; i++) { @@ -147,6 +162,54 @@ describe('deprecate(message)', function () { assert.ok(stderr.indexOf('deprecated') !== -1) assert.ok(/ exports\.automsganon | /.test(stderr)) }) + + describe('in strict mode library', function () { + it('should generate message for method call on named function', function () { + function callold() { strictlib.automsgnamed() } + var stderr = captureStderr(callold) + assert.ok(stderr.indexOf(basename(__filename)) !== -1) + assert.ok(stderr.indexOf('deprecated') !== -1) + assert.ok(stderr.indexOf(' automsgnamed ') !== -1) + }) + + it('should generate message for function call on named function', function () { + function callold() { + var fn = strictlib.automsgnamed + fn() + } + var stderr = captureStderr(callold) + assert.ok(stderr.indexOf(basename(__filename)) !== -1) + assert.ok(stderr.indexOf('deprecated') !== -1) + assert.ok(stderr.indexOf(' automsgnamed ') !== -1) + }) + + it('should generate message for method call on unnamed function', function () { + function callold() { strictlib.automsg() } + var stderr = captureStderr(callold) + assert.ok(stderr.indexOf(basename(__filename)) !== -1) + assert.ok(stderr.indexOf('deprecated') !== -1) + assert.ok(stderr.indexOf(' exports.automsg ') !== -1) + }) + + it('should generate message for function call on unnamed function', function () { + function callold() { + var fn = strictlib.automsg + fn() + } + var stderr = captureStderr(callold) + assert.ok(stderr.indexOf(basename(__filename)) !== -1) + assert.ok(stderr.indexOf('deprecated') !== -1) + assert.ok(stderr.indexOf(' exports.automsg ') !== -1) + }) + + it('should generate message for function call on anonymous function', function () { + function callold() { strictlib.automsganon() } + var stderr = captureStderr(callold) + assert.ok(stderr.indexOf(basename(__filename)) !== -1) + assert.ok(stderr.indexOf('deprecated') !== -1) + assert.ok(/ exports\.automsganon | /.test(stderr)) + }) + }) }) describe('when output supports colors', function () { @@ -215,7 +278,7 @@ describe('deprecate(message)', function () { }) describe('deprecate.function(fn, message)', function () { - it('should thrown when not given function', function () { + it('should throw when not given function', function () { var deprecate = depd('test') assert.throws(deprecate.function.bind(deprecate, 2), /fn.*function/) }) @@ -243,6 +306,13 @@ describe('deprecate.function(fn, message)', function () { assert.ok(/test.js:[0-9]+:[0-9]+/.test(stderr)) }) + it('should show call site outside scope from strict lib', function () { + function callold() { strictlib.layerfn() } + var stderr = captureStderr(callold) + assert.ok(stderr.indexOf(' oldfn ') !== -1) + assert.ok(/test.js:[0-9]+:[0-9]+/.test(stderr)) + }) + it('should only warn once per call site', function () { function callold() { for (var i = 0; i < 5; i++) { @@ -297,6 +367,26 @@ describe('deprecate.function(fn, message)', function () { assert.ok(/ /.test(stderr)) assert.ok(/ at [^:]+test\.js:/.test(stderr)) }) + + describe('in strict mode library', function () { + it('should generate message for method call on named function', function () { + function callold() { strictlib.oldfnauto() } + var stderr = captureStderr(callold) + assert.ok(stderr.indexOf(basename(__filename)) !== -1) + assert.ok(stderr.indexOf('deprecated') !== -1) + assert.ok(stderr.indexOf(' fn ') !== -1) + assert.ok(/ at [^:]+test\.js:/.test(stderr)) + }) + + it('should generate message for method call on anonymous function', function () { + function callold() { strictlib.oldfnautoanon() } + var stderr = captureStderr(callold) + assert.ok(stderr.indexOf(basename(__filename)) !== -1) + assert.ok(stderr.indexOf('deprecated') !== -1) + assert.ok(/ /.test(stderr)) + assert.ok(/ at [^:]+test\.js:/.test(stderr)) + }) + }) }) }) @@ -369,6 +459,13 @@ describe('deprecate.property(obj, prop, message)', function () { assert.ok(/test.js:[0-9]+:[0-9]+/.test(stderr)) }) + it('should show call site outside scope from strict lib', function () { + function callold() { strictlib.layerprop() } + var stderr = captureStderr(callold) + assert.ok(stderr.indexOf(' propa ') !== -1) + assert.ok(/test.js:[0-9]+:[0-9]+/.test(stderr)) + }) + describe('when obj is a function', function () { it('should log on access to property on function', function () { function callprop() { mylib.fnprop.propa } @@ -383,6 +480,22 @@ describe('deprecate.property(obj, prop, message)', function () { assert.ok(stderr.indexOf(' deprecated ') !== -1) assert.ok(stderr.indexOf(' thefn.propautomsg ') !== -1) }) + + describe('in strict mode library', function () { + it('should log on access to property on function', function () { + function callprop() { strictlib.fnprop.propa } + var stderr = captureStderr(callprop) + assert.ok(stderr.indexOf(' deprecated ') !== -1) + assert.ok(stderr.indexOf(' fn propa gone ') !== -1) + }) + + it('should generate message on named function', function () { + function callprop() { strictlib.fnprop.propautomsg } + var stderr = captureStderr(callprop) + assert.ok(stderr.indexOf(' deprecated ') !== -1) + assert.ok(stderr.indexOf(' thefn.propautomsg ') !== -1) + }) + }) }) describe('when value descriptor', function () { @@ -429,6 +542,17 @@ describe('deprecate.property(obj, prop, message)', function () { assert.ok(stderr.indexOf(' propauto ') !== -1) assert.ok(/ at [^:]+test\.js:/.test(stderr)) }) + + describe('in strict mode library', function () { + it('should generate message for method call on named function', function () { + function callold() { strictlib.propauto } + var stderr = captureStderr(callold) + assert.ok(stderr.indexOf(basename(__filename)) !== -1) + assert.ok(stderr.indexOf('deprecated') !== -1) + assert.ok(stderr.indexOf(' propauto ') !== -1) + assert.ok(/ at [^:]+test\.js:/.test(stderr)) + }) + }) }) })