|
|
- /*!
- * depd
- * Copyright(c) 2014-2017 Douglas Christopher Wilson
- * MIT Licensed
- */
-
- /**
- * Module dependencies.
- */
-
- var callSiteToString = require('./lib/compat').callSiteToString
- var eventListenerCount = require('./lib/compat').eventListenerCount
- var relative = require('path').relative
-
- /**
- * Module exports.
- */
-
- module.exports = depd
-
- /**
- * Get the path to base files on.
- */
-
- var basePath = process.cwd()
-
- /**
- * Determine if namespace is contained in the string.
- */
-
- function containsNamespace (str, namespace) {
- var vals = str.split(/[ ,]+/)
- var ns = String(namespace).toLowerCase()
-
- for (var i = 0; i < vals.length; i++) {
- var val = vals[i]
-
- // namespace contained
- if (val && (val === '*' || val.toLowerCase() === ns)) {
- return true
- }
- }
-
- return false
- }
-
- /**
- * 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 ' + callSiteToString(stack[i])
- }
-
- 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._traced = istraced(namespace)
- deprecate._warned = Object.create(null)
-
- deprecate.function = wrapfunction
- deprecate.property = wrapproperty
-
- return deprecate
- }
-
- /**
- * Determine if namespace is ignored.
- */
-
- function isignored (namespace) {
- /* istanbul ignore next: tested in a child processs */
- if (process.noDeprecation) {
- // --no-deprecation support
- return true
- }
-
- var str = process.env.NO_DEPRECATION || ''
-
- // namespace ignored
- return containsNamespace(str, namespace)
- }
-
- /**
- * Determine if namespace is traced.
- */
-
- function istraced (namespace) {
- /* istanbul ignore next: tested in a child processs */
- if (process.traceDeprecation) {
- // --trace-deprecation support
- return true
- }
-
- var str = process.env.TRACE_DEPRECATION || ''
-
- // namespace traced
- return containsNamespace(str, namespace)
- }
-
- /**
- * 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 callFile
- var callSite
- var depSite
- var i = 0
- var seen = false
- var stack = getStack()
- var file = this._file
-
- if (site) {
- // provided site
- depSite = site
- callSite = callSiteLocation(stack[1])
- callSite.name = depSite.name
- file = callSite[0]
- } else {
- // get call site
- i = 2
- depSite = callSiteLocation(stack[i])
- callSite = depSite
- }
-
- // get caller of deprecated thing in relation to file
- for (; i < stack.length; i++) {
- caller = callSiteLocation(stack[i])
- callFile = caller[0]
-
- if (callFile === file) {
- seen = true
- } else if (callFile === this._file) {
- file = this._file
- } else if (seen) {
- break
- }
- }
-
- var key = caller
- ? depSite.join(':') + '__' + caller.join(':')
- : undefined
-
- if (key !== undefined && key in this._warned) {
- // already warned
- return
- }
-
- this._warned[key] = true
-
- // generate automatic message from call site
- var msg = message
- if (!msg) {
- msg = callSite === depSite || !callSite.name
- ? defaultMessage(depSite)
- : defaultMessage(callSite)
- }
-
- // emit deprecation if listeners exist
- if (haslisteners) {
- var err = DeprecationError(this._namespace, msg, stack.slice(i))
- process.emit('deprecation', err)
- return
- }
-
- // format and write message
- var format = process.stderr.isTTY
- ? formatColor
- : formatPlain
- var output = format.call(this, msg, caller, stack.slice(i))
- process.stderr.write(output + '\n', 'utf8')
- }
-
- /**
- * 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) + '>'
- }
-
- var context = callSite.getThis()
- var typeName = context && callSite.getTypeName()
-
- // ignore useless type name
- if (typeName === 'Object') {
- typeName = undefined
- }
-
- // make useful type name
- if (typeName === 'Function') {
- typeName = context.name || typeName
- }
-
- return typeName && callSite.getMethodName()
- ? typeName + '.' + funcName
- : funcName
- }
-
- /**
- * Format deprecation message without color.
- */
-
- function formatPlain (msg, caller, stack) {
- var timestamp = new Date().toUTCString()
-
- var formatted = timestamp +
- ' ' + this._namespace +
- ' deprecated ' + msg
-
- // add stack trace
- if (this._traced) {
- for (var i = 0; i < stack.length; i++) {
- formatted += '\n at ' + callSiteToString(stack[i])
- }
-
- return formatted
- }
-
- if (caller) {
- formatted += ' at ' + formatLocation(caller)
- }
-
- return formatted
- }
-
- /**
- * Format deprecation message with color.
- */
-
- function formatColor (msg, caller, stack) {
- var formatted = '\x1b[36;1m' + this._namespace + '\x1b[22;39m' + // bold cyan
- ' \x1b[33;1mdeprecated\x1b[22;39m' + // bold yellow
- ' \x1b[0m' + msg + '\x1b[39m' // reset
-
- // add stack trace
- if (this._traced) {
- for (var i = 0; i < stack.length; i++) {
- formatted += '\n \x1b[36mat ' + callSiteToString(stack[i]) + '\x1b[39m' // cyan
- }
-
- return formatted
- }
-
- 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 limit = Error.stackTraceLimit
- var obj = {}
- var prep = Error.prepareStackTrace
-
- Error.prepareStackTrace = prepareObjectStackTrace
- Error.stackTraceLimit = Math.max(10, limit)
-
- // capture the stack
- Error.captureStackTrace(obj)
-
- // slice this function off the top
- var stack = obj.stack.slice(1)
-
- Error.prepareStackTrace = prep
- Error.stackTraceLimit = limit
-
- 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 // eslint-disable-line no-unused-vars
- var stack = getStack()
- var site = callSiteLocation(stack[1])
-
- site.name = fn.name
-
- // eslint-disable-next-line no-eval
- var deprecatedfn = eval('(function (' + args + ') {\n' +
- '"use strict"\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' && typeof obj !== 'function')) {
- 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
- }
|