You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
blockvote/node_modules/depd/index.js

614 lines
19 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*!
* 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 containsNamespace(str, namespace) {
// 使用正则表达式将字符串按空格或逗号分割成数组
var vals = str.split(/[ ,]+/);
// 将命名空间转换为小写以进行不区分大小写的比较
var ns = String(namespace).toLowerCase();
// 遍历分割后的数组
for (var i = 0; i < vals.length; i++) {
var val = vals[i];
// 如果 val 存在,并且等于 '*' 或者等于指定的命名空间,则返回 true
if (val && (val === '*' || val.toLowerCase() === ns)) {
return true;
}
}
// 如果没有找到匹配的命名空间,则返回 false
return false;
}
/**
* 将数据描述符转换为访问器描述符。
* @param {Object} obj - 要修改的对象。
* @param {string} prop - 要转换的属性名。
* @param {string} message - 相关消息(未使用)。
* @returns {Object} - 返回转换后的描述符。
*/
function convertDataDescriptorToAccessor(obj, prop, message) {
// 获取对象的属性描述符
var descriptor = Object.getOwnPropertyDescriptor(obj, prop);
// 获取属性的值
var value = descriptor.value;
// 定义 getter 方法,返回属性的值
descriptor.get = function getter() { return value; };
// 如果属性是可写的,则定义 setter 方法
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.
*/
/**
* 检查给定的字符串中是否包含指定的命名空间。
* @param {string} str - 要检查的字符串,可能包含多个命名空间。
* @param {string} namespace - 要查找的命名空间。
* @returns {boolean} - 如果字符串中包含命名空间,则返回 true否则返回 false。
*/
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];
// 如果 val 存在,并且等于 '*' 或者等于指定的命名空间,则返回 true
if (val && (val === '*' || val.toLowerCase() === ns)) {
return true;
}
}
// 如果没有找到匹配的命名空间,则返回 false
return false;
}
/**
* 将数据描述符转换为访问器描述符。
* @param {Object} obj - 要修改的对象。
* @param {string} prop - 要转换的属性名。
* @param {string} message - 相关消息(未使用)。
* @returns {Object} - 返回转换后的描述符。
*/
function convertDataDescriptorToAccessor(obj, prop, message) {
// 获取对象的属性描述符
var descriptor = Object.getOwnPropertyDescriptor(obj, prop);
// 获取属性的值
var value = descriptor.value;
// 定义 getter 方法,返回属性的值
descriptor.get = function getter() { return value; };
// 如果属性是可写的,则定义 setter 方法
if (descriptor.writable) {
descriptor.set = function setter(val) { return (value = val); };
}
// 删除原有的值和可写性描述符
delete descriptor.value;
delete descriptor.writable;
// 使用新的描述符重新定义对象的属性
Object.defineProperty(obj, prop, descriptor);
// 返回转换后的描述符
return descriptor;
}
/**
* Determine if namespace is ignored.
*/
// 生成一个唯一的键,用于标识调用者的弃用消息
var key = caller
? depSite.join(':') + '__' + caller.join(':') // 如果有调用者,组合依赖站点和调用者信息
: undefined; // 如果没有调用者,键为 undefined
// 检查该键是否已经被警告过
if (key !== undefined && key in this._warned) {
// 如果已经发出警告,则提前返回
return;
}
// 将该键标记为已警告
this._warned[key] = true;
// 生成自动弃用消息
var msg = message; // 首先使用提供的消息
if (!msg) {
// 如果没有提供消息,则根据调用位置生成默认消息
msg = callSite === depSite || !callSite.name
? defaultMessage(depSite) // 如果调用位置与依赖站点相同或没有名称,使用依赖站点生成默认消息
: defaultMessage(callSite); // 否则,使用调用位置生成默认消息
}
// 如果存在监听器,则发出弃用事件
if (haslisteners) {
// 创建一个弃用错误对象并发出事件
var err = DeprecationError(this._namespace, msg, stack.slice(i));
process.emit('deprecation', err); // 发出 'deprecation' 事件
return; // 结束函数
}
// 格式化并写入消息
var format = process.stderr.isTTY // 检查标准错误输出是否为 TTY
? formatColor // 如果是 TTY使用彩色格式
: formatPlain; // 否则,使用普通格式
var output = format.call(this, msg, caller, stack.slice(i)); // 格式化输出消息
process.stderr.write(output + '\n', 'utf8'); // 将消息写入标准错误输出
/**
* 获取调用位置的文件位置作为数组。
*/
function callSiteLocation(callSite) {
var file = callSite.getFileName() || '<anonymous>'; // 获取文件名,如果没有则标记为 '<anonymous>'
var line = callSite.getLineNumber(); // 获取行号
var colm = callSite.getColumnNumber(); // 获取列号
// 如果调用位置是 eval则获取 eval 的原始位置
if (callSite.isEval()) {
file = callSite.getEvalOrigin() + ', ' + file; // 组合 eval 原始位置和文件名
}
var site = [file, line, colm]; // 创建位置数组
site.callSite = callSite; // 将原始调用位置附加到数组
site.name = callSite.getFunctionName(); // 获取函数名称并附加
return site; // 返回位置数组
}
/**
* 从调用位置生成默认消息。
*/
function defaultMessage(site) {
var callSite = site.callSite; // 获取调用位置
var funcName = site.name; // 获取函数名称
// 为匿名函数生成有用的名称
if (!funcName) {
funcName = '<anonymous@' + formatLocation(site) + '>'; // 如果没有函数名,生成匿名名称
}
var context = callSite.getThis(); // 获取调用上下文
var typeName = context && callSite.getTypeName(); // 获取类型名称
// 忽略无用的类型名称
if (typeName === 'Object') {
typeName = undefined; // 如果类型名称是 'Object',则设置为 undefined
}
// 为有用的类型名称
if (typeName === 'Function') {
typeName = context.name || typeName; // 如果上下文是函数,使用上下文的名称
}
// 生成默认消息
return typeName && callSite.getMethodName()
? typeName + '.' + funcName // 如果有类型名称和方法名称,组合成 '类型名.函数名'
: funcName; // 否则,仅返回函数名称
}
/**
* Format deprecation message without color.
*/
/**
* 格式化普通的弃用消息。
* @param {string} msg - 弃用消息。
* @param {Object} caller - 调用者信息。
* @param {Array} stack - 堆栈跟踪数组。
* @returns {string} - 格式化后的弃用消息。
*/
function formatPlain(msg, caller, stack) {
var timestamp = new Date().toUTCString(); // 获取当前时间的 UTC 字符串表示
// 组合格式化的消息,包括时间戳、命名空间和弃用消息
var formatted = timestamp +
' ' + this._namespace +
' deprecated ' + msg;
// 添加堆栈跟踪
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; // 返回最终格式化后的消息
}
/**
* 使用颜色格式化弃用消息。
* @param {string} msg - 弃用消息。
* @param {Object} caller - 调用者信息。
* @param {Array} stack - 堆栈跟踪数组。
* @returns {string} - 格式化后的彩色弃用消息。
*/
function formatColor(msg, caller, stack) {
// 组合格式化的消息,使用 ANSI 转义码为不同部分添加颜色
var formatted = '\x1b[36;1m' + this._namespace + '\x1b[22;39m' + // 粗体青色命名空间
' \x1b[33;1mdeprecated\x1b[22;39m' + // 粗体黄色 'deprecated'
' \x1b[0m' + msg + '\x1b[39m'; // 重置颜色并添加消息
// 添加堆栈跟踪
if (this._traced) {
for (var i = 0; i < stack.length; i++) {
formatted += '\n \x1b[36mat ' + stack[i].toString() + '\x1b[39m'; // 在堆栈条目前添加 'at' 和颜色
}
return formatted; // 返回格式化后的消息
}
// 如果有调用者信息,则添加调用者位置
if (caller) {
formatted += ' \x1b[36m' + formatLocation(caller) + '\x1b[39m'; // 格式化调用位置并添加颜色
}
return formatted; // 返回最终格式化后的消息
}
/**
* 格式化调用位置。
* @param {Array} callSite - 调用位置数组,包含文件名、行号和列号。
* @returns {string} - 格式化后的调用位置字符串。
*/
function formatLocation(callSite) {
// 返回相对路径、行号和列号的组合
return relative(basePath, callSite[0]) +
':' + callSite[1] +
':' + callSite[2];
}
/**
* 获取调用堆栈作为调用位置数组。
* @returns {Array} - 堆栈跟踪数组。
*/
function getStack() {
var limit = Error.stackTraceLimit; // 保存当前的堆栈跟踪限制
var obj = {}; // 创建一个对象用于捕获堆栈
var prep = Error.prepareStackTrace; // 保存原始的 prepareStackTrace 函数
// 设置自定义的堆栈准备函数
Error.prepareStackTrace = prepareObjectStackTrace;
Error.stackTraceLimit = Math.max(10, limit); // 确保堆栈跟踪限制至少为 10
// 捕获堆栈
Error.captureStackTrace(obj);
// 从堆栈中切除当前函数
var stack = obj.stack.slice(1);
// 恢复原始的堆栈准备函数和堆栈跟踪限制
Error.prepareStackTrace = prep;
Error.stackTraceLimit = limit;
return stack; // 返回堆栈数组
}
/**
* Capture call site stack from v8.
*/
/**
* 准备堆栈跟踪,返回传入的堆栈。
* @param {Object} obj - 捕获堆栈的对象。
* @param {Array} stack - 堆栈数组。
* @returns {Array} - 返回原始堆栈数组。
*/
function prepareObjectStackTrace(obj, stack) {
return stack; // 直接返回传入的堆栈数组
}
/**
* 返回一个包装的函数,并添加弃用消息。
* @param {Function} fn - 要包装的函数。
* @param {string} message - 弃用消息。
* @returns {Function} - 包装后的函数。
*/
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; // 返回包装后的函数
}
/**
* 在属性上添加弃用消息的包装。
* @param {Object} obj - 拥有属性的对象。
* @param {string} prop - 属性名称。
* @param {string} 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]); // 获取调用位置
// 设置调用位置的名称为属性名称
site.name = prop;
// 如果是数据描述符,则转换为访问器描述符
if ('value' in descriptor) {
descriptor = convertDataDescriptorToAccessor(obj, prop, message);
}
var get = descriptor.get; // 获取 getter
var set = descriptor.set; // 获取 setter
// 包装 getter
if (typeof get === 'function') {
descriptor.get = function getter() {
log.call(deprecate, message, site); // 调用日志记录弃用消息
return get.apply(this, arguments); // 调用原始 getter
};
}
// 包装 setter
if (typeof set === 'function') {
descriptor.set = function setter() {
log.call(deprecate, message, site); // 调用日志记录弃用消息
return set.apply(this, arguments); // 调用原始 setter
};
}
// 重新定义属性,应用新的描述符
Object.defineProperty(obj, prop, descriptor);
}
/**
* 创建一个弃用错误对象。
* @param {string} namespace - 命名空间。
* @param {string} message - 弃用消息。
* @param {Array} stack - 堆栈数组。
*/
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,
});
}
/**
* 准备堆栈跟踪,返回传入的堆栈。
* @param {Object} obj - 捕获堆栈的对象。
* @param {Array} stack - 堆栈数组。
* @returns {Array} - 返回原始堆栈数组。
*/
function prepareObjectStackTrace(obj, stack) {
return stack; // 直接返回传入的堆栈数组
}
/**
* 返回一个包装的函数,并添加弃用消息。
* @param {Function} fn - 要包装的函数。
* @param {string} message - 弃用消息。
* @returns {Function} - 包装后的函数。
*/
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; // 返回包装后的函数
}
/**
* 在属性上添加弃用消息的包装。
* @param {Object} obj - 拥有属性的对象。
* @param {string} prop - 属性名称。
* @param {string} 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]); // 获取调用位置
// 设置调用位置的名称为属性名称
site.name = prop;
// 如果是数据描述符,则转换为访问器描述符
if ('value' in descriptor) {
descriptor = convertDataDescriptorToAccessor(obj, prop, message);
}
var get = descriptor.get; // 获取 getter
var set = descriptor.set; // 获取 setter
// 包装 getter
if (typeof get === 'function') {
descriptor.get = function getter() {
log.call(deprecate, message, site); // 调用日志记录弃用消息
return get.apply(this, arguments); // 调用原始 getter
};
}
// 包装 setter
if (typeof set === 'function') {
descriptor.set = function setter() {
log.call(deprecate, message, site); // 调用日志记录弃用消息
return set.apply(this, arguments); // 调用原始 setter
};
}
// 重新定义属性,应用新的描述符
Object.defineProperty(obj, prop, descriptor);
}
/**
* 创建一个弃用错误对象。
* @param {string} namespace - 命名空间。
* @param {string} message - 弃用消息。
* @param {Array} stack - 堆栈数组。
*/
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,
});
}