123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539 |
- /*!
- * depd
- * Copyright(c) 2014-2018 Douglas Christopher Wilson
- * MIT Licensed
- */
- /**
- * Module dependencies.
- */
- 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 ' + 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._traced = istraced(namespace)
- deprecate._warned = Object.create(null)
- deprecate.function = wrapfunction
- deprecate.property = wrapproperty
- return deprecate
- }
- /**
- * Determine if event emitter has listeners of a given type.
- *
- * The way to do this check is done three different ways in Node.js >= 0.8
- * so this consolidates them into a minimal set using instance methods.
- *
- * @param {EventEmitter} emitter
- * @param {string} type
- * @returns {boolean}
- * @private
- */
- function eehaslisteners (emitter, type) {
- var count = typeof emitter.listenerCount !== 'function'
- ? emitter.listeners(type).length
- : emitter.listenerCount(type)
- return count > 0
- }
- /**
- * Determine if namespace is ignored.
- */
- function isignored (namespace) {
- 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) {
- 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 = eehaslisteners(process, 'deprecation')
- // 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 ' + stack[i].toString()
- }
- 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 ' + stack[i].toString() + '\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 stack = getStack()
- var site = callSiteLocation(stack[1])
- site.name = fn.name
- // eslint-disable-next-line no-new-func
- var deprecatedfn = new Function('fn', 'log', 'deprecate', 'message', 'site',
- '"use strict"\n' +
- 'return function (' + args + ') {' +
- 'log.call(deprecate, message, site)\n' +
- 'return fn.apply(this, arguments)\n' +
- '}')(fn, log, this, message, site)
- 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
- }
|