[Pkg-javascript-commits] [node-depd] 01/02: Imported Upstream version 0.3.0

Andrew Kelley andrewrk-guest at moszumanska.debian.org
Sat Jun 28 15:49:14 UTC 2014


This is an automated email from the git hooks/post-receive script.

andrewrk-guest pushed a commit to branch master
in repository node-depd.

commit 95723d9e5133278301776be2bab237b64d2e35c5
Author: Andrew Kelley <superjoe30 at gmail.com>
Date:   Sat Jun 28 15:43:37 2014 +0000

    Imported Upstream version 0.3.0
---
 .gitignore                 |   3 +
 .npmignore                 |   4 +
 .travis.yml                |  11 +
 History.md                 |  27 +++
 LICENSE                    |  22 ++
 Readme.md                  | 249 +++++++++++++++++++++++
 files/message.png          | Bin 0 -> 2733 bytes
 index.js                   | 452 +++++++++++++++++++++++++++++++++++++++++
 package.json               |  25 +++
 test/fixtures/cool-lib.js  |  11 +
 test/fixtures/multi-lib.js |  11 +
 test/fixtures/my-lib.js    |  64 ++++++
 test/fixtures/new-lib.js   |   6 +
 test/fixtures/old-lib.js   |  11 +
 test/test.js               | 495 +++++++++++++++++++++++++++++++++++++++++++++
 15 files changed, 1391 insertions(+)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..3cd27af
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+coverage/
+node_modules/
+npm-debug.log
diff --git a/.npmignore b/.npmignore
new file mode 100644
index 0000000..0c7e391
--- /dev/null
+++ b/.npmignore
@@ -0,0 +1,4 @@
+coverage/
+files/
+test/
+.travis.yml
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..1ff243c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,11 @@
+language: node_js
+node_js:
+  - "0.8"
+  - "0.10"
+  - "0.11"
+matrix:
+  allow_failures:
+    - node_js: "0.11"
+  fast_finish: true
+script: "npm run-script test-travis"
+after_script: "npm install coveralls at 2.10.0 && cat ./coverage/lcov.info | coveralls"
diff --git a/History.md b/History.md
new file mode 100644
index 0000000..b9d1c6d
--- /dev/null
+++ b/History.md
@@ -0,0 +1,27 @@
+0.3.0 / 2014-06-16
+==================
+
+  * Add `NO_DEPRECATION` environment variable
+
+0.2.0 / 2014-06-15
+==================
+
+  * Add `deprecate.property(obj, prop, message)`
+  * Remove `supports-color` dependency for node.js 0.8
+
+0.1.0 / 2014-06-15
+==================
+
+  * Add `deprecate.function(fn, message)`
+  * Add `process.on('deprecation', fn)` emitter
+  * Automatically generate message when omitted from `deprecate()`
+
+0.0.1 / 2014-06-15
+==================
+
+  * Fix warning for dynamic calls at singe call site
+
+0.0.0 / 2014-06-15
+==================
+
+  * Initial implementation
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..b7dce6c
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,22 @@
+(The MIT License)
+
+Copyright (c) 2014 Douglas Christopher Wilson
+
+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.
diff --git a/Readme.md b/Readme.md
new file mode 100644
index 0000000..872a8b4
--- /dev/null
+++ b/Readme.md
@@ -0,0 +1,249 @@
+# depd
+
+[![NPM version](https://badge.fury.io/js/depd.svg)](http://badge.fury.io/js/depd)
+[![Build Status](https://travis-ci.org/dougwilson/nodejs-depd.svg?branch=master)](https://travis-ci.org/dougwilson/nodejs-depd)
+[![Coverage Status](https://img.shields.io/coveralls/dougwilson/nodejs-depd.svg?branch=master)](https://coveralls.io/r/dougwilson/nodejs-depd)
+
+Deprecate all the things
+
+> With great modules comes great responsibility; mark things deprecated!
+
+## Install
+
+```sh
+$ npm install depd
+```
+
+## API
+
+```js
+var depd      = require('depd')
+var deprecate = depd('my-module')
+```
+
+This library allows you to display deprecation messages to your users.
+This library goes above and beyond with deprecation warnings by
+introspecting the call stack (but only the bits that it is interested
+in).
+
+Instead of just warning on the first invocation of a deprecated
+function and never again, this module will warn on the first invocation
+of a deprecated function per unique call site, making it ideal to alert
+users of all deprecated uses across the code base, rather than just
+whatever happens to execute first.
+
+The deprecation warnings from this module also include the file and line
+information for the call into the module that the deprecated function was
+in.
+
+### depd(namespace)
+
+Create a new deprecate function that uses the given namespace name in the
+messages and will display the call site prior to the stack entering the
+file this function was called from. It is highly suggested you use the
+name of your module as the namespace.
+
+### deprecate(message)
+
+Call this function from deprecated code to display a deprecation message.
+This message will appear once per unique caller site. Caller site is the
+first call site in the stack in a different file from the caller of this
+function.
+
+If the message is omitted, a message is generated for you based on the site
+of the `deprecate()` call and will display the name of the function called,
+similar to the name displayed in a stack trace.
+
+### deprecate.function(fn, message)
+
+Call this function to wrap a given function in a deprecation message on any
+call to the function. An optional message can be supplied to provide a custom
+message.
+
+### deprecate.property(obj, prop, message)
+
+Call this function to wrap a given property on object in a deprecation message
+on any accessing or setting of the property. An optional message can be supplied
+to provide a custom message.
+
+The method must be called on the object where the property belongs (not
+inherited from the prototype).
+
+If the property is a data descriptor, it will be converted to an accessor
+descriptor in order to display the deprecation message.
+
+### process.on('deprecation', fn)
+
+This module will allow easy capturing of deprecation errors by emitting the
+errors as the type "deprecation" on the global `process`. If there are no
+listeners for this type, the errors are written to STDERR as normal, but if
+there are any listeners, nothing will be written to STDERR and instead only
+emitted. From there, you can write the errors in a different format or to a
+logging source.
+
+The error represents the deprecation and is emitted only once with the same
+rules as writing to STDERR. The error has the following properties:
+
+  - `message` - This is the message given by the library
+  - `name` - This is always `'DeprecationError'`
+  - `namespace` - This is the namespace the deprecation came from
+  - `stack` - This is the stack of the call to the deprecated thing
+
+Example `error.stack` output:
+
+```
+DeprecationError: my-cool-module deprecated oldfunction
+    at Object.<anonymous> ([eval]-wrapper:6:22)
+    at Module._compile (module.js:456:26)
+    at evalScript (node.js:532:25)
+    at startup (node.js:80:7)
+    at node.js:902:3
+```
+
+### process.env.NO_DEPRECATION
+
+As a user of modules that are deprecated, the environment variable `NO_DEPRECATION`
+is provided as a quick solution to silencing deprecation warnings from being
+output. The format of this is similar to that of `DEBUG`:
+
+```sh
+$ NO_DEPRECATION=my-module,othermod node app.js
+```
+
+This will suppress deprecations from being output for "my-module" and "othermod".
+The value is a list of comma-separated namespaces. To suppress every warning
+across all namespaces, use the value `*` for a namespace.
+
+**NOTE** This will not suppress the deperecations given to any "deprecation"
+event listeners, just the output to STDERR.
+
+## Display
+
+![message](files/message.png)
+
+When a user calls a function in your library that you mark deprecated, they
+will see the following written to STDERR (in the given colors, similar colors
+and layout to the `debug` module):
+
+```
+bright cyan    bright yellow
+|              |          grey        cyan
+|              |          |           |
+▼              ▼          ▼           ▼
+my-cool-module deprecated oldfunction [eval]-wrapper:6:22
+▲              ▲          ▲           ▲
+|              |          |           |
+namespace      |          |           location of mycoolmod.oldfunction() call
+               |          deprecation message
+               the word "deprecated"
+```
+
+If the user redirects their STDERR to a file or somewhere that does not support
+colors, they see (similar layout to the `debug` module):
+
+```
+Sun, 15 Jun 2014 05:21:37 GMT my-cool-module deprecated oldfunction at [eval]-wrapper:6:22
+▲                             ▲              ▲          ▲              ▲
+|                             |              |          |              |
+timestamp of message          namespace      |          |             location of mycoolmod.oldfunction() call
+                                             |          deprecation message
+                                             the word "deprecated"
+```
+
+## Examples
+
+### Deprecating all calls to a function
+
+This will display a deprecated message about "oldfunction" being deprecated
+from "my-module" on STDERR.
+
+```js
+var deprecate = require('depd')('my-cool-module')
+
+// message automatically derived from function name
+// Object.oldfunction
+exports.oldfunction = deprecate.function(function oldfunction() {
+  // all calls to function are deprecated
+})
+
+// specific message
+exports.oldfunction = deprecate.function(function () {
+  // all calls to function are deprecated
+}, 'oldfunction')
+```
+
+### Conditionally deprecating a function call
+
+This will display a deprecated message about "weirdfunction" being deprecated
+from "my-module" on STDERR when called with less than 2 arguments.
+
+```js
+var deprecate = require('depd')('my-cool-module')
+
+exports.weirdfunction = function () {
+  if (arguments.length < 2) {
+    // calls with 0 or 1 args are deprecated
+    deprecate('weirdfunction args < 2')
+  }
+}
+```
+
+When calling `deprecate` as a function, the warning is counted per call site
+within your own module, so you can display different deprecations depending
+on different situations and the users will still get all the warnings:
+
+```js
+var deprecate = require('depd')('my-cool-module')
+
+exports.weirdfunction = function () {
+  if (arguments.length < 2) {
+    // calls with 0 or 1 args are deprecated
+    deprecate('weirdfunction args < 2')
+  } else if (typeof arguments[0] !== 'string') {
+    // calls with non-string first argument are deprecated
+    deprecate('weirdfunction non-string first arg')
+  }
+}
+```
+
+### Deprecating property access
+
+This will display a deprecated message about "oldprop" being deprecated
+from "my-module" on STDERR when accessed. A deprecation will be displayed
+when setting the value and when getting the value.
+
+```js
+var deprecate = require('depd')('my-cool-module')
+
+exports.oldprop = 'something'
+
+// message automatically derives from property name
+deprecate.property(exports, 'oldprop')
+
+// explicit message
+deprecate.property(exports, 'oldprop', 'oldprop >= 0.10')
+```
+
+## License
+
+The MIT License (MIT)
+
+Copyright (c) 2014 Douglas Christopher Wilson
+
+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.
diff --git a/files/message.png b/files/message.png
new file mode 100644
index 0000000..21dc881
Binary files /dev/null and b/files/message.png differ
diff --git a/index.js b/index.js
new file mode 100644
index 0000000..f42aa07
--- /dev/null
+++ b/index.js
@@ -0,0 +1,452 @@
+/*!
+ * depd
+ * Copyright(c) 2014 Douglas Christopher Wilson
+ * MIT Licensed
+ */
+
+/**
+ * Module dependencies.
+ */
+
+var EventEmitter = require('events').EventEmitter
+var relative = require('path').relative
+
+/**
+ * Module exports.
+ */
+
+module.exports = depd
+
+/**
+ * Get the path to base files on.
+ */
+
+var basePath = process.cwd()
+
+/**
+ * Get listener count on event emitter.
+ */
+
+/*istanbul ignore next*/
+var eventListenerCount = EventEmitter.listenerCount
+  || function (emitter, type) { return emitter.listeners(type).length }
+
+/**
+ * Convert a data descriptor to accessor descriptor.
+ */
+
+function convertDataDescriptorToAccessor(obj, prop, message) {
+  var descriptor = Object.getOwnPropertyDescriptor(obj, prop)
+  var value = descriptor.value
+
+  descriptor.get = function getter() { return value }
+
+  if (descriptor.writable) {
+    descriptor.set = function setter(val) { return value = val }
+  }
+
+  delete descriptor.value
+  delete descriptor.writable
+
+  Object.defineProperty(obj, prop, descriptor)
+
+  return descriptor
+}
+
+/**
+ * Create arguments string to keep arity.
+ */
+
+function createArgumentsString(arity) {
+  var str = ''
+
+  for (var i = 0; i < arity; i++) {
+    str += ', arg' + i
+  }
+
+  return str.substr(2)
+}
+
+/**
+ * Create stack string from stack.
+ */
+
+function createStackString(stack) {
+  var str = this.name + ': ' + this.namespace
+
+  if (this.message) {
+    str += ' deprecated ' + this.message
+  }
+
+  for (var i = 0; i < stack.length; i++) {
+    str += '\n    at ' + stack[i].toString()
+  }
+
+  return str
+}
+
+/**
+ * Create deprecate for namespace in caller.
+ */
+
+function depd(namespace) {
+  if (!namespace) {
+    throw new TypeError('argument namespace is required')
+  }
+
+  var stack = getStack()
+  var site = callSiteLocation(stack[1])
+  var file = site[0]
+
+  function deprecate(message) {
+    // call to self as log
+    log.call(deprecate, message)
+  }
+
+  deprecate._file = file
+  deprecate._ignored = isignored(namespace)
+  deprecate._namespace = namespace
+  deprecate._warned = Object.create(null)
+
+  deprecate.function = wrapfunction
+  deprecate.property = wrapproperty
+
+  return deprecate
+}
+
+/**
+ * Determine if namespace is ignored.
+ */
+
+function isignored(namespace) {
+  var str = process.env.NO_DEPRECATION || ''
+  var val = str.split(/[ ,]+/)
+
+  namespace = String(namespace).toLowerCase()
+
+  for (var i = 0 ; i < val.length; i++) {
+    if (!(str = val[i])) continue;
+
+    // namespace ignored
+    if (str === '*' || str.toLowerCase() === namespace) {
+      return true
+    }
+  }
+
+  return false
+}
+
+/**
+ * Display deprecation message.
+ */
+
+function log(message, site) {
+  var haslisteners = eventListenerCount(process, 'deprecation') !== 0
+
+  // abort early if no destination
+  if (!haslisteners && this._ignored) {
+    return
+  }
+
+  var caller
+  var callSite
+  var i = 0
+  var seen = false
+  var stack = getStack()
+  var file = this._file
+
+  if (site) {
+    // provided site
+    callSite = callSiteLocation(stack[1])
+    callSite.name = site.name
+    file = callSite[0]
+  } else {
+    // get call site
+    i = 2
+    site = callSiteLocation(stack[i])
+    callSite = site
+  }
+
+  // get caller of deprecated thing in relation to file
+  for (; i < stack.length; i++) {
+    caller = callSiteLocation(stack[i])
+
+    if (caller[0] === file) {
+      seen = true
+    } else if (seen) {
+      break
+    }
+  }
+
+  var key = caller
+    ? site.join(':') + '__' + caller.join(':')
+    : undefined
+
+  if (key !== undefined && key in this._warned) {
+    // already warned
+    return
+  }
+
+  this._warned[key] = true
+
+  // generate automatic message from call site
+  if (!message) {
+    message = callSite === site || !callSite.name
+      ? defaultMessage(site)
+      : defaultMessage(callSite)
+  }
+
+  // emit deprecation if listeners exist
+  if (haslisteners) {
+    var err = DeprecationError(this._namespace, message, stack.slice(i))
+    process.emit('deprecation', err)
+    return
+  }
+
+  // format and write message
+  var format = process.stderr.isTTY
+    ? formatColor
+    : formatPlain
+  var msg = format.call(this, message, caller)
+  process.stderr.write(msg + '\n', 'utf8')
+
+  return
+}
+
+/**
+ * Get call site location as array.
+ */
+
+function callSiteLocation(callSite) {
+  var file = callSite.getFileName() || '<anonymous>'
+  var line = callSite.getLineNumber()
+  var colm = callSite.getColumnNumber()
+
+  if (callSite.isEval()) {
+    file = callSite.getEvalOrigin() + ', ' + file
+  }
+
+  var site = [file, line, colm]
+
+  site.callSite = callSite
+  site.name = callSite.getFunctionName()
+
+  return site
+}
+
+/**
+ * Generate a default message from the site.
+ */
+
+function defaultMessage(site) {
+  var callSite = site.callSite
+  var funcName = site.name
+
+  // make useful anonymous name
+  if (!funcName) {
+    funcName = '<anonymous@' + formatLocation(site) + '>'
+  }
+
+  return callSite.getMethodName()
+    ? callSite.getTypeName() + '.' + funcName
+    : funcName
+}
+
+/**
+ * Format deprecation message without color.
+ */
+
+function formatPlain(msg, caller) {
+  var timestamp = new Date().toUTCString()
+
+  var formatted = timestamp
+    + ' ' + this._namespace
+    + ' deprecated ' + msg
+
+  if (caller) {
+    formatted += ' at ' + formatLocation(caller)
+  }
+
+  return formatted
+}
+
+/**
+ * Format deprecation message with color.
+ */
+
+function formatColor(msg, caller) {
+  var formatted = '\x1b[36;1m' + this._namespace + '\x1b[22;39m' // bold cyan
+    + ' \x1b[33;1mdeprecated\x1b[22;39m' // bold yellow
+    + ' \x1b[90m' + msg + '\x1b[39m' // grey
+
+  if (caller) {
+    formatted += ' \x1b[36m' + formatLocation(caller) + '\x1b[39m' // cyan
+  }
+
+  return formatted
+}
+
+/**
+ * Format call site location.
+ */
+
+function formatLocation(callSite) {
+  return relative(basePath, callSite[0])
+    + ':' + callSite[1]
+    + ':' + callSite[2]
+}
+
+/**
+ * Get the stack as array of call sites.
+ */
+
+function getStack() {
+  var obj = {}
+  var prep = Error.prepareStackTrace
+
+  Error.prepareStackTrace = prepareObjectStackTrace
+  Error.captureStackTrace(obj, getStack)
+
+  var stack = obj.stack
+
+  Error.prepareStackTrace = prep
+
+  return stack
+}
+
+/**
+ * Capture call site stack from v8.
+ */
+
+function prepareObjectStackTrace(obj, stack) {
+  return stack
+}
+
+/**
+ * Return a wrapped function in a deprecation message.
+ */
+
+function wrapfunction(fn, message) {
+  if (typeof fn !== 'function') {
+    throw new TypeError('argument fn must be a function')
+  }
+
+  var args = createArgumentsString(fn.length)
+  var deprecate = this
+  var stack = getStack()
+  var site = callSiteLocation(stack[1])
+
+  site.name = fn.name
+
+  var deprecatedfn = eval('(function (' + args + ') {\n'
+    + 'log.call(deprecate, message, site)\n'
+    + 'return fn.apply(this, arguments)\n'
+    + '})')
+
+  return deprecatedfn
+}
+
+/**
+ * Wrap property in a deprecation message.
+ */
+
+function wrapproperty(obj, prop, message) {
+  if (!obj || typeof obj !== 'object') {
+    throw new TypeError('argument obj must be object')
+  }
+
+  var descriptor = Object.getOwnPropertyDescriptor(obj, prop)
+
+  if (!descriptor) {
+    throw new TypeError('must call property on owner object')
+  }
+
+  if (!descriptor.configurable) {
+    throw new TypeError('property must be configurable')
+  }
+
+  var deprecate = this
+  var stack = getStack()
+  var site = callSiteLocation(stack[1])
+
+  // set site name
+  site.name = prop
+
+  // convert data descriptor
+  if ('value' in descriptor) {
+    descriptor = convertDataDescriptorToAccessor(obj, prop, message)
+  }
+
+  var get = descriptor.get
+  var set = descriptor.set
+
+  // wrap getter
+  if (typeof get === 'function') {
+    descriptor.get = function getter() {
+      log.call(deprecate, message, site)
+      return get.apply(this, arguments)
+    }
+  }
+
+  // wrap setter
+  if (typeof set === 'function') {
+    descriptor.set = function setter() {
+      log.call(deprecate, message, site)
+      return set.apply(this, arguments)
+    }
+  }
+
+  Object.defineProperty(obj, prop, descriptor)
+}
+
+/**
+ * Create DeprecationError for deprecation
+ */
+
+function DeprecationError(namespace, message, stack) {
+  var error = new Error()
+  var stackString
+
+  Object.defineProperty(error, 'constructor', {
+    value: DeprecationError
+  })
+
+  Object.defineProperty(error, 'message', {
+    configurable: true,
+    enumerable: false,
+    value: message,
+    writable: true
+  })
+
+  Object.defineProperty(error, 'name', {
+    enumerable: false,
+    configurable: true,
+    value: 'DeprecationError',
+    writable: true
+  })
+
+  Object.defineProperty(error, 'namespace', {
+    configurable: true,
+    enumerable: false,
+    value: namespace,
+    writable: true
+  })
+
+  Object.defineProperty(error, 'stack', {
+    configurable: true,
+    enumerable: false,
+    get: function () {
+      if (stackString !== undefined) {
+        return stackString
+      }
+
+      // prepare stack trace
+      return stackString = createStackString.call(this, stack)
+    },
+    set: function setter(val) {
+      stackString = val
+    }
+  })
+
+  return error
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..bc62cf5
--- /dev/null
+++ b/package.json
@@ -0,0 +1,25 @@
+{
+  "name": "depd",
+  "description": "Deprecate all the things",
+  "version": "0.3.0",
+  "author": "Douglas Christopher Wilson <doug at somethingdoug.com>",
+  "license": "MIT",
+  "keywords": [
+    "deprecate",
+    "deprecated"
+  ],
+  "repository": "dougwilson/nodejs-depd",
+  "devDependencies": {
+    "istanbul": "0.2.10",
+    "mocha": "~1.20.1",
+    "should": "~4.0.4"
+  },
+  "engines": {
+    "node": ">= 0.8.0"
+  },
+  "scripts": {
+    "test": "mocha --reporter spec --bail --require should test/",
+    "test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --require should test/",
+    "test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --require should test/"
+  }
+}
diff --git a/test/fixtures/cool-lib.js b/test/fixtures/cool-lib.js
new file mode 100644
index 0000000..e8ed86b
--- /dev/null
+++ b/test/fixtures/cool-lib.js
@@ -0,0 +1,11 @@
+
+var deprecate1 = require('../..')('cool-lib')
+var deprecate2 = require('../..')('neat-lib')
+
+exports.cool = function () {
+  deprecate1('cool')
+}
+
+exports.neat = function () {
+  deprecate2('neat')
+}
diff --git a/test/fixtures/multi-lib.js b/test/fixtures/multi-lib.js
new file mode 100644
index 0000000..7129761
--- /dev/null
+++ b/test/fixtures/multi-lib.js
@@ -0,0 +1,11 @@
+
+var deprecate1 = require('../..')('multi-lib')
+var deprecate2 = require('../..')('multi-lib-other')
+
+exports.old = function () {
+  deprecate1('old')
+}
+
+exports.old2 = function () {
+  deprecate2('old2')
+}
diff --git a/test/fixtures/my-lib.js b/test/fixtures/my-lib.js
new file mode 100644
index 0000000..fa096cc
--- /dev/null
+++ b/test/fixtures/my-lib.js
@@ -0,0 +1,64 @@
+
+var deprecate = require('../..')('my-lib')
+
+exports.old = function () {
+  deprecate('old')
+}
+
+exports.old2 = function () {
+  deprecate('old2')
+}
+
+exports.oldfn = deprecate.function(fn, 'oldfn')
+
+exports.oldfnauto = deprecate.function(fn)
+
+exports.oldfnautoanon = deprecate.function(function () {})
+
+exports.propa = 'thingie'
+exports.propauto = 'thingie'
+
+Object.defineProperty(exports, 'propget', {
+  configurable: true,
+  value: 'thingie',
+  writable: false
+})
+
+Object.defineProperty(exports, 'propdyn', {
+  configurable: true,
+  get: function () { return 'thingie' },
+  set: function () {}
+})
+
+Object.defineProperty(exports, 'propgetter', {
+  configurable: true,
+  get: function () { return 'thingie' }
+})
+
+Object.defineProperty(exports, 'propsetter', {
+  configurable: true,
+  set: function () {}
+})
+
+deprecate.property(exports, 'propa', 'propa gone')
+deprecate.property(exports, 'propauto')
+deprecate.property(exports, 'propdyn')
+deprecate.property(exports, 'propget')
+deprecate.property(exports, 'propgetter')
+deprecate.property(exports, 'propsetter')
+
+exports.automsg = function () {
+  deprecate()
+}
+
+exports.automsgnamed = function automsgnamed() {
+  deprecate()
+}
+
+exports.automsganon = function () {
+  (function () { deprecate() }())
+}
+
+function fn(a1, a2) {
+  return a2
+}
diff --git a/test/fixtures/new-lib.js b/test/fixtures/new-lib.js
new file mode 100644
index 0000000..f9593a1
--- /dev/null
+++ b/test/fixtures/new-lib.js
@@ -0,0 +1,6 @@
+
+var deprecate = require('../..')('new-lib')
+
+exports.old = function () {
+  deprecate('old')
+}
diff --git a/test/fixtures/old-lib.js b/test/fixtures/old-lib.js
new file mode 100644
index 0000000..fc33744
--- /dev/null
+++ b/test/fixtures/old-lib.js
@@ -0,0 +1,11 @@
+
+var deprecate1 = require('../..')('old-lib')
+var deprecate2 = require('../..')('old-lib-other')
+
+exports.old = function () {
+  deprecate1('old')
+}
+
+exports.old2 = function () {
+  deprecate2('old2')
+}
diff --git a/test/test.js b/test/test.js
new file mode 100644
index 0000000..50882d0
--- /dev/null
+++ b/test/test.js
@@ -0,0 +1,495 @@
+
+var basename = require('path').basename
+var depd = require('..')
+var mylib = require('./fixtures/my-lib')
+var should = require('should')
+
+describe('depd(namespace)', function () {
+  it('creates deprecated function', function () {
+    depd('test').should.be.a.function
+  })
+
+  it('requires namespace', function () {
+    depd.bind().should.throw(/namespace.*required/)
+  })
+})
+
+describe('deprecate(message)', function () {
+  it('should log namespace', function () {
+    function callold() { mylib.old() }
+    captureStderr(callold).should.containEql('my-lib')
+  })
+
+  it('should log deprecation', function () {
+    function callold() { mylib.old() }
+    captureStderr(callold).should.containEql('deprecate')
+  })
+
+  it('should log message', function () {
+    function callold() { mylib.old() }
+    captureStderr(callold).should.containEql('old')
+  })
+
+  it('should log call site', function () {
+    function callold() { mylib.old() }
+    var stderr = captureStderr(callold)
+    stderr.should.containEql(basename(__filename))
+    stderr.should.match(/\.js:[0-9]+:[0-9]+/)
+  })
+
+  it('should log call site within eval', function () {
+    function callold() { eval('mylib.old()') }
+    var stderr = captureStderr(callold)
+    stderr.should.containEql(basename(__filename))
+    stderr.should.containEql('<anonymous>:1:')
+    stderr.should.match(/\.js:[0-9]+:[0-9]+/)
+  })
+
+  it('should only warn once per call site', function () {
+    function callold() {
+      for (var i = 0; i < 5; i++) {
+        mylib.old() // single call site
+        process.stderr.write('invoke ' + i + '\n')
+      }
+    }
+
+    var stderr = captureStderr(callold)
+    stderr.split('deprecated').should.have.length(2)
+    stderr.split('invoke').should.have.length(6)
+  })
+
+  it('should warn for different fns on same call site', function () {
+    var prop
+
+    function callold() {
+      mylib[prop]() // call from same site
+    }
+
+    prop = 'old'
+    captureStderr(callold).should.containEql(basename(__filename))
+
+    prop = 'old2'
+    captureStderr(callold).should.containEql(basename(__filename))
+  })
+
+  it('should warn for different calls on same line', function () {
+    function callold() {
+      mylib.old(), mylib.old()
+    }
+
+    var stderr = captureStderr(callold)
+    var fileline = stderr.match(/\.js:[0-9]+:/)
+    stderr.should.containEql(basename(__filename))
+    stderr.split('deprecated').should.have.length(3)
+    stderr.split(fileline[0]).should.have.length(3)
+  })
+
+  describe('when message omitted', function () {
+    it('should generate message for method call on named function', function () {
+      function callold() { mylib.automsgnamed() }
+      var stderr = captureStderr(callold)
+      stderr.should.containEql(basename(__filename))
+      stderr.should.containEql('deprecated')
+      stderr.should.containEql(' Object.automsgnamed ')
+    })
+
+    it('should generate message for function call on named function', function () {
+      function callold() {
+        var fn = mylib.automsgnamed
+        fn()
+      }
+      var stderr = captureStderr(callold)
+      stderr.should.containEql(basename(__filename))
+      stderr.should.containEql('deprecated')
+      stderr.should.containEql(' automsgnamed ')
+    })
+
+    it('should generate message for method call on unnamed function', function () {
+      function callold() { mylib.automsg() }
+      var stderr = captureStderr(callold)
+      stderr.should.containEql(basename(__filename))
+      stderr.should.containEql('deprecated')
+      stderr.should.containEql(' Object.exports.automsg ')
+    })
+
+    it('should generate message for function call on unnamed function', function () {
+      function callold() {
+        var fn = mylib.automsg
+        fn()
+      }
+      var stderr = captureStderr(callold)
+      stderr.should.containEql(basename(__filename))
+      stderr.should.containEql('deprecated')
+      stderr.should.containEql(' exports.automsg ')
+    })
+
+    it('should generate message for function call on anonymous function', function () {
+      function callold() { mylib.automsganon() }
+      var stderr = captureStderr(callold)
+      stderr.should.containEql(basename(__filename))
+      stderr.should.containEql('deprecated')
+      stderr.should.match(/ exports\.automsganon | <anonymous@[^:]+:[0-9]+:[0-9]+> /)
+    })
+  })
+
+  describe('when output supports colors', function () {
+    var stderr
+    before(function () {
+      function callold() { mylib.old() }
+      stderr = captureStderr(callold, true)
+    })
+
+    it('should log in color', function () {
+      stderr.should.not.be.empty
+      stderr.should.containEql('\x1b[')
+    })
+
+    it('should log namespace', function () {
+      stderr.should.containEql('my-lib')
+    })
+
+    it('should log deprecation', function () {
+      stderr.should.containEql('deprecate')
+    })
+
+    it('should log message', function () {
+      stderr.should.containEql('old')
+    })
+
+    it('should log call site', function () {
+      stderr.should.containEql(basename(__filename))
+      stderr.should.match(/\.js:[0-9]+:[0-9]+/)
+    })
+  })
+
+  describe('when output does not support colors', function () {
+    var stderr
+    before(function () {
+      function callold() { mylib.old() }
+      stderr = captureStderr(callold, false)
+    })
+
+    it('should not log in color', function () {
+      stderr.should.not.be.empty
+      stderr.should.not.containEql('\x1b[')
+    })
+
+    it('should log namespace', function () {
+      stderr.should.containEql('my-lib')
+    })
+
+    it('should log timestamp', function () {
+      stderr.should.match(/\w+, \d+ \w+ \d{4} \d{2}:\d{2}:\d{2} \w{3}/)
+    })
+
+    it('should log deprecation', function () {
+      stderr.should.containEql('deprecate')
+    })
+
+    it('should log message', function () {
+      stderr.should.containEql('old')
+    })
+
+    it('should log call site', function () {
+      stderr.should.containEql(basename(__filename))
+      stderr.should.match(/\.js:[0-9]+:[0-9]+/)
+    })
+  })
+})
+
+describe('deprecate.function(fn, message)', function () {
+  it('should thrown when not given function', function () {
+    var deprecate = depd('test')
+    deprecate.function.bind(deprecate, 2).should.throw(/fn.*function/)
+  })
+
+  it('should log on call to function', function () {
+    function callold() { mylib.oldfn() }
+    captureStderr(callold).should.containEql(' oldfn ')
+  })
+
+  it('should have same arity', function () {
+    mylib.oldfn.should.have.length(2)
+  })
+
+  it('should pass arguments', function () {
+    var ret
+    function callold() { ret = mylib.oldfn(1, 2) }
+    captureStderr(callold).should.containEql(' oldfn ')
+    ret.should.equal(2)
+  })
+
+  it('should only warn once per call site', function () {
+    function callold() {
+      for (var i = 0; i < 5; i++) {
+        mylib.oldfn() // single call site
+        process.stderr.write('invoke ' + i + '\n')
+      }
+    }
+
+    var stderr = captureStderr(callold)
+    stderr.split('deprecated').should.have.length(2)
+    stderr.split('invoke').should.have.length(6)
+  })
+
+  it('should warn for different calls on same line', function () {
+    function callold() {
+      mylib.oldfn(), mylib.oldfn()
+    }
+
+    var stderr = captureStderr(callold)
+    var fileline = stderr.match(/\.js:[0-9]+:/)
+    stderr.should.containEql(basename(__filename))
+    stderr.split('deprecated').should.have.length(3)
+    stderr.split(fileline[0]).should.have.length(3)
+  })
+
+  describe('when message omitted', function () {
+    it('should generate message for method call on named function', function () {
+      function callold() { mylib.oldfnauto() }
+      var stderr = captureStderr(callold)
+      stderr.should.containEql(basename(__filename))
+      stderr.should.containEql('deprecated')
+      stderr.should.containEql(' Object.fn ')
+      stderr.should.match(/ at [^:]+test\.js:/)
+    })
+
+    it('should generate message for method call on anonymous function', function () {
+      function callold() { mylib.oldfnautoanon() }
+      var stderr = captureStderr(callold)
+      stderr.should.containEql(basename(__filename))
+      stderr.should.containEql('deprecated')
+      stderr.should.match(/ <anonymous@[^:]+my-lib\.js:[0-9]+:[0-9]+> /)
+      stderr.should.match(/ at [^:]+test\.js:/)
+    })
+  })
+})
+
+describe('deprecate.property(obj, prop, message)', function () {
+  it('should throw when given primitive', function () {
+    var deprecate = depd('test')
+    deprecate.property.bind(deprecate, 2).should.throw(/obj.*object/)
+  })
+
+  it('should throw when given missing property', function () {
+    var deprecate = depd('test')
+    var obj = {}
+    deprecate.property.bind(deprecate, obj, 'blargh').should.throw(/property.*owner/)
+  })
+
+  it('should throw when given non-configurable property', function () {
+    var deprecate = depd('test')
+    var obj = {}
+    Object.defineProperty(obj, 'thing', {value: 'thingie'})
+    deprecate.property.bind(deprecate, obj, 'thing').should.throw(/property.*configurable/)
+  })
+
+  it('should log on access to property', function () {
+    function callprop() { mylib.propa }
+    var stderr = captureStderr(callprop)
+    stderr.should.containEql(' deprecated ')
+    stderr.should.containEql(' propa gone ')
+  })
+
+  it('should log on setting property', function () {
+    var val
+    function callprop() { val = mylib.propa }
+    function setprop() { mylib.propa = 'newval' }
+    var stderr = captureStderr(setprop)
+    stderr.should.containEql(' deprecated ')
+    stderr.should.containEql(' propa gone ')
+    captureStderr(callprop).should.containEql(' deprecated ')
+    val.should.equal('newval')
+  })
+
+  it('should only warn once per call site', function () {
+    function callold() {
+      for (var i = 0; i < 5; i++) {
+        mylib.propa // single call site
+        process.stderr.write('access ' + i + '\n')
+      }
+    }
+
+    var stderr = captureStderr(callold)
+    stderr.split('deprecated').should.have.length(2)
+    stderr.split('access').should.have.length(6)
+  })
+
+  it('should warn for different accesses on same line', function () {
+    function callold() {
+      mylib.propa, mylib.propa
+    }
+
+    var stderr = captureStderr(callold)
+    var fileline = stderr.match(/\.js:[0-9]+:/)
+    stderr.should.containEql(basename(__filename))
+    stderr.split('deprecated').should.have.length(3)
+    stderr.split(fileline[0]).should.have.length(3)
+  })
+
+  describe('when value descriptor', function () {
+    it('should log on access and set', function () {
+      function callold() { mylib.propa }
+      function setold() { mylib.propa = 'val' }
+      captureStderr(callold).should.containEql(' deprecated ')
+      captureStderr(setold).should.containEql(' deprecated ')
+    })
+
+    it('should not log on set to non-writable', function () {
+      function callold() { mylib.propget }
+      function setold() { mylib.propget = 'val' }
+      captureStderr(callold).should.containEql(' deprecated ')
+      captureStderr(setold).should.be.empty
+    })
+  })
+
+  describe('when accessor descriptor', function () {
+    it('should log on access and set', function () {
+      function callold() { mylib.propdyn }
+      function setold() { mylib.propdyn = 'val' }
+      captureStderr(callold).should.containEql(' deprecated ')
+      captureStderr(setold).should.containEql(' deprecated ')
+    })
+
+    it('should not log on access when no accessor', function () {
+      function callold() { mylib.propsetter }
+      captureStderr(callold).should.be.empty
+    })
+
+    it('should not log on set when no setter', function () {
+      function callold() { mylib.propgetter = 'val' }
+      captureStderr(callold).should.be.empty
+    })
+  })
+
+  describe('when message omitted', function () {
+    it('should generate message for method call on named function', function () {
+      function callold() { mylib.propauto }
+      var stderr = captureStderr(callold)
+      stderr.should.containEql(basename(__filename))
+      stderr.should.containEql('deprecated')
+      stderr.should.containEql(' Object.propauto ')
+      stderr.should.match(/ at [^:]+test\.js:/)
+    })
+  })
+})
+
+describe('process.on(\'deprecation\', fn)', function () {
+  var error
+  var stderr
+  before(function () {
+    process.on('deprecation', ondeprecation)
+    function callold() { mylib.old() }
+    stderr = captureStderr(callold)
+  })
+  after(function () {
+    process.removeListener('deprecation', ondeprecation)
+  })
+
+  function ondeprecation(err) { error = err }
+
+  it('should not write when listener exists', function () {
+    stderr.should.be.empty
+  })
+
+  it('should emit error', function () {
+    error.should.be.ok
+  })
+
+  it('should emit DeprecationError', function () {
+    error.name.should.equal('DeprecationError')
+  })
+
+  it('should emit DeprecationError', function () {
+    error.name.should.equal('DeprecationError')
+  })
+
+  it('should emit error with message', function () {
+    error.message.should.equal('old')
+  })
+
+  it('should emit error with namespace', function () {
+    error.namespace.should.equal('my-lib')
+  })
+
+  it('should emit error with proper [[Class]]', function () {
+    Object.prototype.toString.call(error).should.equal('[object Error]')
+  })
+
+  it('should be instanceof Error', function () {
+    error.should.be.instanceof(Error)
+  })
+
+  it('should emit error with proper stack', function () {
+    var stack = error.stack.split('\n')
+    stack[0].should.equal('DeprecationError: my-lib deprecated old')
+    stack[1].should.match(/    at callold \(.+test\.js:[0-9]+:[0-9]+\)/)
+  })
+
+  it('should have writable properties', function () {
+    error.name = 'bname'
+    error.name.should.equal('bname')
+    error.message = 'bmessage'
+    error.message.should.equal('bmessage')
+    error.stack = 'bstack'
+    error.stack.should.equal('bstack')
+  })
+})
+
+describe('process.env.NO_DEPRECATION', function () {
+  var error
+  function ondeprecation(err) { error = err }
+
+  after(function () {
+    process.env.NO_DEPRECATION = ''
+  })
+
+  it('should suppress given namespace', function () {
+    process.env.NO_DEPRECATION = 'old-lib'
+    var oldlib = require('./fixtures/old-lib')
+    captureStderr(oldlib.old).should.be.empty
+    captureStderr(oldlib.old2).should.not.be.empty
+  })
+
+  it('should suppress multiple namespaces', function () {
+    process.env.NO_DEPRECATION = 'cool-lib,neat-lib'
+    var coollib = require('./fixtures/cool-lib')
+    captureStderr(coollib.cool).should.be.empty
+    captureStderr(coollib.neat).should.be.empty
+  })
+
+  it('should be case-insensitive', function () {
+    process.env.NO_DEPRECATION = 'NEW-LIB'
+    var newlib = require('./fixtures/new-lib')
+    captureStderr(newlib.old).should.be.empty
+  })
+
+  describe('when *', function () {
+    it('should suppress any namespace', function () {
+      process.env.NO_DEPRECATION = '*'
+      var multilib = require('./fixtures/multi-lib')
+      captureStderr(multilib.old).should.be.empty
+      captureStderr(multilib.old2).should.be.empty
+    })
+  })
+})
+
+function captureStderr(fn, color) {
+  var chunks = []
+  var isTTY = process.stderr.isTTY
+  var write = process.stderr.write
+
+  process.stderr.isTTY = Boolean(color)
+  process.stderr.write = function write(chunk, encoding) {
+    chunks.push(new Buffer(chunk, encoding))
+  }
+
+  try {
+    fn()
+  } finally {
+    process.stderr.isTTY = isTTY
+    process.stderr.write = write
+  }
+
+  return Buffer.concat(chunks).toString('utf8')
+}

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/node-depd.git



More information about the Pkg-javascript-commits mailing list