root / HServer / 00.Server / 00.Program / node_modules / depd / index.js
이력 | 보기 | 이력해설 | 다운로드 (10.4 KB)
1 |
/*!
|
---|---|
2 |
* depd
|
3 |
* Copyright(c) 2014-2017 Douglas Christopher Wilson
|
4 |
* MIT Licensed
|
5 |
*/
|
6 |
|
7 |
/**
|
8 |
* Module dependencies.
|
9 |
*/
|
10 |
|
11 |
var callSiteToString = require('./lib/compat').callSiteToString |
12 |
var eventListenerCount = require('./lib/compat').eventListenerCount |
13 |
var relative = require('path').relative |
14 |
|
15 |
/**
|
16 |
* Module exports.
|
17 |
*/
|
18 |
|
19 |
module.exports = depd |
20 |
|
21 |
/**
|
22 |
* Get the path to base files on.
|
23 |
*/
|
24 |
|
25 |
var basePath = process.cwd()
|
26 |
|
27 |
/**
|
28 |
* Determine if namespace is contained in the string.
|
29 |
*/
|
30 |
|
31 |
function containsNamespace (str, namespace) { |
32 |
var vals = str.split(/[ ,]+/) |
33 |
var ns = String(namespace).toLowerCase()
|
34 |
|
35 |
for (var i = 0; i < vals.length; i++) { |
36 |
var val = vals[i]
|
37 |
|
38 |
// namespace contained
|
39 |
if (val && (val === '*' || val.toLowerCase() === ns)) { |
40 |
return true |
41 |
} |
42 |
} |
43 |
|
44 |
return false |
45 |
} |
46 |
|
47 |
/**
|
48 |
* Convert a data descriptor to accessor descriptor.
|
49 |
*/
|
50 |
|
51 |
function convertDataDescriptorToAccessor (obj, prop, message) { |
52 |
var descriptor = Object.getOwnPropertyDescriptor(obj, prop)
|
53 |
var value = descriptor.value
|
54 |
|
55 |
descriptor.get = function getter () { return value } |
56 |
|
57 |
if (descriptor.writable) {
|
58 |
descriptor.set = function setter (val) { return (value = val) } |
59 |
} |
60 |
|
61 |
delete descriptor.value
|
62 |
delete descriptor.writable
|
63 |
|
64 |
Object.defineProperty(obj, prop, descriptor) |
65 |
|
66 |
return descriptor
|
67 |
} |
68 |
|
69 |
/**
|
70 |
* Create arguments string to keep arity.
|
71 |
*/
|
72 |
|
73 |
function createArgumentsString (arity) { |
74 |
var str = '' |
75 |
|
76 |
for (var i = 0; i < arity; i++) { |
77 |
str += ', arg' + i
|
78 |
} |
79 |
|
80 |
return str.substr(2) |
81 |
} |
82 |
|
83 |
/**
|
84 |
* Create stack string from stack.
|
85 |
*/
|
86 |
|
87 |
function createStackString (stack) { |
88 |
var str = this.name + ': ' + this.namespace |
89 |
|
90 |
if (this.message) { |
91 |
str += ' deprecated ' + this.message |
92 |
} |
93 |
|
94 |
for (var i = 0; i < stack.length; i++) { |
95 |
str += '\n at ' + callSiteToString(stack[i])
|
96 |
} |
97 |
|
98 |
return str
|
99 |
} |
100 |
|
101 |
/**
|
102 |
* Create deprecate for namespace in caller.
|
103 |
*/
|
104 |
|
105 |
function depd (namespace) { |
106 |
if (!namespace) {
|
107 |
throw new TypeError('argument namespace is required') |
108 |
} |
109 |
|
110 |
var stack = getStack()
|
111 |
var site = callSiteLocation(stack[1]) |
112 |
var file = site[0] |
113 |
|
114 |
function deprecate (message) { |
115 |
// call to self as log
|
116 |
log.call(deprecate, message) |
117 |
} |
118 |
|
119 |
deprecate._file = file |
120 |
deprecate._ignored = isignored(namespace) |
121 |
deprecate._namespace = namespace |
122 |
deprecate._traced = istraced(namespace) |
123 |
deprecate._warned = Object.create(null)
|
124 |
|
125 |
deprecate.function = wrapfunction
|
126 |
deprecate.property = wrapproperty |
127 |
|
128 |
return deprecate
|
129 |
} |
130 |
|
131 |
/**
|
132 |
* Determine if namespace is ignored.
|
133 |
*/
|
134 |
|
135 |
function isignored (namespace) { |
136 |
/* istanbul ignore next: tested in a child processs */
|
137 |
if (process.noDeprecation) {
|
138 |
// --no-deprecation support
|
139 |
return true |
140 |
} |
141 |
|
142 |
var str = process.env.NO_DEPRECATION || '' |
143 |
|
144 |
// namespace ignored
|
145 |
return containsNamespace(str, namespace)
|
146 |
} |
147 |
|
148 |
/**
|
149 |
* Determine if namespace is traced.
|
150 |
*/
|
151 |
|
152 |
function istraced (namespace) { |
153 |
/* istanbul ignore next: tested in a child processs */
|
154 |
if (process.traceDeprecation) {
|
155 |
// --trace-deprecation support
|
156 |
return true |
157 |
} |
158 |
|
159 |
var str = process.env.TRACE_DEPRECATION || '' |
160 |
|
161 |
// namespace traced
|
162 |
return containsNamespace(str, namespace)
|
163 |
} |
164 |
|
165 |
/**
|
166 |
* Display deprecation message.
|
167 |
*/
|
168 |
|
169 |
function log (message, site) { |
170 |
var haslisteners = eventListenerCount(process, 'deprecation') !== 0 |
171 |
|
172 |
// abort early if no destination
|
173 |
if (!haslisteners && this._ignored) { |
174 |
return
|
175 |
} |
176 |
|
177 |
var caller
|
178 |
var callFile
|
179 |
var callSite
|
180 |
var depSite
|
181 |
var i = 0 |
182 |
var seen = false |
183 |
var stack = getStack()
|
184 |
var file = this._file |
185 |
|
186 |
if (site) {
|
187 |
// provided site
|
188 |
depSite = site |
189 |
callSite = callSiteLocation(stack[1])
|
190 |
callSite.name = depSite.name |
191 |
file = callSite[0]
|
192 |
} else {
|
193 |
// get call site
|
194 |
i = 2
|
195 |
depSite = callSiteLocation(stack[i]) |
196 |
callSite = depSite |
197 |
} |
198 |
|
199 |
// get caller of deprecated thing in relation to file
|
200 |
for (; i < stack.length; i++) {
|
201 |
caller = callSiteLocation(stack[i]) |
202 |
callFile = caller[0]
|
203 |
|
204 |
if (callFile === file) {
|
205 |
seen = true
|
206 |
} else if (callFile === this._file) { |
207 |
file = this._file
|
208 |
} else if (seen) { |
209 |
break
|
210 |
} |
211 |
} |
212 |
|
213 |
var key = caller
|
214 |
? depSite.join(':') + '__' + caller.join(':') |
215 |
: undefined
|
216 |
|
217 |
if (key !== undefined && key in this._warned) { |
218 |
// already warned
|
219 |
return
|
220 |
} |
221 |
|
222 |
this._warned[key] = true |
223 |
|
224 |
// generate automatic message from call site
|
225 |
var msg = message
|
226 |
if (!msg) {
|
227 |
msg = callSite === depSite || !callSite.name |
228 |
? defaultMessage(depSite) |
229 |
: defaultMessage(callSite) |
230 |
} |
231 |
|
232 |
// emit deprecation if listeners exist
|
233 |
if (haslisteners) {
|
234 |
var err = DeprecationError(this._namespace, msg, stack.slice(i)) |
235 |
process.emit('deprecation', err)
|
236 |
return
|
237 |
} |
238 |
|
239 |
// format and write message
|
240 |
var format = process.stderr.isTTY
|
241 |
? formatColor |
242 |
: formatPlain |
243 |
var output = format.call(this, msg, caller, stack.slice(i)) |
244 |
process.stderr.write(output + '\n', 'utf8') |
245 |
} |
246 |
|
247 |
/**
|
248 |
* Get call site location as array.
|
249 |
*/
|
250 |
|
251 |
function callSiteLocation (callSite) { |
252 |
var file = callSite.getFileName() || '<anonymous>' |
253 |
var line = callSite.getLineNumber()
|
254 |
var colm = callSite.getColumnNumber()
|
255 |
|
256 |
if (callSite.isEval()) {
|
257 |
file = callSite.getEvalOrigin() + ', ' + file
|
258 |
} |
259 |
|
260 |
var site = [file, line, colm]
|
261 |
|
262 |
site.callSite = callSite |
263 |
site.name = callSite.getFunctionName() |
264 |
|
265 |
return site
|
266 |
} |
267 |
|
268 |
/**
|
269 |
* Generate a default message from the site.
|
270 |
*/
|
271 |
|
272 |
function defaultMessage (site) { |
273 |
var callSite = site.callSite
|
274 |
var funcName = site.name
|
275 |
|
276 |
// make useful anonymous name
|
277 |
if (!funcName) {
|
278 |
funcName = '<anonymous@' + formatLocation(site) + '>' |
279 |
} |
280 |
|
281 |
var context = callSite.getThis()
|
282 |
var typeName = context && callSite.getTypeName()
|
283 |
|
284 |
// ignore useless type name
|
285 |
if (typeName === 'Object') { |
286 |
typeName = undefined
|
287 |
} |
288 |
|
289 |
// make useful type name
|
290 |
if (typeName === 'Function') { |
291 |
typeName = context.name || typeName |
292 |
} |
293 |
|
294 |
return typeName && callSite.getMethodName()
|
295 |
? typeName + '.' + funcName
|
296 |
: funcName |
297 |
} |
298 |
|
299 |
/**
|
300 |
* Format deprecation message without color.
|
301 |
*/
|
302 |
|
303 |
function formatPlain (msg, caller, stack) { |
304 |
var timestamp = new Date().toUTCString() |
305 |
|
306 |
var formatted = timestamp +
|
307 |
' ' + this._namespace + |
308 |
' deprecated ' + msg
|
309 |
|
310 |
// add stack trace
|
311 |
if (this._traced) { |
312 |
for (var i = 0; i < stack.length; i++) { |
313 |
formatted += '\n at ' + callSiteToString(stack[i])
|
314 |
} |
315 |
|
316 |
return formatted
|
317 |
} |
318 |
|
319 |
if (caller) {
|
320 |
formatted += ' at ' + formatLocation(caller)
|
321 |
} |
322 |
|
323 |
return formatted
|
324 |
} |
325 |
|
326 |
/**
|
327 |
* Format deprecation message with color.
|
328 |
*/
|
329 |
|
330 |
function formatColor (msg, caller, stack) { |
331 |
var formatted = '\x1b[36;1m' + this._namespace + '\x1b[22;39m' + // bold cyan |
332 |
' \x1b[33;1mdeprecated\x1b[22;39m' + // bold yellow |
333 |
' \x1b[0m' + msg + '\x1b[39m' // reset |
334 |
|
335 |
// add stack trace
|
336 |
if (this._traced) { |
337 |
for (var i = 0; i < stack.length; i++) { |
338 |
formatted += '\n \x1b[36mat ' + callSiteToString(stack[i]) + '\x1b[39m' // cyan |
339 |
} |
340 |
|
341 |
return formatted
|
342 |
} |
343 |
|
344 |
if (caller) {
|
345 |
formatted += ' \x1b[36m' + formatLocation(caller) + '\x1b[39m' // cyan |
346 |
} |
347 |
|
348 |
return formatted
|
349 |
} |
350 |
|
351 |
/**
|
352 |
* Format call site location.
|
353 |
*/
|
354 |
|
355 |
function formatLocation (callSite) { |
356 |
return relative(basePath, callSite[0]) + |
357 |
':' + callSite[1] + |
358 |
':' + callSite[2] |
359 |
} |
360 |
|
361 |
/**
|
362 |
* Get the stack as array of call sites.
|
363 |
*/
|
364 |
|
365 |
function getStack () { |
366 |
var limit = Error.stackTraceLimit
|
367 |
var obj = {}
|
368 |
var prep = Error.prepareStackTrace
|
369 |
|
370 |
Error.prepareStackTrace = prepareObjectStackTrace |
371 |
Error.stackTraceLimit = Math.max(10, limit)
|
372 |
|
373 |
// capture the stack
|
374 |
Error.captureStackTrace(obj) |
375 |
|
376 |
// slice this function off the top
|
377 |
var stack = obj.stack.slice(1) |
378 |
|
379 |
Error.prepareStackTrace = prep |
380 |
Error.stackTraceLimit = limit |
381 |
|
382 |
return stack
|
383 |
} |
384 |
|
385 |
/**
|
386 |
* Capture call site stack from v8.
|
387 |
*/
|
388 |
|
389 |
function prepareObjectStackTrace (obj, stack) { |
390 |
return stack
|
391 |
} |
392 |
|
393 |
/**
|
394 |
* Return a wrapped function in a deprecation message.
|
395 |
*/
|
396 |
|
397 |
function wrapfunction (fn, message) { |
398 |
if (typeof fn !== 'function') { |
399 |
throw new TypeError('argument fn must be a function') |
400 |
} |
401 |
|
402 |
var args = createArgumentsString(fn.length)
|
403 |
var deprecate = this // eslint-disable-line no-unused-vars |
404 |
var stack = getStack()
|
405 |
var site = callSiteLocation(stack[1]) |
406 |
|
407 |
site.name = fn.name |
408 |
|
409 |
// eslint-disable-next-line no-eval
|
410 |
var deprecatedfn = eval('(function (' + args + ') {\n' + |
411 |
'"use strict"\n' +
|
412 |
'log.call(deprecate, message, site)\n' +
|
413 |
'return fn.apply(this, arguments)\n' +
|
414 |
'})')
|
415 |
|
416 |
return deprecatedfn
|
417 |
} |
418 |
|
419 |
/**
|
420 |
* Wrap property in a deprecation message.
|
421 |
*/
|
422 |
|
423 |
function wrapproperty (obj, prop, message) { |
424 |
if (!obj || (typeof obj !== 'object' && typeof obj !== 'function')) { |
425 |
throw new TypeError('argument obj must be object') |
426 |
} |
427 |
|
428 |
var descriptor = Object.getOwnPropertyDescriptor(obj, prop)
|
429 |
|
430 |
if (!descriptor) {
|
431 |
throw new TypeError('must call property on owner object') |
432 |
} |
433 |
|
434 |
if (!descriptor.configurable) {
|
435 |
throw new TypeError('property must be configurable') |
436 |
} |
437 |
|
438 |
var deprecate = this |
439 |
var stack = getStack()
|
440 |
var site = callSiteLocation(stack[1]) |
441 |
|
442 |
// set site name
|
443 |
site.name = prop |
444 |
|
445 |
// convert data descriptor
|
446 |
if ('value' in descriptor) { |
447 |
descriptor = convertDataDescriptorToAccessor(obj, prop, message) |
448 |
} |
449 |
|
450 |
var get = descriptor.get
|
451 |
var set = descriptor.set
|
452 |
|
453 |
// wrap getter
|
454 |
if (typeof get === 'function') { |
455 |
descriptor.get = function getter () { |
456 |
log.call(deprecate, message, site) |
457 |
return get.apply(this, arguments) |
458 |
} |
459 |
} |
460 |
|
461 |
// wrap setter
|
462 |
if (typeof set === 'function') { |
463 |
descriptor.set = function setter () { |
464 |
log.call(deprecate, message, site) |
465 |
return set.apply(this, arguments) |
466 |
} |
467 |
} |
468 |
|
469 |
Object.defineProperty(obj, prop, descriptor) |
470 |
} |
471 |
|
472 |
/**
|
473 |
* Create DeprecationError for deprecation
|
474 |
*/
|
475 |
|
476 |
function DeprecationError (namespace, message, stack) { |
477 |
var error = new Error() |
478 |
var stackString
|
479 |
|
480 |
Object.defineProperty(error, 'constructor', {
|
481 |
value: DeprecationError
|
482 |
}) |
483 |
|
484 |
Object.defineProperty(error, 'message', {
|
485 |
configurable: true, |
486 |
enumerable: false, |
487 |
value: message,
|
488 |
writable: true |
489 |
}) |
490 |
|
491 |
Object.defineProperty(error, 'name', {
|
492 |
enumerable: false, |
493 |
configurable: true, |
494 |
value: 'DeprecationError', |
495 |
writable: true |
496 |
}) |
497 |
|
498 |
Object.defineProperty(error, 'namespace', {
|
499 |
configurable: true, |
500 |
enumerable: false, |
501 |
value: namespace,
|
502 |
writable: true |
503 |
}) |
504 |
|
505 |
Object.defineProperty(error, 'stack', {
|
506 |
configurable: true, |
507 |
enumerable: false, |
508 |
get: function () { |
509 |
if (stackString !== undefined) { |
510 |
return stackString
|
511 |
} |
512 |
|
513 |
// prepare stack trace
|
514 |
return (stackString = createStackString.call(this, stack)) |
515 |
}, |
516 |
set: function setter (val) { |
517 |
stackString = val |
518 |
} |
519 |
}) |
520 |
|
521 |
return error
|
522 |
} |