opusdev/vector-similarity-api
1
1/*!2 * depd3 * Copyright(c) 2014-2018 Douglas Christopher Wilson4 * MIT Licensed5 */6 7/**8 * Module dependencies.9 */10 11var relative = require('path').relative12 13/**14 * Module exports.15 */16 17module.exports = depd18 19/**20 * Get the path to base files on.21 */22 23var basePath = process.cwd()24 25/**26 * Determine if namespace is contained in the string.27 */28 29function containsNamespace (str, namespace) {30 var vals = str.split(/[ ,]+/)31 var ns = String(namespace).toLowerCase()32 33 for (var i = 0; i < vals.length; i++) {34 var val = vals[i]35 36 // namespace contained37 if (val && (val === '*' || val.toLowerCase() === ns)) {38 return true39 }40 }41 42 return false43}44 45/**46 * Convert a data descriptor to accessor descriptor.47 */48 49function convertDataDescriptorToAccessor (obj, prop, message) {50 var descriptor = Object.getOwnPropertyDescriptor(obj, prop)51 var value = descriptor.value52 53 descriptor.get = function getter () { return value }54 55 if (descriptor.writable) {56 descriptor.set = function setter (val) { return (value = val) }57 }58 59 delete descriptor.value60 delete descriptor.writable61 62 Object.defineProperty(obj, prop, descriptor)63 64 return descriptor65}66 67/**68 * Create arguments string to keep arity.69 */70 71function createArgumentsString (arity) {72 var str = ''73 74 for (var i = 0; i < arity; i++) {75 str += ', arg' + i76 }77 78 return str.substr(2)79}80 81/**82 * Create stack string from stack.83 */84 85function createStackString (stack) {86 var str = this.name + ': ' + this.namespace87 88 if (this.message) {89 str += ' deprecated ' + this.message90 }91 92 for (var i = 0; i < stack.length; i++) {93 str += '\n at ' + stack[i].toString()94 }95 96 return str97}98 99/**100 * Create deprecate for namespace in caller.101 */102 103function depd (namespace) {104 if (!namespace) {105 throw new TypeError('argument namespace is required')106 }107 108 var stack = getStack()109 var site = callSiteLocation(stack[1])110 var file = site[0]111 112 function deprecate (message) {113 // call to self as log114 log.call(deprecate, message)115 }116 117 deprecate._file = file118 deprecate._ignored = isignored(namespace)119 deprecate._namespace = namespace120 deprecate._traced = istraced(namespace)121 deprecate._warned = Object.create(null)122 123 deprecate.function = wrapfunction124 deprecate.property = wrapproperty125 126 return deprecate127}128 129/**130 * Determine if event emitter has listeners of a given type.131 *132 * The way to do this check is done three different ways in Node.js >= 0.8133 * so this consolidates them into a minimal set using instance methods.134 *135 * @param {EventEmitter} emitter136 * @param {string} type137 * @returns {boolean}138 * @private139 */140 141function eehaslisteners (emitter, type) {142 var count = typeof emitter.listenerCount !== 'function'143 ? emitter.listeners(type).length144 : emitter.listenerCount(type)145 146 return count > 0147}148 149/**150 * Determine if namespace is ignored.151 */152 153function isignored (namespace) {154 if (process.noDeprecation) {155 // --no-deprecation support156 return true157 }158 159 var str = process.env.NO_DEPRECATION || ''160 161 // namespace ignored162 return containsNamespace(str, namespace)163}164 165/**166 * Determine if namespace is traced.167 */168 169function istraced (namespace) {170 if (process.traceDeprecation) {171 // --trace-deprecation support172 return true173 }174 175 var str = process.env.TRACE_DEPRECATION || ''176 177 // namespace traced178 return containsNamespace(str, namespace)179}180 181/**182 * Display deprecation message.183 */184 185function log (message, site) {186 var haslisteners = eehaslisteners(process, 'deprecation')187 188 // abort early if no destination189 if (!haslisteners && this._ignored) {190 return191 }192 193 var caller194 var callFile195 var callSite196 var depSite197 var i = 0198 var seen = false199 var stack = getStack()200 var file = this._file201 202 if (site) {203 // provided site204 depSite = site205 callSite = callSiteLocation(stack[1])206 callSite.name = depSite.name207 file = callSite[0]208 } else {209 // get call site210 i = 2211 depSite = callSiteLocation(stack[i])212 callSite = depSite213 }214 215 // get caller of deprecated thing in relation to file216 for (; i < stack.length; i++) {217 caller = callSiteLocation(stack[i])218 callFile = caller[0]219 220 if (callFile === file) {221 seen = true222 } else if (callFile === this._file) {223 file = this._file224 } else if (seen) {225 break226 }227 }228 229 var key = caller230 ? depSite.join(':') + '__' + caller.join(':')231 : undefined232 233 if (key !== undefined && key in this._warned) {234 // already warned235 return236 }237 238 this._warned[key] = true239 240 // generate automatic message from call site241 var msg = message242 if (!msg) {243 msg = callSite === depSite || !callSite.name244 ? defaultMessage(depSite)245 : defaultMessage(callSite)246 }247 248 // emit deprecation if listeners exist249 if (haslisteners) {250 var err = DeprecationError(this._namespace, msg, stack.slice(i))251 process.emit('deprecation', err)252 return253 }254 255 // format and write message256 var format = process.stderr.isTTY257 ? formatColor258 : formatPlain259 var output = format.call(this, msg, caller, stack.slice(i))260 process.stderr.write(output + '\n', 'utf8')261}262 263/**264 * Get call site location as array.265 */266 267function callSiteLocation (callSite) {268 var file = callSite.getFileName() || '<anonymous>'269 var line = callSite.getLineNumber()270 var colm = callSite.getColumnNumber()271 272 if (callSite.isEval()) {273 file = callSite.getEvalOrigin() + ', ' + file274 }275 276 var site = [file, line, colm]277 278 site.callSite = callSite279 site.name = callSite.getFunctionName()280 281 return site282}283 284/**285 * Generate a default message from the site.286 */287 288function defaultMessage (site) {289 var callSite = site.callSite290 var funcName = site.name291 292 // make useful anonymous name293 if (!funcName) {294 funcName = '<anonymous@' + formatLocation(site) + '>'295 }296 297 var context = callSite.getThis()298 var typeName = context && callSite.getTypeName()299 300 // ignore useless type name301 if (typeName === 'Object') {302 typeName = undefined303 }304 305 // make useful type name306 if (typeName === 'Function') {307 typeName = context.name || typeName308 }309 310 return typeName && callSite.getMethodName()311 ? typeName + '.' + funcName312 : funcName313}314 315/**316 * Format deprecation message without color.317 */318 319function formatPlain (msg, caller, stack) {320 var timestamp = new Date().toUTCString()321 322 var formatted = timestamp +323 ' ' + this._namespace +324 ' deprecated ' + msg325 326 // add stack trace327 if (this._traced) {328 for (var i = 0; i < stack.length; i++) {329 formatted += '\n at ' + stack[i].toString()330 }331 332 return formatted333 }334 335 if (caller) {336 formatted += ' at ' + formatLocation(caller)337 }338 339 return formatted340}341 342/**343 * Format deprecation message with color.344 */345 346function formatColor (msg, caller, stack) {347 var formatted = '\x1b[36;1m' + this._namespace + '\x1b[22;39m' + // bold cyan348 ' \x1b[33;1mdeprecated\x1b[22;39m' + // bold yellow349 ' \x1b[0m' + msg + '\x1b[39m' // reset350 351 // add stack trace352 if (this._traced) {353 for (var i = 0; i < stack.length; i++) {354 formatted += '\n \x1b[36mat ' + stack[i].toString() + '\x1b[39m' // cyan355 }356 357 return formatted358 }359 360 if (caller) {361 formatted += ' \x1b[36m' + formatLocation(caller) + '\x1b[39m' // cyan362 }363 364 return formatted365}366 367/**368 * Format call site location.369 */370 371function formatLocation (callSite) {372 return relative(basePath, callSite[0]) +373 ':' + callSite[1] +374 ':' + callSite[2]375}376 377/**378 * Get the stack as array of call sites.379 */380 381function getStack () {382 var limit = Error.stackTraceLimit383 var obj = {}384 var prep = Error.prepareStackTrace385 386 Error.prepareStackTrace = prepareObjectStackTrace387 Error.stackTraceLimit = Math.max(10, limit)388 389 // capture the stack390 Error.captureStackTrace(obj)391 392 // slice this function off the top393 var stack = obj.stack.slice(1)394 395 Error.prepareStackTrace = prep396 Error.stackTraceLimit = limit397 398 return stack399}400 401/**402 * Capture call site stack from v8.403 */404 405function prepareObjectStackTrace (obj, stack) {406 return stack407}408 409/**410 * Return a wrapped function in a deprecation message.411 */412 413function wrapfunction (fn, message) {414 if (typeof fn !== 'function') {415 throw new TypeError('argument fn must be a function')416 }417 418 var args = createArgumentsString(fn.length)419 var stack = getStack()420 var site = callSiteLocation(stack[1])421 422 site.name = fn.name423 424 // eslint-disable-next-line no-new-func425 var deprecatedfn = new Function('fn', 'log', 'deprecate', 'message', 'site',426 '"use strict"\n' +427 'return function (' + args + ') {' +428 'log.call(deprecate, message, site)\n' +429 'return fn.apply(this, arguments)\n' +430 '}')(fn, log, this, message, site)431 432 return deprecatedfn433}434 435/**436 * Wrap property in a deprecation message.437 */438 439function wrapproperty (obj, prop, message) {440 if (!obj || (typeof obj !== 'object' && typeof obj !== 'function')) {441 throw new TypeError('argument obj must be object')442 }443 444 var descriptor = Object.getOwnPropertyDescriptor(obj, prop)445 446 if (!descriptor) {447 throw new TypeError('must call property on owner object')448 }449 450 if (!descriptor.configurable) {451 throw new TypeError('property must be configurable')452 }453 454 var deprecate = this455 var stack = getStack()456 var site = callSiteLocation(stack[1])457 458 // set site name459 site.name = prop460 461 // convert data descriptor462 if ('value' in descriptor) {463 descriptor = convertDataDescriptorToAccessor(obj, prop, message)464 }465 466 var get = descriptor.get467 var set = descriptor.set468 469 // wrap getter470 if (typeof get === 'function') {471 descriptor.get = function getter () {472 log.call(deprecate, message, site)473 return get.apply(this, arguments)474 }475 }476 477 // wrap setter478 if (typeof set === 'function') {479 descriptor.set = function setter () {480 log.call(deprecate, message, site)481 return set.apply(this, arguments)482 }483 }484 485 Object.defineProperty(obj, prop, descriptor)486}487 488/**489 * Create DeprecationError for deprecation490 */491 492function DeprecationError (namespace, message, stack) {493 var error = new Error()494 var stackString495 496 Object.defineProperty(error, 'constructor', {497 value: DeprecationError498 })499 500 Object.defineProperty(error, 'message', {501 configurable: true,502 enumerable: false,503 value: message,504 writable: true505 })506 507 Object.defineProperty(error, 'name', {508 enumerable: false,509 configurable: true,510 value: 'DeprecationError',511 writable: true512 })513 514 Object.defineProperty(error, 'namespace', {515 configurable: true,516 enumerable: false,517 value: namespace,518 writable: true519 })520 521 Object.defineProperty(error, 'stack', {522 configurable: true,523 enumerable: false,524 get: function () {525 if (stackString !== undefined) {526 return stackString527 }528 529 // prepare stack trace530 return (stackString = createStackString.call(this, stack))531 },532 set: function setter (val) {533 stackString = val534 }535 })536 537 return error538}539 