diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..4a7ea303 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 00000000..f53e9ccf --- /dev/null +++ b/.eslintignore @@ -0,0 +1,5 @@ +.vscode/ +config/ +dist/ +node_modules/ +webpack \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 00000000..eda8d6ad --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,15 @@ +module.exports = { + env: { + es6: true, + node: true, + }, + extends: ["eslint:recommended", "plugin:import/errors", "plugin:import/warnings", "prettier"], + parserOptions: { + ecmaVersion: 2017, + sourceType: "module", + }, + rules: { + quotes: ["error", "double", { avoidEscape: true }], + semi: ["error", "always"], + }, +}; diff --git a/.gitignore b/.gitignore index 45c1bf32..a3076c1f 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ node_modules/ bin/amqp-rabbitmq-0.9.1.json etc/ coverage/ +.nyc_output \ No newline at end of file diff --git a/.mocharc.json b/.mocharc.json new file mode 100644 index 00000000..d1cca7a9 --- /dev/null +++ b/.mocharc.json @@ -0,0 +1,5 @@ +{ + "extension": ["js"], + "ui": "tdd", + "spec": "test/**/*.js" +} diff --git a/.npmignore b/.npmignore index 4ec93971..058a55ec 100644 --- a/.npmignore +++ b/.npmignore @@ -6,3 +6,4 @@ scratch bin/amqp-rabbitmq-0.9.1.json etc/ coverage/ +.nyc_output/ \ No newline at end of file diff --git a/Makefile b/Makefile index 98bd8726..be912c85 100644 --- a/Makefile +++ b/Makefile @@ -42,7 +42,7 @@ bin/amqp-rabbitmq-0.9.1.json: curl -L $(AMQP_JSON) > $@ $(ISTANBUL): - npm install + npm install --production=false $(UGLIFY): - npm install + npm install --production=false diff --git a/amqplib.d.ts b/amqplib.d.ts new file mode 100644 index 00000000..709597fa --- /dev/null +++ b/amqplib.d.ts @@ -0,0 +1,36 @@ +declare module "@worthaboutapig/amqplib" { + export type CloseHandler = () => void; + export type ErrorHandler = (error: Error) => void; + export type IMessage = { content: string }; + + export interface CommonChannelConnection { + close(): Promise; + on(event: string, handler: CloseHandler | ErrorHandler): void; + removeListener(name: string, handler: CloseHandler | ErrorHandler): void; + valid: boolean; + } + + export interface IChannel extends CommonChannelConnection { + handlers?: ChannelEventHandlers; + assertQueue(name: string, options: unknown): Promise; + consume(name: string, handler: (message: IMessage) => Promise, options: { noAck: boolean }): Promise; + sendToQueue(name: string, data: unknown, options: { persistent: true }): boolean; + } + + export interface IConnection extends CommonChannelConnection { + handlers?: ConnectionEventHandlers; + createChannel(): Promise; + } + + export type ConnectionEventHandlers = { + onConnectionError(error: Error): Promise; + onConnectionClose(): Promise; + }; + + export type ChannelEventHandlers = { + onChannelError(error: Error): Promise; + onChannelClose(): Promise; + }; + + export function connect(url: string, connOptions: unknown): Promise; +} diff --git a/channel_api.js b/channel_api.js index 6c8c4dd7..bc08d82a 100644 --- a/channel_api.js +++ b/channel_api.js @@ -1,16 +1,22 @@ -var raw_connect = require('./lib/connect').connect; -var ChannelModel = require('./lib/channel_model').ChannelModel; -var Promise = require('bluebird'); +var raw_connect = require("./lib/connect").connect; +var ChannelModel = require("./lib/channel_model").ChannelModel; function connect(url, connOptions) { - return Promise.fromCallback(function(cb) { - return raw_connect(url, connOptions, cb); - }) - .then(function(conn) { - return new ChannelModel(conn); + var options = { Promise: (connOptions && connOptions.Promise) || Promise }; + + return new options.Promise(function (resolve, reject) { + raw_connect(url, connOptions, function (err, result) { + if (err) { + reject(err); + } else { + resolve(result); + } + }); + }).then(function (conn) { + return new ChannelModel(conn, options); }); -}; +} module.exports.connect = connect; -module.exports.credentials = require('./lib/credentials'); -module.exports.IllegalOperationError = require('./lib/error').IllegalOperationError; +module.exports.credentials = require("./lib/credentials"); +module.exports.IllegalOperationError = require("./lib/error").IllegalOperationError; diff --git a/examples/tutorials/receive_logs_direct.js b/examples/tutorials/receive_logs_direct.js index 17fc22de..68b0994e 100755 --- a/examples/tutorials/receive_logs_direct.js +++ b/examples/tutorials/receive_logs_direct.js @@ -1,45 +1,51 @@ #!/usr/bin/env node -var amqp = require('amqplib'); -var all = require('bluebird').all; -var basename = require('path').basename; +var amqp = require("amqplib"); +var basename = require("path").basename; var severities = process.argv.slice(2); if (severities.length < 1) { - console.warn('Usage: %s [info] [warning] [error]', - basename(process.argv[1])); + console.warn("Usage: %s [info] [warning] [error]", basename(process.argv[1])); process.exit(1); } -amqp.connect('amqp://localhost').then(function(conn) { - process.once('SIGINT', function() { conn.close(); }); - return conn.createChannel().then(function(ch) { - var ex = 'direct_logs'; - - var ok = ch.assertExchange(ex, 'direct', {durable: false}); - - ok = ok.then(function() { - return ch.assertQueue('', {exclusive: true}); - }); - - ok = ok.then(function(qok) { - var queue = qok.queue; - return all(severities.map(function(sev) { - ch.bindQueue(queue, ex, sev); - })).then(function() { return queue; }); +amqp + .connect("amqp://localhost") + .then(function (conn) { + process.once("SIGINT", function () { + conn.close(); }); - ok = ok.then(function(queue) { - return ch.consume(queue, logMessage, {noAck: true}); - }); - return ok.then(function() { - console.log(' [*] Waiting for logs. To exit press CTRL+C.'); + return conn.createChannel().then(function (ch) { + var ex = "direct_logs"; + + var ok = ch.assertExchange(ex, "direct", { durable: false }); + + ok = ok.then(function () { + return ch.assertQueue("", { exclusive: true }); + }); + + ok = ok.then(function (qok) { + var queue = qok.queue; + return Promise.all( + severities.map(function (sev) { + ch.bindQueue(queue, ex, sev); + }), + ).then(function () { + return queue; + }); + }); + + ok = ok.then(function (queue) { + return ch.consume(queue, logMessage, { noAck: true }); + }); + return ok.then(function () { + console.log(" [*] Waiting for logs. To exit press CTRL+C."); + }); + + function logMessage(msg) { + console.log(" [x] %s:'%s'", msg.fields.routingKey, msg.content.toString()); + } }); - - function logMessage(msg) { - console.log(" [x] %s:'%s'", - msg.fields.routingKey, - msg.content.toString()); - } - }); -}).catch(console.warn); + }) + .catch(console.warn); diff --git a/examples/tutorials/receive_logs_topic.js b/examples/tutorials/receive_logs_topic.js index 3e8eb6f0..cbc7b1fd 100755 --- a/examples/tutorials/receive_logs_topic.js +++ b/examples/tutorials/receive_logs_topic.js @@ -1,44 +1,49 @@ #!/usr/bin/env node -var amqp = require('amqplib'); -var basename = require('path').basename; -var all = require('bluebird').all; +var amqp = require("amqplib"); +var basename = require("path").basename; var keys = process.argv.slice(2); if (keys.length < 1) { - console.log('Usage: %s pattern [pattern...]', - basename(process.argv[1])); + console.log("Usage: %s pattern [pattern...]", basename(process.argv[1])); process.exit(1); } -amqp.connect('amqp://localhost').then(function(conn) { - process.once('SIGINT', function() { conn.close(); }); - return conn.createChannel().then(function(ch) { - var ex = 'topic_logs'; - var ok = ch.assertExchange(ex, 'topic', {durable: false}); - - ok = ok.then(function() { - return ch.assertQueue('', {exclusive: true}); +amqp + .connect("amqp://localhost") + .then(function (conn) { + process.once("SIGINT", function () { + conn.close(); }); + return conn.createChannel().then(function (ch) { + var ex = "topic_logs"; + var ok = ch.assertExchange(ex, "topic", { durable: false }); - ok = ok.then(function(qok) { - var queue = qok.queue; - return all(keys.map(function(rk) { - ch.bindQueue(queue, ex, rk); - })).then(function() { return queue; }); - }); + ok = ok.then(function () { + return ch.assertQueue("", { exclusive: true }); + }); - ok = ok.then(function(queue) { - return ch.consume(queue, logMessage, {noAck: true}); - }); - return ok.then(function() { - console.log(' [*] Waiting for logs. To exit press CTRL+C.'); - }); + ok = ok.then(function (qok) { + var queue = qok.queue; + return Promise.all( + keys.map(function (rk) { + ch.bindQueue(queue, ex, rk); + }), + ).then(function () { + return queue; + }); + }); + + ok = ok.then(function (queue) { + return ch.consume(queue, logMessage, { noAck: true }); + }); + return ok.then(function () { + console.log(" [*] Waiting for logs. To exit press CTRL+C."); + }); - function logMessage(msg) { - console.log(" [x] %s:'%s'", - msg.fields.routingKey, - msg.content.toString()); - } - }); -}).catch(console.warn); + function logMessage(msg) { + console.log(" [x] %s:'%s'", msg.fields.routingKey, msg.content.toString()); + } + }); + }) + .catch(console.warn); diff --git a/examples/tutorials/rpc_client.js b/examples/tutorials/rpc_client.js index 47566b34..4d2d58ab 100755 --- a/examples/tutorials/rpc_client.js +++ b/examples/tutorials/rpc_client.js @@ -1,9 +1,8 @@ #!/usr/bin/env node -var amqp = require('amqplib'); -var basename = require('path').basename; -var Promise = require('bluebird'); -var uuid = require('node-uuid'); +var amqp = require("amqplib"); +var basename = require("path").basename; +var uuid = require("node-uuid"); // I've departed from the form of the original RPC tutorial, which // needlessly introduces a class definition, and doesn't even @@ -11,43 +10,52 @@ var uuid = require('node-uuid'); var n; try { - if (process.argv.length < 3) throw Error('Too few args'); + if (process.argv.length < 3) throw Error("Too few args"); n = parseInt(process.argv[2]); -} -catch (e) { +} catch (e) { console.error(e); - console.warn('Usage: %s number', basename(process.argv[1])); + console.warn("Usage: %s number", basename(process.argv[1])); process.exit(1); } -amqp.connect('amqp://localhost').then(function(conn) { - return conn.createChannel().then(function(ch) { - return new Promise(function(resolve) { - var corrId = uuid(); - function maybeAnswer(msg) { - if (msg.properties.correlationId === corrId) { - resolve(msg.content.toString()); - } - } +amqp + .connect("amqp://localhost") + .then(function (conn) { + return conn + .createChannel() + .then(function (ch) { + return new Promise(function (resolve) { + var corrId = uuid(); + function maybeAnswer(msg) { + if (msg.properties.correlationId === corrId) { + resolve(msg.content.toString()); + } + } - var ok = ch.assertQueue('', {exclusive: true}) - .then(function(qok) { return qok.queue; }); + var ok = ch.assertQueue("", { exclusive: true }).then(function (qok) { + return qok.queue; + }); - ok = ok.then(function(queue) { - return ch.consume(queue, maybeAnswer, {noAck: true}) - .then(function() { return queue; }); - }); + ok = ok.then(function (queue) { + return ch.consume(queue, maybeAnswer, { noAck: true }).then(function () { + return queue; + }); + }); - ok = ok.then(function(queue) { - console.log(' [x] Requesting fib(%d)', n); - ch.sendToQueue('rpc_queue', Buffer.from(n.toString()), { - correlationId: corrId, replyTo: queue + ok = ok.then(function (queue) { + console.log(" [x] Requesting fib(%d)", n); + ch.sendToQueue("rpc_queue", Buffer.from(n.toString()), { + correlationId: corrId, + replyTo: queue, + }); + }); }); + }) + .then(function (fibN) { + console.log(" [.] Got %d", fibN); + }) + .finally(function () { + conn.close(); }); - }); - }) - .then(function(fibN) { - console.log(' [.] Got %d', fibN); }) - .finally(function() { conn.close(); }); -}).catch(console.warn); + .catch(console.warn); diff --git a/lib/callback_model.js b/lib/callback_model.js index dca383f8..4c7c50cc 100644 --- a/lib/callback_model.js +++ b/lib/callback_model.js @@ -2,23 +2,22 @@ // // -'use strict'; - -var defs = require('./defs'); -var Promise = require('bluebird'); -var inherits = require('util').inherits; -var EventEmitter = require('events').EventEmitter; -var BaseChannel = require('./channel').BaseChannel; -var acceptMessage = require('./channel').acceptMessage; -var Args = require('./api_args'); - -function CallbackModel(connection) { - if (!(this instanceof CallbackModel)) - return new CallbackModel(connection); - EventEmitter.call( this ); +"use strict"; + +var defs = require("./defs"); +var inherits = require("util").inherits; +var EventEmitter = require("events").EventEmitter; +var BaseChannel = require("./channel").BaseChannel; +var acceptMessage = require("./channel").acceptMessage; +var Args = require("./api_args"); + +function CallbackModel(connection, options) { + if (!(this instanceof CallbackModel)) return new CallbackModel(connection); + EventEmitter.call(this); this.connection = connection; + this.Promise = options || Promise; var self = this; - ['error', 'close', 'blocked', 'unblocked'].forEach(function(ev) { + ["error", "close", "blocked", "unblocked"].forEach(function (ev) { connection.on(ev, self.emit.bind(self, ev)); }); } @@ -26,22 +25,22 @@ inherits(CallbackModel, EventEmitter); module.exports.CallbackModel = CallbackModel; -CallbackModel.prototype.close = function(cb) { +CallbackModel.prototype.close = function (cb) { this.connection.close(cb); }; function Channel(connection) { BaseChannel.call(this, connection); - this.on('delivery', this.handleDelivery.bind(this)); - this.on('cancel', this.handleCancel.bind(this)); + this.on("delivery", this.handleDelivery.bind(this)); + this.on("cancel", this.handleCancel.bind(this)); } inherits(Channel, BaseChannel); module.exports.Channel = Channel; -CallbackModel.prototype.createChannel = function(cb) { +CallbackModel.prototype.createChannel = function (cb) { var ch = new Channel(this.connection); - ch.open(function(err, ok) { + ch.open(function (err, ok) { if (err === null) cb && cb(null, ch); else cb && cb(err); }); @@ -54,12 +53,13 @@ CallbackModel.prototype.createChannel = function(cb) { // otherwise falsey, for convenience in methods for which the callback // is optional (that is, most of them). function callbackWrapper(ch, cb) { - return (cb) ? function(err, ok) { - if (err === null) { - cb(null, ok); - } - else cb(err); - } : function() {}; + return cb + ? function (err, ok) { + if (err === null) { + cb(null, ok); + } else cb(err); + } + : function () {}; } // This encodes straight-forward RPC: no side-effects and return the @@ -68,209 +68,167 @@ function callbackWrapper(ch, cb) { // needs to have side-effects, or needs to change the server response, // use `#_rpc(...)` and remember to dereference `.fields` of the // server response. -Channel.prototype.rpc = function(method, fields, expect, cb0) { +Channel.prototype.rpc = function (method, fields, expect, cb0) { var cb = callbackWrapper(this, cb0); - this._rpc(method, fields, expect, function(err, ok) { + this._rpc(method, fields, expect, function (err, ok) { cb(err, ok && ok.fields); // in case of an error, ok will be - // undefined + // undefined }); return this; }; // === Public API === -Channel.prototype.open = function(cb) { - try { this.allocate(); } - catch (e) { return cb(e); } +Channel.prototype.open = function (cb) { + try { + this.allocate(); + } catch (e) { + return cb(e); + } - return this.rpc(defs.ChannelOpen, {outOfBand: ""}, - defs.ChannelOpenOk, cb); + return this.rpc(defs.ChannelOpen, { outOfBand: "" }, defs.ChannelOpenOk, cb); }; -Channel.prototype.close = function(cb) { - return this.closeBecause("Goodbye", defs.constants.REPLY_SUCCESS, - function() { cb && cb(null); }); +Channel.prototype.close = function (cb) { + return this.closeBecause("Goodbye", defs.constants.REPLY_SUCCESS, function () { + cb && cb(null); + }); }; -Channel.prototype.assertQueue = function(queue, options, cb) { - return this.rpc(defs.QueueDeclare, - Args.assertQueue(queue, options), - defs.QueueDeclareOk, cb); +Channel.prototype.assertQueue = function (queue, options, cb) { + return this.rpc(defs.QueueDeclare, Args.assertQueue(queue, options), defs.QueueDeclareOk, cb); }; -Channel.prototype.checkQueue = function(queue, cb) { - return this.rpc(defs.QueueDeclare, - Args.checkQueue(queue), - defs.QueueDeclareOk, cb); +Channel.prototype.checkQueue = function (queue, cb) { + return this.rpc(defs.QueueDeclare, Args.checkQueue(queue), defs.QueueDeclareOk, cb); }; -Channel.prototype.deleteQueue = function(queue, options, cb) { - return this.rpc(defs.QueueDelete, - Args.deleteQueue(queue, options), - defs.QueueDeleteOk, cb); +Channel.prototype.deleteQueue = function (queue, options, cb) { + return this.rpc(defs.QueueDelete, Args.deleteQueue(queue, options), defs.QueueDeleteOk, cb); }; -Channel.prototype.purgeQueue = function(queue, cb) { - return this.rpc(defs.QueuePurge, - Args.purgeQueue(queue), - defs.QueuePurgeOk, cb); +Channel.prototype.purgeQueue = function (queue, cb) { + return this.rpc(defs.QueuePurge, Args.purgeQueue(queue), defs.QueuePurgeOk, cb); }; -Channel.prototype.bindQueue = - function(queue, source, pattern, argt, cb) { - return this.rpc(defs.QueueBind, - Args.bindQueue(queue, source, pattern, argt), - defs.QueueBindOk, cb); - }; +Channel.prototype.bindQueue = function (queue, source, pattern, argt, cb) { + return this.rpc(defs.QueueBind, Args.bindQueue(queue, source, pattern, argt), defs.QueueBindOk, cb); +}; -Channel.prototype.unbindQueue = - function(queue, source, pattern, argt, cb) { - return this.rpc(defs.QueueUnbind, - Args.unbindQueue(queue, source, pattern, argt), - defs.QueueUnbindOk, cb); - }; +Channel.prototype.unbindQueue = function (queue, source, pattern, argt, cb) { + return this.rpc(defs.QueueUnbind, Args.unbindQueue(queue, source, pattern, argt), defs.QueueUnbindOk, cb); +}; -Channel.prototype.assertExchange = function(ex, type, options, cb0) { +Channel.prototype.assertExchange = function (ex, type, options, cb0) { var cb = callbackWrapper(this, cb0); - this._rpc(defs.ExchangeDeclare, - Args.assertExchange(ex, type, options), - defs.ExchangeDeclareOk, - function(e, _) { cb(e, {exchange: ex}); }); + this._rpc(defs.ExchangeDeclare, Args.assertExchange(ex, type, options), defs.ExchangeDeclareOk, function (e, _) { + cb(e, { exchange: ex }); + }); return this; }; -Channel.prototype.checkExchange = function(exchange, cb) { - return this.rpc(defs.ExchangeDeclare, - Args.checkExchange(exchange), - defs.ExchangeDeclareOk, cb); +Channel.prototype.checkExchange = function (exchange, cb) { + return this.rpc(defs.ExchangeDeclare, Args.checkExchange(exchange), defs.ExchangeDeclareOk, cb); }; -Channel.prototype.deleteExchange = function(exchange, options, cb) { - return this.rpc(defs.ExchangeDelete, - Args.deleteExchange(exchange, options), - defs.ExchangeDeleteOk, cb); +Channel.prototype.deleteExchange = function (exchange, options, cb) { + return this.rpc(defs.ExchangeDelete, Args.deleteExchange(exchange, options), defs.ExchangeDeleteOk, cb); }; -Channel.prototype.bindExchange = - function(dest, source, pattern, argt, cb) { - return this.rpc(defs.ExchangeBind, - Args.bindExchange(dest, source, pattern, argt), - defs.ExchangeBindOk, cb); - }; +Channel.prototype.bindExchange = function (dest, source, pattern, argt, cb) { + return this.rpc(defs.ExchangeBind, Args.bindExchange(dest, source, pattern, argt), defs.ExchangeBindOk, cb); +}; -Channel.prototype.unbindExchange = - function(dest, source, pattern, argt, cb) { - return this.rpc(defs.ExchangeUnbind, - Args.unbindExchange(dest, source, pattern, argt), - defs.ExchangeUnbindOk, cb); - }; +Channel.prototype.unbindExchange = function (dest, source, pattern, argt, cb) { + return this.rpc(defs.ExchangeUnbind, Args.unbindExchange(dest, source, pattern, argt), defs.ExchangeUnbindOk, cb); +}; -Channel.prototype.publish = - function(exchange, routingKey, content, options) { - var fieldsAndProps = Args.publish(exchange, routingKey, options); - return this.sendMessage(fieldsAndProps, fieldsAndProps, content); - }; +Channel.prototype.publish = function (exchange, routingKey, content, options) { + var fieldsAndProps = Args.publish(exchange, routingKey, options); + return this.sendMessage(fieldsAndProps, fieldsAndProps, content); +}; -Channel.prototype.sendToQueue = function(queue, content, options) { - return this.publish('', queue, content, options); +Channel.prototype.sendToQueue = function (queue, content, options) { + return this.publish("", queue, content, options); }; -Channel.prototype.consume = function(queue, callback, options, cb0) { +Channel.prototype.consume = function (queue, callback, options, cb0) { var cb = callbackWrapper(this, cb0); var fields = Args.consume(queue, options); var self = this; - this._rpc( - defs.BasicConsume, fields, defs.BasicConsumeOk, - function(err, ok) { - if (err === null) { - self.registerConsumer(ok.fields.consumerTag, callback); - cb(null, ok.fields); - } - else cb(err); - }); + this._rpc(defs.BasicConsume, fields, defs.BasicConsumeOk, function (err, ok) { + if (err === null) { + self.registerConsumer(ok.fields.consumerTag, callback); + cb(null, ok.fields); + } else cb(err); + }); return this; }; -Channel.prototype.cancel = function(consumerTag, cb0) { +Channel.prototype.cancel = function (consumerTag, cb0) { var cb = callbackWrapper(this, cb0); var self = this; - this._rpc( - defs.BasicCancel, Args.cancel(consumerTag), defs.BasicCancelOk, - function(err, ok) { - if (err === null) { - self.unregisterConsumer(consumerTag); - cb(null, ok.fields); - } - else cb(err); - }); + this._rpc(defs.BasicCancel, Args.cancel(consumerTag), defs.BasicCancelOk, function (err, ok) { + if (err === null) { + self.unregisterConsumer(consumerTag); + cb(null, ok.fields); + } else cb(err); + }); return this; }; -Channel.prototype.get = function(queue, options, cb0) { +Channel.prototype.get = function (queue, options, cb0) { var self = this; var fields = Args.get(queue, options); var cb = callbackWrapper(this, cb0); - this.sendOrEnqueue(defs.BasicGet, fields, function(err, f) { + this.sendOrEnqueue(defs.BasicGet, fields, function (err, f) { if (err === null) { if (f.id === defs.BasicGetEmpty) { cb(null, false); - } - else if (f.id === defs.BasicGetOk) { - self.handleMessage = acceptMessage(function(m) { + } else if (f.id === defs.BasicGetOk) { + self.handleMessage = acceptMessage(function (m) { m.fields = f.fields; cb(null, m); }); - } - else { - cb(new Error("Unexpected response to BasicGet: " + - inspect(f))); + } else { + cb(new Error("Unexpected response to BasicGet: " + inspect(f))); } } }); return this; }; -Channel.prototype.ack = function(message, allUpTo) { - this.sendImmediately( - defs.BasicAck, Args.ack(message.fields.deliveryTag, allUpTo)); +Channel.prototype.ack = function (message, allUpTo) { + this.sendImmediately(defs.BasicAck, Args.ack(message.fields.deliveryTag, allUpTo)); return this; }; -Channel.prototype.ackAll = function() { +Channel.prototype.ackAll = function () { this.sendImmediately(defs.BasicAck, Args.ack(0, true)); return this; }; -Channel.prototype.nack = function(message, allUpTo, requeue) { - this.sendImmediately( - defs.BasicNack, - Args.nack(message.fields.deliveryTag, allUpTo, requeue)); +Channel.prototype.nack = function (message, allUpTo, requeue) { + this.sendImmediately(defs.BasicNack, Args.nack(message.fields.deliveryTag, allUpTo, requeue)); return this; }; -Channel.prototype.nackAll = function(requeue) { - this.sendImmediately( - defs.BasicNack, Args.nack(0, true, requeue)) +Channel.prototype.nackAll = function (requeue) { + this.sendImmediately(defs.BasicNack, Args.nack(0, true, requeue)); return this; }; -Channel.prototype.reject = function(message, requeue) { - this.sendImmediately( - defs.BasicReject, - Args.reject(message.fields.deliveryTag, requeue)); +Channel.prototype.reject = function (message, requeue) { + this.sendImmediately(defs.BasicReject, Args.reject(message.fields.deliveryTag, requeue)); return this; }; -Channel.prototype.prefetch = function(count, global, cb) { - return this.rpc(defs.BasicQos, - Args.prefetch(count, global), - defs.BasicQosOk, cb); +Channel.prototype.prefetch = function (count, global, cb) { + return this.rpc(defs.BasicQos, Args.prefetch(count, global), defs.BasicQosOk, cb); }; -Channel.prototype.recover = function(cb) { - return this.rpc(defs.BasicRecover, - Args.recover(), - defs.BasicRecoverOk, cb); +Channel.prototype.recover = function (cb) { + return this.rpc(defs.BasicRecover, Args.recover(), defs.BasicRecoverOk, cb); }; function ConfirmChannel(connection) { @@ -280,41 +238,39 @@ inherits(ConfirmChannel, Channel); module.exports.ConfirmChannel = ConfirmChannel; -CallbackModel.prototype.createConfirmChannel = function(cb) { +CallbackModel.prototype.createConfirmChannel = function (cb) { var ch = new ConfirmChannel(this.connection); - ch.open(function(err) { + ch.open(function (err) { if (err !== null) return cb && cb(err); else { - ch.rpc(defs.ConfirmSelect, {nowait: false}, - defs.ConfirmSelectOk, function(err, _ok) { - if (err !== null) return cb && cb(err); - else cb && cb(null, ch); - }); + ch.rpc(defs.ConfirmSelect, { nowait: false }, defs.ConfirmSelectOk, function (err, _ok) { + if (err !== null) return cb && cb(err); + else cb && cb(null, ch); + }); } }); return ch; }; -ConfirmChannel.prototype.publish = function(exchange, routingKey, - content, options, cb) { +ConfirmChannel.prototype.publish = function (exchange, routingKey, content, options, cb) { this.pushConfirmCallback(cb); - return Channel.prototype.publish.call( - this, exchange, routingKey, content, options); + return Channel.prototype.publish.call(this, exchange, routingKey, content, options); }; -ConfirmChannel.prototype.sendToQueue = function(queue, content, - options, cb) { - return this.publish('', queue, content, options, cb); +ConfirmChannel.prototype.sendToQueue = function (queue, content, options, cb) { + return this.publish("", queue, content, options, cb); }; -ConfirmChannel.prototype.waitForConfirms = function(k) { +ConfirmChannel.prototype.waitForConfirms = function (k) { + var self = this; var awaiting = []; var unconfirmed = this.unconfirmed; - unconfirmed.forEach(function(val, index) { - if (val === null); // already confirmed + unconfirmed.forEach(function (val, index) { + if (val === null); else { - var confirmed = new Promise(function(resolve, reject) { - unconfirmed[index] = function(err) { + // already confirmed + var confirmed = new self.Promise(function (resolve, reject) { + unconfirmed[index] = function (err) { if (val) val(err); if (err === null) resolve(); else reject(err); @@ -323,6 +279,12 @@ ConfirmChannel.prototype.waitForConfirms = function(k) { awaiting.push(confirmed); } }); - return Promise.all(awaiting).then(function() { k(); }, - function(err) { k(err); }); + return this.Promise.all(awaiting).then( + function () { + k(); + }, + function (err) { + k(err); + }, + ); }; diff --git a/lib/channel.js b/lib/channel.js index fc8f17d6..71bd13c4 100644 --- a/lib/channel.js +++ b/lib/channel.js @@ -4,21 +4,22 @@ // Channel machinery. -'use strict'; - -var defs = require('./defs'); -var closeMsg = require('./format').closeMessage; -var inspect = require('./format').inspect; -var methodName = require('./format').methodName; -var assert = require('assert'); -var inherits = require('util').inherits; -var EventEmitter = require('events').EventEmitter; -var fmt = require('util').format; -var IllegalOperationError = require('./error').IllegalOperationError; -var stackCapture = require('./error').stackCapture; -var Buffer = require('safe-buffer').Buffer -function Channel(connection) { - EventEmitter.call( this ); +"use strict"; + +var defs = require("./defs"); +var closeMsg = require("./format").closeMessage; +var inspect = require("./format").inspect; +var methodName = require("./format").methodName; +var assert = require("assert"); +var inherits = require("util").inherits; +var EventEmitter = require("events").EventEmitter; +var fmt = require("util").format; +var IllegalOperationError = require("./error").IllegalOperationError; +var stackCapture = require("./error").stackCapture; +var Buffer = require("safe-buffer").Buffer; +function Channel(connection, options) { + EventEmitter.call(this); + this.Promise = (options && options.Promise) || Promise; this.connection = connection; // for the presently outstanding RPC this.reply = null; @@ -27,18 +28,24 @@ function Channel(connection) { // for unconfirmed messages this.lwm = 1; // the least, unconfirmed deliveryTag this.unconfirmed = []; // rolling window of delivery callbacks - this.on('ack', this.handleConfirm.bind(this, function(cb) { - if (cb) cb(null); - })); - this.on('nack', this.handleConfirm.bind(this, function(cb) { - if (cb) cb(new Error('message nacked')); - })); - this.on('close', function () { + this.on( + "ack", + this.handleConfirm.bind(this, function (cb) { + if (cb) cb(null); + }), + ); + this.on( + "nack", + this.handleConfirm.bind(this, function (cb) { + if (cb) cb(new Error("message nacked")); + }), + ); + this.on("close", function () { var cb; - while (cb = this.unconfirmed.shift()) { - if (cb) cb(new Error('channel closed')); + while ((cb = this.unconfirmed.shift())) { + if (cb) cb(new Error("channel closed")); } - }) + }); // message frame state machine this.handleMessage = acceptDeliveryOrReturn; } @@ -49,10 +56,10 @@ module.exports.acceptMessage = acceptMessage; var C = Channel.prototype; -C.allocate = function() { +C.allocate = function () { this.ch = this.connection.freshChannel(this); return this; -} +}; // Incoming frames are either notifications of e.g., message delivery, // or replies to something we've sent. In general I deal with the @@ -66,7 +73,7 @@ C.allocate = function() { // reply. // Just send the damn frame. -C.sendImmediately = function(method, fields) { +C.sendImmediately = function (method, fields) { return this.connection.sendMethod(this.ch, method, fields); }; @@ -74,47 +81,37 @@ C.sendImmediately = function(method, fields) { // clear a reply, we must send another RPC (and thereby fill // this.reply) if there is one waiting. The invariant relevant here // and in `accept`. -C.sendOrEnqueue = function(method, fields, reply) { - if (!this.reply) { // if no reply waiting, we can go +C.sendOrEnqueue = function (method, fields, reply) { + if (!this.reply) { + // if no reply waiting, we can go assert(this.pending.length === 0); this.reply = reply; this.sendImmediately(method, fields); - } - else { - this.pending.push({method: method, - fields: fields, - reply: reply}); + } else { + this.pending.push({ method: method, fields: fields, reply: reply }); } }; -C.sendMessage = function(fields, properties, content) { - return this.connection.sendMessage( - this.ch, - defs.BasicPublish, fields, - defs.BasicProperties, properties, - content); +C.sendMessage = function (fields, properties, content) { + return this.connection.sendMessage(this.ch, defs.BasicPublish, fields, defs.BasicProperties, properties, content); }; // Internal, synchronously resolved RPC; the return value is resolved // with the whole frame. -C._rpc = function(method, fields, expect, cb) { +C._rpc = function (method, fields, expect, cb) { var self = this; function reply(err, f) { if (err === null) { if (f.id === expect) { return cb(null, f); - } - else { + } else { // We have detected a problem, so it's up to us to close the // channel var expectedName = methodName(expect); - var e = new Error(fmt("Expected %s; got %s", - expectedName, inspect(f, false))); - self.closeWithError(f.id, fmt('Expected %s; got %s', - expectedName, methodName(f.id)), - defs.constants.UNEXPECTED_FRAME, e); + var e = new Error(fmt("Expected %s; got %s", expectedName, inspect(f, false))); + self.closeWithError(f.id, fmt("Expected %s; got %s", expectedName, methodName(f.id)), defs.constants.UNEXPECTED_FRAME, e); return cb(e); } } @@ -125,12 +122,8 @@ C._rpc = function(method, fields, expect, cb) { // and the channel is closed by the server else { // otherwise, it's a close frame - var closeReason = - (err.fields.classId << 16) + err.fields.methodId; - var e = (method === closeReason) - ? fmt("Operation failed: %s; %s", - methodName(method), closeMsg(err)) - : fmt("Channel closed by server: %s", closeMsg(err)); + var closeReason = (err.fields.classId << 16) + err.fields.methodId; + var e = method === closeReason ? fmt("Operation failed: %s; %s", methodName(method), closeMsg(err)) : fmt("Channel closed by server: %s", closeMsg(err)); var closeFrameError = new Error(e); closeFrameError.code = err.fields.replyCode; closeFrameError.classId = err.fields.classId; @@ -156,47 +149,45 @@ C._rpc = function(method, fields, expect, cb) { // the exchange. function invalidOp(msg, stack) { - return function() { + return function () { throw new IllegalOperationError(msg, stack); }; } function invalidateSend(ch, msg, stack) { - ch.sendImmediately = ch.sendOrEnqueue = ch.sendMessage = - invalidOp(msg, stack); + ch.sendImmediately = ch.sendOrEnqueue = ch.sendMessage = invalidOp(msg, stack); } // Move to entirely closed state. -C.toClosed = function(capturedStack) { +C.toClosed = function (capturedStack) { this._rejectPending(); - invalidateSend(this, 'Channel closed', capturedStack); - this.accept = invalidOp('Channel closed', capturedStack); + invalidateSend(this, "Channel closed", capturedStack); + this.accept = invalidOp("Channel closed", capturedStack); this.connection.releaseChannel(this.ch); - this.emit('close'); + this.emit("close"); }; // Stop being able to send and receive methods and content. Used when // we close the channel. Invokes the continuation once the server has // acknowledged the close, but before the channel is moved to the // closed state. -C.toClosing = function(capturedStack, k) { +C.toClosing = function (capturedStack, k) { var send = this.sendImmediately.bind(this); - invalidateSend(this, 'Channel closing', capturedStack); + invalidateSend(this, "Channel closing", capturedStack); - this.accept = function(f) { + this.accept = function (f) { if (f.id === defs.ChannelCloseOk) { if (k) k(); - var s = stackCapture('ChannelCloseOk frame received'); + var s = stackCapture("ChannelCloseOk frame received"); this.toClosed(s); - } - else if (f.id === defs.ChannelClose) { + } else if (f.id === defs.ChannelClose) { send(defs.ChannelCloseOk, {}); } // else ignore frame }; }; -C._rejectPending = function() { +C._rejectPending = function () { function rej(r) { r(new Error("Channel ended, no reply will be forthcoming")); } @@ -204,33 +195,34 @@ C._rejectPending = function() { this.reply = null; var discard; - while (discard = this.pending.shift()) rej(discard.reply); + while ((discard = this.pending.shift())) rej(discard.reply); this.pending = null; // so pushes will break }; -C.closeBecause = function(reason, code, k) { +C.closeBecause = function (reason, code, k) { this.sendImmediately(defs.ChannelClose, { replyText: reason, replyCode: code, - methodId:0, classId: 0 + methodId: 0, + classId: 0, }); - var s = stackCapture('closeBecause called: ' + reason); + var s = stackCapture("closeBecause called: " + reason); this.toClosing(s, k); }; // If we close because there's been an error, we need to distinguish // between what we tell the server (`reason`) and what we report as // the cause in the client (`error`). -C.closeWithError = function(id, reason, code, error) { +C.closeWithError = function (id, reason, code, error) { var self = this; - this.closeBecause(reason, code, function() { + this.closeBecause(reason, code, function () { error.code = code; // content frames and consumer errors do not provide a method a class/method ID if (id) { error.classId = defs.info(id).classId; error.methodId = defs.info(id).methodId; } - self.emit('error', error); + self.emit("error", error); }); }; @@ -242,23 +234,16 @@ C.closeWithError = function(id, reason, code, error) { // Keep the try/catch localised, in an attempt to avoid disabling // optimisation -C.acceptMessageFrame = function(f) { +C.acceptMessageFrame = function (f) { try { this.handleMessage = this.handleMessage(f); - } - catch (msg) { - if (typeof msg === 'string') { - this.closeWithError(f.id, msg, defs.constants.UNEXPECTED_FRAME, - new Error(msg)); - } - else if (msg instanceof Error) { - this.closeWithError(f.id, 'Error while processing message', - defs.constants.INTERNAL_ERROR, msg); - } - else { - this.closeWithError(f.id, 'Internal error while processing message', - defs.constants.INTERNAL_ERROR, - new Error(msg.toString())); + } catch (msg) { + if (typeof msg === "string") { + this.closeWithError(f.id, msg, defs.constants.UNEXPECTED_FRAME, new Error(msg)); + } else if (msg instanceof Error) { + this.closeWithError(f.id, "Error while processing message", defs.constants.INTERNAL_ERROR, msg); + } else { + this.closeWithError(f.id, "Internal error while processing message", defs.constants.INTERNAL_ERROR, new Error(msg.toString())); } } }; @@ -267,14 +252,13 @@ C.acceptMessageFrame = function(f) { // frame (BasicGet uses the RPC mechanism) function acceptDeliveryOrReturn(f) { var event; - if (f.id === defs.BasicDeliver) event = 'delivery'; - else if (f.id === defs.BasicReturn) event = 'return'; - else throw fmt("Expected BasicDeliver or BasicReturn; got %s", - inspect(f)); + if (f.id === defs.BasicDeliver) event = "delivery"; + else if (f.id === defs.BasicReturn) event = "return"; + else throw fmt("Expected BasicDeliver or BasicReturn; got %s", inspect(f)); var self = this; var fields = f.fields; - return acceptMessage(function(message) { + return acceptMessage(function (message) { message.fields = fields; self.emit(event, message); }); @@ -283,13 +267,14 @@ function acceptDeliveryOrReturn(f) { // Move to the state of waiting for message frames (headers, then // one or more content frames) function acceptMessage(continuation) { - var totalSize = 0, remaining = 0; + var totalSize = 0, + remaining = 0; var buffers = null; var message = { fields: null, properties: null, - content: null + content: null, }; return headers; @@ -305,12 +290,10 @@ function acceptMessage(continuation) { message.content = Buffer.alloc(0); continuation(message); return acceptDeliveryOrReturn; - } - else { + } else { return content; } - } - else { + } else { throw "Expected headers frame after delivery"; } } @@ -325,30 +308,23 @@ function acceptMessage(continuation) { if (buffers !== null) { buffers.push(f.content); message.content = Buffer.concat(buffers); - } - else { + } else { message.content = f.content; } continuation(message); return acceptDeliveryOrReturn; - } - else if (remaining < 0) { - throw fmt("Too much content sent! Expected %d bytes", - totalSize); - } - else { - if (buffers !== null) - buffers.push(f.content); - else - buffers = [f.content]; + } else if (remaining < 0) { + throw fmt("Too much content sent! Expected %d bytes", totalSize); + } else { + if (buffers !== null) buffers.push(f.content); + else buffers = [f.content]; return content; } - } - else throw "Expected content frame after headers" + } else throw "Expected content frame after headers"; } } -C.handleConfirm = function(handle, f) { +C.handleConfirm = function (handle, f) { var tag = f.deliveryTag; var multi = f.multiple; @@ -356,8 +332,7 @@ C.handleConfirm = function(handle, f) { var confirmed = this.unconfirmed.splice(0, tag - this.lwm + 1); this.lwm = tag + 1; confirmed.forEach(handle); - } - else { + } else { var c; if (tag === this.lwm) { c = this.unconfirmed.shift(); @@ -368,8 +343,7 @@ C.handleConfirm = function(handle, f) { this.unconfirmed.shift(); this.lwm++; } - } - else { + } else { c = this.unconfirmed[tag - this.lwm]; this.unconfirmed[tag - this.lwm] = null; } @@ -379,7 +353,7 @@ C.handleConfirm = function(handle, f) { } }; -C.pushConfirmCallback = function(cb) { +C.pushConfirmCallback = function (cb) { // `null` is used specifically for marking already confirmed slots, // so I coerce `undefined` and `null` to false; functions are never // falsey. @@ -388,79 +362,77 @@ C.pushConfirmCallback = function(cb) { // Interface for connection to use -C.accept = function(f) { - +C.accept = function (f) { switch (f.id) { - // Message frames - case undefined: // content frame! - case defs.BasicDeliver: - case defs.BasicReturn: - case defs.BasicProperties: - return this.acceptMessageFrame(f); + case undefined: // content frame! + case defs.BasicDeliver: + case defs.BasicReturn: + case defs.BasicProperties: + return this.acceptMessageFrame(f); // confirmations, need to do confirm.select first - case defs.BasicAck: - return this.emit('ack', f.fields); - case defs.BasicNack: - return this.emit('nack', f.fields); - case defs.BasicCancel: - // The broker can send this if e.g., the queue is deleted. - return this.emit('cancel', f.fields); - - case defs.ChannelClose: - // Any remote closure is an error to us. Reject the pending reply - // with the close frame, so it can see whether it was that - // operation that caused it to close. - if (this.reply) { - var reply = this.reply; this.reply = null; - reply(f); - } - var emsg = "Channel closed by server: " + closeMsg(f); - this.sendImmediately(defs.ChannelCloseOk, {}); - - var error = new Error(emsg); - error.code = f.fields.replyCode; - error.classId = f.fields.classId; - error.methodId = f.fields.methodId; - this.emit('error', error); - - var s = stackCapture(emsg); - this.toClosed(s); - return; - - case defs.BasicFlow: - // RabbitMQ doesn't send this, it just blocks the TCP socket - return this.closeWithError(f.id, "Flow not implemented", - defs.constants.NOT_IMPLEMENTED, - new Error('Flow not implemented')); - - default: // assume all other things are replies - // Resolving the reply may lead to another RPC; to make sure we - // don't hold that up, clear this.reply - var reply = this.reply; this.reply = null; - // however, maybe there's an RPC waiting to go? If so, that'll - // fill this.reply again, restoring the invariant. This does rely - // on any response being recv'ed after resolving the promise, - // below; hence, I use synchronous defer. - if (this.pending.length > 0) { - var send = this.pending.shift(); - this.reply = send.reply; - this.sendImmediately(send.method, send.fields); - } - return reply(null, f); + case defs.BasicAck: + return this.emit("ack", f.fields); + case defs.BasicNack: + return this.emit("nack", f.fields); + case defs.BasicCancel: + // The broker can send this if e.g., the queue is deleted. + return this.emit("cancel", f.fields); + + case defs.ChannelClose: + // Any remote closure is an error to us. Reject the pending reply + // with the close frame, so it can see whether it was that + // operation that caused it to close. + if (this.reply) { + var reply = this.reply; + this.reply = null; + reply(f); + } + var emsg = "Channel closed by server: " + closeMsg(f); + this.sendImmediately(defs.ChannelCloseOk, {}); + + var error = new Error(emsg); + error.code = f.fields.replyCode; + error.classId = f.fields.classId; + error.methodId = f.fields.methodId; + this.emit("error", error); + + var s = stackCapture(emsg); + this.toClosed(s); + return; + + case defs.BasicFlow: + // RabbitMQ doesn't send this, it just blocks the TCP socket + return this.closeWithError(f.id, "Flow not implemented", defs.constants.NOT_IMPLEMENTED, new Error("Flow not implemented")); + + default: + // assume all other things are replies + // Resolving the reply may lead to another RPC; to make sure we + // don't hold that up, clear this.reply + var reply = this.reply; + this.reply = null; + // however, maybe there's an RPC waiting to go? If so, that'll + // fill this.reply again, restoring the invariant. This does rely + // on any response being recv'ed after resolving the promise, + // below; hence, I use synchronous defer. + if (this.pending.length > 0) { + var send = this.pending.shift(); + this.reply = send.reply; + this.sendImmediately(send.method, send.fields); + } + return reply(null, f); } }; -C.onBufferDrain = function() { - this.emit('drain'); +C.onBufferDrain = function () { + this.emit("drain"); }; - // This adds just a bit more stuff useful for the APIs, but not // low-level machinery. -function BaseChannel(connection) { - Channel.call(this, connection); +function BaseChannel(connection, options) { + Channel.call(this, connection, options); this.consumers = {}; } inherits(BaseChannel, Channel); @@ -469,30 +441,29 @@ module.exports.BaseChannel = BaseChannel; // Not sure I like the ff, it's going to be changing hidden classes // all over the place. On the other hand, whaddya do. -BaseChannel.prototype.registerConsumer = function(tag, callback) { +BaseChannel.prototype.registerConsumer = function (tag, callback) { this.consumers[tag] = callback; }; -BaseChannel.prototype.unregisterConsumer = function(tag) { +BaseChannel.prototype.unregisterConsumer = function (tag) { delete this.consumers[tag]; }; -BaseChannel.prototype.dispatchMessage = function(fields, message) { +BaseChannel.prototype.dispatchMessage = function (fields, message) { var consumerTag = fields.consumerTag; var consumer = this.consumers[consumerTag]; if (consumer) { return consumer(message); - } - else { + } else { // %%% Surely a race here throw new Error("Unknown consumer: " + consumerTag); } }; -BaseChannel.prototype.handleDelivery = function(message) { +BaseChannel.prototype.handleDelivery = function (message) { return this.dispatchMessage(message.fields, message); }; -BaseChannel.prototype.handleCancel = function(fields) { +BaseChannel.prototype.handleCancel = function (fields) { return this.dispatchMessage(fields, null); }; diff --git a/lib/channel_model.js b/lib/channel_model.js index 2097fd14..79403ffc 100644 --- a/lib/channel_model.js +++ b/lib/channel_model.js @@ -2,23 +2,22 @@ // // -'use strict'; - -var defs = require('./defs'); -var Promise = require('bluebird'); -var inherits = require('util').inherits; -var EventEmitter = require('events').EventEmitter; -var BaseChannel = require('./channel').BaseChannel; -var acceptMessage = require('./channel').acceptMessage; -var Args = require('./api_args'); - -function ChannelModel(connection) { - if (!(this instanceof ChannelModel)) - return new ChannelModel(connection); - EventEmitter.call( this ); +"use strict"; + +var defs = require("./defs"); +var inherits = require("util").inherits; +var EventEmitter = require("events").EventEmitter; +var BaseChannel = require("./channel").BaseChannel; +var acceptMessage = require("./channel").acceptMessage; +var Args = require("./api_args"); + +function ChannelModel(connection, options) { + if (!(this instanceof ChannelModel)) return new ChannelModel(connection); + EventEmitter.call(this); this.connection = connection; + this.Promise = (options && options.Promise) || Promise; var self = this; - ['error', 'close', 'blocked', 'unblocked'].forEach(function(ev) { + ["error", "close", "blocked", "unblocked"].forEach(function (ev) { connection.on(ev, self.emit.bind(self, ev)); }); } @@ -28,24 +27,36 @@ module.exports.ChannelModel = ChannelModel; var CM = ChannelModel.prototype; -CM.close = function() { - return Promise.fromCallback(this.connection.close.bind(this.connection)); +CM.close = function () { + var close = this.connection.close.bind(this.connection); + return new this.Promise(function (resolve, reject) { + close(function (err, result) { + if (err) { + reject(err); + } else { + resolve(result); + } + }); + }); }; // Channels -function Channel(connection) { - BaseChannel.call(this, connection); - this.on('delivery', this.handleDelivery.bind(this)); - this.on('cancel', this.handleCancel.bind(this)); +function Channel(connection, options) { + BaseChannel.call(this, connection, options); + this.on("delivery", this.handleDelivery.bind(this)); + this.on("cancel", this.handleCancel.bind(this)); } inherits(Channel, BaseChannel); module.exports.Channel = Channel; -CM.createChannel = function() { - var c = new Channel(this.connection); - return c.open().then(function(openOk) { return c; }); +CM.createChannel = function () { + var options = { Promise: this.Promise }; + var c = new Channel(this.connection, options); + return c.open().then(function (openOk) { + return c; + }); }; var C = Channel.prototype; @@ -53,197 +64,191 @@ var C = Channel.prototype; // An RPC that returns a 'proper' promise, which resolves to just the // response's fields; this is intended to be suitable for implementing // API procedures. -C.rpc = function(method, fields, expect) { +C.rpc = function (method, fields, expect) { var self = this; - return Promise.fromCallback(function(cb) { - return self._rpc(method, fields, expect, cb); - }) - .then(function(f) { + return new this.Promise(function (resolve, reject) { + self._rpc(method, fields, expect, function (err, result) { + if (err) { + reject(err); + } else { + resolve(result); + } + }); + }).then(function (f) { return f.fields; }); }; // Do the remarkably simple channel open handshake -C.open = function() { - return Promise.try(this.allocate.bind(this)).then( - function(ch) { - return ch.rpc(defs.ChannelOpen, {outOfBand: ""}, - defs.ChannelOpenOk); - }); +C.open = function () { + var allocate = this.allocate.bind(this); + return new this.Promise(function (resolve) { + resolve(allocate()); + }).then(function (ch) { + return ch.rpc(defs.ChannelOpen, { outOfBand: "" }, defs.ChannelOpenOk); + }); + // return Promise.try(this.allocate.bind(this)).then(function(ch) { + // return ch.rpc(defs.ChannelOpen, { outOfBand: '' }, defs.ChannelOpenOk) + // }) }; -C.close = function() { +C.close = function () { var self = this; - return Promise.fromCallback(function(cb) { - return self.closeBecause("Goodbye", defs.constants.REPLY_SUCCESS, - cb); + return new this.Promise(function (resolve, reject) { + self.closeBecause("Goodbye", defs.constants.REPLY_SUCCESS, function (err, result) { + if (err) { + reject(err); + } else { + resolve(result); + } + }); }); }; // === Public API, declaring queues and stuff === -C.assertQueue = function(queue, options) { - return this.rpc(defs.QueueDeclare, - Args.assertQueue(queue, options), - defs.QueueDeclareOk); +C.assertQueue = function (queue, options) { + return this.rpc(defs.QueueDeclare, Args.assertQueue(queue, options), defs.QueueDeclareOk); }; -C.checkQueue = function(queue) { - return this.rpc(defs.QueueDeclare, - Args.checkQueue(queue), - defs.QueueDeclareOk); +C.checkQueue = function (queue) { + return this.rpc(defs.QueueDeclare, Args.checkQueue(queue), defs.QueueDeclareOk); }; -C.deleteQueue = function(queue, options) { - return this.rpc(defs.QueueDelete, - Args.deleteQueue(queue, options), - defs.QueueDeleteOk); +C.deleteQueue = function (queue, options) { + return this.rpc(defs.QueueDelete, Args.deleteQueue(queue, options), defs.QueueDeleteOk); }; -C.purgeQueue = function(queue) { - return this.rpc(defs.QueuePurge, - Args.purgeQueue(queue), - defs.QueuePurgeOk); +C.purgeQueue = function (queue) { + return this.rpc(defs.QueuePurge, Args.purgeQueue(queue), defs.QueuePurgeOk); }; -C.bindQueue = function(queue, source, pattern, argt) { - return this.rpc(defs.QueueBind, - Args.bindQueue(queue, source, pattern, argt), - defs.QueueBindOk); +C.bindQueue = function (queue, source, pattern, argt) { + return this.rpc(defs.QueueBind, Args.bindQueue(queue, source, pattern, argt), defs.QueueBindOk); }; -C.unbindQueue = function(queue, source, pattern, argt) { - return this.rpc(defs.QueueUnbind, - Args.unbindQueue(queue, source, pattern, argt), - defs.QueueUnbindOk); +C.unbindQueue = function (queue, source, pattern, argt) { + return this.rpc(defs.QueueUnbind, Args.unbindQueue(queue, source, pattern, argt), defs.QueueUnbindOk); }; -C.assertExchange = function(exchange, type, options) { +C.assertExchange = function (exchange, type, options) { // The server reply is an empty set of fields, but it's convenient // to have the exchange name handed to the continuation. - return this.rpc(defs.ExchangeDeclare, - Args.assertExchange(exchange, type, options), - defs.ExchangeDeclareOk) - .then(function(_ok) { return { exchange: exchange }; }); + return this.rpc(defs.ExchangeDeclare, Args.assertExchange(exchange, type, options), defs.ExchangeDeclareOk).then(function (_ok) { + return { exchange: exchange }; + }); }; -C.checkExchange = function(exchange) { - return this.rpc(defs.ExchangeDeclare, - Args.checkExchange(exchange), - defs.ExchangeDeclareOk); +C.checkExchange = function (exchange) { + return this.rpc(defs.ExchangeDeclare, Args.checkExchange(exchange), defs.ExchangeDeclareOk); }; -C.deleteExchange = function(name, options) { - return this.rpc(defs.ExchangeDelete, - Args.deleteExchange(name, options), - defs.ExchangeDeleteOk); +C.deleteExchange = function (name, options) { + return this.rpc(defs.ExchangeDelete, Args.deleteExchange(name, options), defs.ExchangeDeleteOk); }; -C.bindExchange = function(dest, source, pattern, argt) { - return this.rpc(defs.ExchangeBind, - Args.bindExchange(dest, source, pattern, argt), - defs.ExchangeBindOk); +C.bindExchange = function (dest, source, pattern, argt) { + return this.rpc(defs.ExchangeBind, Args.bindExchange(dest, source, pattern, argt), defs.ExchangeBindOk); }; -C.unbindExchange = function(dest, source, pattern, argt) { - return this.rpc(defs.ExchangeUnbind, - Args.unbindExchange(dest, source, pattern, argt), - defs.ExchangeUnbindOk); +C.unbindExchange = function (dest, source, pattern, argt) { + return this.rpc(defs.ExchangeUnbind, Args.unbindExchange(dest, source, pattern, argt), defs.ExchangeUnbindOk); }; // Working with messages -C.publish = function(exchange, routingKey, content, options) { +C.publish = function (exchange, routingKey, content, options) { var fieldsAndProps = Args.publish(exchange, routingKey, options); return this.sendMessage(fieldsAndProps, fieldsAndProps, content); }; -C.sendToQueue = function(queue, content, options) { - return this.publish('', queue, content, options); +C.sendToQueue = function (queue, content, options) { + return this.publish("", queue, content, options); }; -C.consume = function(queue, callback, options) { +C.consume = function (queue, callback, options) { var self = this; // NB we want the callback to be run synchronously, so that we've // registered the consumerTag before any messages can arrive. var fields = Args.consume(queue, options); - return Promise.fromCallback(function(cb) { - self._rpc(defs.BasicConsume, fields, defs.BasicConsumeOk, cb); - }) - .then(function(ok) { - self.registerConsumer(ok.fields.consumerTag, callback); - return ok.fields; + return new this.Promise(function (resolve, reject) { + self._rpc(defs.BasicConsume, fields, defs.BasicConsumeOk, function (err, result) { + if (err) { + reject(err); + } else { + self.registerConsumer(result.fields.consumerTag, callback); + resolve(result.fields); + } + }); }); }; -C.cancel = function(consumerTag) { +C.cancel = function (consumerTag) { var self = this; - return Promise.fromCallback(function(cb) { - self._rpc(defs.BasicCancel, Args.cancel(consumerTag), - defs.BasicCancelOk, - cb); - }) - .then(function(ok) { + return new this.Promise(function (resolve, reject) { + self._rpc(defs.BasicCancel, Args.cancel(consumerTag), defs.BasicCancelOk, function (err, result) { + if (err) { + reject(err); + } else { + resolve(result); + } + }); + }).then(function (ok) { self.unregisterConsumer(consumerTag); return ok.fields; }); }; -C.get = function(queue, options) { +C.get = function (queue, options) { var self = this; var fields = Args.get(queue, options); - return Promise.fromCallback(function(cb) { - return self.sendOrEnqueue(defs.BasicGet, fields, cb); - }) - .then(function(f) { + return new this.Promise(function (resolve, reject) { + self.sendOrEnqueue(defs.BasicGet, fields, function (err, result) { + if (err) { + reject(err); + } else { + resolve(result); + } + }); + }).then(function (f) { if (f.id === defs.BasicGetEmpty) { return false; - } - else if (f.id === defs.BasicGetOk) { + } else if (f.id === defs.BasicGetOk) { var fields = f.fields; - return new Promise(function(resolve) { - self.handleMessage = acceptMessage(function(m) { + return new this.Promise(function (resolve) { + self.handleMessage = acceptMessage(function (m) { m.fields = fields; resolve(m); }); }); + } else { + throw new Error("Unexpected response to BasicGet: " + inspect(f)); } - else { - throw new Error("Unexpected response to BasicGet: " + - inspect(f)); - } - }) + }); }; -C.ack = function(message, allUpTo) { - this.sendImmediately( - defs.BasicAck, - Args.ack(message.fields.deliveryTag, allUpTo)); +C.ack = function (message, allUpTo) { + this.sendImmediately(defs.BasicAck, Args.ack(message.fields.deliveryTag, allUpTo)); }; -C.ackAll = function() { +C.ackAll = function () { this.sendImmediately(defs.BasicAck, Args.ack(0, true)); }; -C.nack = function(message, allUpTo, requeue) { - this.sendImmediately( - defs.BasicNack, - Args.nack(message.fields.deliveryTag, allUpTo, requeue)); +C.nack = function (message, allUpTo, requeue) { + this.sendImmediately(defs.BasicNack, Args.nack(message.fields.deliveryTag, allUpTo, requeue)); }; -C.nackAll = function(requeue) { - this.sendImmediately(defs.BasicNack, - Args.nack(0, true, requeue)); +C.nackAll = function (requeue) { + this.sendImmediately(defs.BasicNack, Args.nack(0, true, requeue)); }; // `Basic.Nack` is not available in older RabbitMQ versions (or in the // AMQP specification), so you have to use the one-at-a-time // `Basic.Reject`. This is otherwise synonymous with // `#nack(message, false, requeue)`. -C.reject = function(message, requeue) { - this.sendImmediately( - defs.BasicReject, - Args.reject(message.fields.deliveryTag, requeue)); +C.reject = function (message, requeue) { + this.sendImmediately(defs.BasicReject, Args.reject(message.fields.deliveryTag, requeue)); }; // There are more options in AMQP than exposed here; RabbitMQ only @@ -251,16 +256,12 @@ C.reject = function(message, requeue) { // channels or consumers. RabbitMQ v3.3.0 and after treat prefetch // (without `global` set) as per-consumer (for consumers following), // and prefetch with `global` set as per-channel. -C.prefetch = C.qos = function(count, global) { - return this.rpc(defs.BasicQos, - Args.prefetch(count, global), - defs.BasicQosOk); +C.prefetch = C.qos = function (count, global) { + return this.rpc(defs.BasicQos, Args.prefetch(count, global), defs.BasicQosOk); }; -C.recover = function() { - return this.rpc(defs.BasicRecover, - Args.recover(), - defs.BasicRecoverOk); +C.recover = function () { + return this.rpc(defs.BasicRecover, Args.recover(), defs.BasicRecoverOk); }; // Confirm channel. This is a channel with confirms 'switched on', @@ -277,35 +278,38 @@ inherits(ConfirmChannel, Channel); module.exports.ConfirmChannel = ConfirmChannel; -CM.createConfirmChannel = function() { +CM.createConfirmChannel = function () { var c = new ConfirmChannel(this.connection); - return c.open() - .then(function(openOk) { - return c.rpc(defs.ConfirmSelect, {nowait: false}, - defs.ConfirmSelectOk) + return c + .open() + .then(function (openOk) { + return c.rpc(defs.ConfirmSelect, { nowait: false }, defs.ConfirmSelectOk); }) - .then(function() { return c; }); + .then(function () { + return c; + }); }; var CC = ConfirmChannel.prototype; -CC.publish = function(exchange, routingKey, content, options, cb) { +CC.publish = function (exchange, routingKey, content, options, cb) { this.pushConfirmCallback(cb); return C.publish.call(this, exchange, routingKey, content, options); }; -CC.sendToQueue = function(queue, content, options, cb) { - return this.publish('', queue, content, options, cb); +CC.sendToQueue = function (queue, content, options, cb) { + return this.publish("", queue, content, options, cb); }; -CC.waitForConfirms = function() { +CC.waitForConfirms = function () { var awaiting = []; var unconfirmed = this.unconfirmed; - unconfirmed.forEach(function(val, index) { - if (val === null); // already confirmed + unconfirmed.forEach(function (val, index) { + if (val === null); else { - var confirmed = new Promise(function(resolve, reject) { - unconfirmed[index] = function(err) { + // already confirmed + var confirmed = new this.Promise(function (resolve, reject) { + unconfirmed[index] = function (err) { if (val) val(err); if (err === null) resolve(); else reject(err); @@ -314,5 +318,5 @@ CC.waitForConfirms = function() { awaiting.push(confirmed); } }); - return Promise.all(awaiting); + return this.Promise.all(awaiting); }; diff --git a/package.json b/package.json index 7400703d..67fedad6 100644 --- a/package.json +++ b/package.json @@ -1,29 +1,27 @@ { - "name": "amqplib", + "name": "@worthaboutapig/amqplib", "homepage": "http://squaremo.github.io/amqp.node/", "main": "./channel_api.js", - "version": "0.6.0", + "version": "0.6.6", "description": "An AMQP 0-9-1 (e.g., RabbitMQ) library and client.", "repository": { "type": "git", "url": "https://github.com/squaremo/amqp.node.git" }, - "engines": { - "node": ">=0.8 <=14" - }, "dependencies": { "bitsyntax": "~0.1.0", - "bluebird": "^3.5.2", "buffer-more-ints": "~1.0.0", - "readable-stream": "1.x >=1.1.9", - "safe-buffer": "~5.1.2", - "url-parse": "~1.4.3" + "readable-stream": "~3.6.0", + "safe-buffer": "~5.2.1", + "url-parse": "~1.4.7" }, "devDependencies": { + "bluebird": "^3.7.2", "claire": "0.4.1", - "istanbul": "0.1.x", - "mocha": "^3.5.3", - "uglify-js": "2.6.x" + "istanbul": "0.4.5", + "mocha": "^8.4.0", + "nyc": "^15.1.0", + "uglify-js": "^2.8.29" }, "scripts": { "test": "make test", @@ -35,5 +33,6 @@ "RabbitMQ" ], "author": "Michael Bridgen ", - "license": "MIT" + "license": "MIT", + "typings": "./amqplib.d.ts" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 00000000..81fb8bb4 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,1806 @@ +lockfileVersion: 5.3 + +specifiers: + bitsyntax: ~0.1.0 + bluebird: ^3.7.2 + buffer-more-ints: ~1.0.0 + claire: 0.4.1 + istanbul: 0.4.5 + mocha: ^8.4.0 + nyc: ^15.1.0 + readable-stream: ~3.6.0 + safe-buffer: ~5.2.1 + uglify-js: ^2.8.29 + url-parse: ~1.4.7 + +dependencies: + bitsyntax: 0.1.0 + buffer-more-ints: 1.0.0 + readable-stream: 3.6.0 + safe-buffer: 5.2.1 + url-parse: 1.4.7 + +devDependencies: + bluebird: 3.7.2 + claire: 0.4.1 + istanbul: 0.4.5 + mocha: 8.4.0 + nyc: 15.1.0 + uglify-js: 2.8.29 + +packages: + + /@babel/code-frame/7.16.7: + resolution: {integrity: sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/highlight': 7.16.7 + dev: true + + /@babel/compat-data/7.16.8: + resolution: {integrity: sha512-m7OkX0IdKLKPpBlJtF561YJal5y/jyI5fNfWbPxh2D/nbzzGI4qRyrD8xO2jB24u7l+5I2a43scCG2IrfjC50Q==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/core/7.16.7: + resolution: {integrity: sha512-aeLaqcqThRNZYmbMqtulsetOQZ/5gbR/dWruUCJcpas4Qoyy+QeagfDsPdMrqwsPRDNxJvBlRiZxxX7THO7qtA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.16.7 + '@babel/generator': 7.16.8 + '@babel/helper-compilation-targets': 7.16.7_@babel+core@7.16.7 + '@babel/helper-module-transforms': 7.16.7 + '@babel/helpers': 7.16.7 + '@babel/parser': 7.16.8 + '@babel/template': 7.16.7 + '@babel/traverse': 7.16.8 + '@babel/types': 7.16.8 + convert-source-map: 1.8.0 + debug: 4.3.3 + gensync: 1.0.0-beta.2 + json5: 2.2.0 + semver: 6.3.0 + source-map: 0.5.7 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/generator/7.16.8: + resolution: {integrity: sha512-1ojZwE9+lOXzcWdWmO6TbUzDfqLD39CmEhN8+2cX9XkDo5yW1OpgfejfliysR2AWLpMamTiOiAp/mtroaymhpw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.16.8 + jsesc: 2.5.2 + source-map: 0.5.7 + dev: true + + /@babel/helper-compilation-targets/7.16.7_@babel+core@7.16.7: + resolution: {integrity: sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/compat-data': 7.16.8 + '@babel/core': 7.16.7 + '@babel/helper-validator-option': 7.16.7 + browserslist: 4.19.1 + semver: 6.3.0 + dev: true + + /@babel/helper-environment-visitor/7.16.7: + resolution: {integrity: sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.16.8 + dev: true + + /@babel/helper-function-name/7.16.7: + resolution: {integrity: sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-get-function-arity': 7.16.7 + '@babel/template': 7.16.7 + '@babel/types': 7.16.8 + dev: true + + /@babel/helper-get-function-arity/7.16.7: + resolution: {integrity: sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.16.8 + dev: true + + /@babel/helper-hoist-variables/7.16.7: + resolution: {integrity: sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.16.8 + dev: true + + /@babel/helper-module-imports/7.16.7: + resolution: {integrity: sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.16.8 + dev: true + + /@babel/helper-module-transforms/7.16.7: + resolution: {integrity: sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-environment-visitor': 7.16.7 + '@babel/helper-module-imports': 7.16.7 + '@babel/helper-simple-access': 7.16.7 + '@babel/helper-split-export-declaration': 7.16.7 + '@babel/helper-validator-identifier': 7.16.7 + '@babel/template': 7.16.7 + '@babel/traverse': 7.16.8 + '@babel/types': 7.16.8 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/helper-simple-access/7.16.7: + resolution: {integrity: sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.16.8 + dev: true + + /@babel/helper-split-export-declaration/7.16.7: + resolution: {integrity: sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.16.8 + dev: true + + /@babel/helper-validator-identifier/7.16.7: + resolution: {integrity: sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-validator-option/7.16.7: + resolution: {integrity: sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helpers/7.16.7: + resolution: {integrity: sha512-9ZDoqtfY7AuEOt3cxchfii6C7GDyyMBffktR5B2jvWv8u2+efwvpnVKXMWzNehqy68tKgAfSwfdw/lWpthS2bw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.16.7 + '@babel/traverse': 7.16.8 + '@babel/types': 7.16.8 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/highlight/7.16.7: + resolution: {integrity: sha512-aKpPMfLvGO3Q97V0qhw/V2SWNWlwfJknuwAunU7wZLSfrM4xTBvg7E5opUVi1kJTBKihE38CPg4nBiqX83PWYw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-validator-identifier': 7.16.7 + chalk: 2.4.2 + js-tokens: 4.0.0 + dev: true + + /@babel/parser/7.16.8: + resolution: {integrity: sha512-i7jDUfrVBWc+7OKcBzEe5n7fbv3i2fWtxKzzCvOjnzSxMfWMigAhtfJ7qzZNGFNMsCCd67+uz553dYKWXPvCKw==} + engines: {node: '>=6.0.0'} + hasBin: true + dev: true + + /@babel/template/7.16.7: + resolution: {integrity: sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.16.7 + '@babel/parser': 7.16.8 + '@babel/types': 7.16.8 + dev: true + + /@babel/traverse/7.16.8: + resolution: {integrity: sha512-xe+H7JlvKsDQwXRsBhSnq1/+9c+LlQcCK3Tn/l5sbx02HYns/cn7ibp9+RV1sIUqu7hKg91NWsgHurO9dowITQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.16.7 + '@babel/generator': 7.16.8 + '@babel/helper-environment-visitor': 7.16.7 + '@babel/helper-function-name': 7.16.7 + '@babel/helper-hoist-variables': 7.16.7 + '@babel/helper-split-export-declaration': 7.16.7 + '@babel/parser': 7.16.8 + '@babel/types': 7.16.8 + debug: 4.3.3 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/types/7.16.8: + resolution: {integrity: sha512-smN2DQc5s4M7fntyjGtyIPbRJv6wW4rU/94fmYJ7PKQuZkC0qGMHXJbg6sNGt12JmVr4k5YaptI/XtiLJBnmIg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-validator-identifier': 7.16.7 + to-fast-properties: 2.0.0 + dev: true + + /@istanbuljs/load-nyc-config/1.1.0: + resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} + engines: {node: '>=8'} + dependencies: + camelcase: 5.3.1 + find-up: 4.1.0 + get-package-type: 0.1.0 + js-yaml: 3.14.1 + resolve-from: 5.0.0 + dev: true + + /@istanbuljs/schema/0.1.3: + resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} + engines: {node: '>=8'} + dev: true + + /@ungap/promise-all-settled/1.1.2: + resolution: {integrity: sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==} + dev: true + + /abbrev/1.0.9: + resolution: {integrity: sha1-kbR5JYinc4wl813W9jdSovh3YTU=} + dev: true + + /aggregate-error/3.1.0: + resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} + engines: {node: '>=8'} + dependencies: + clean-stack: 2.2.0 + indent-string: 4.0.0 + dev: true + + /align-text/0.1.4: + resolution: {integrity: sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=} + engines: {node: '>=0.10.0'} + dependencies: + kind-of: 3.2.2 + longest: 1.0.1 + repeat-string: 1.6.1 + dev: true + + /amdefine/1.0.1: + resolution: {integrity: sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=} + engines: {node: '>=0.4.2'} + dev: true + optional: true + + /ansi-colors/4.1.1: + resolution: {integrity: sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==} + engines: {node: '>=6'} + dev: true + + /ansi-regex/3.0.0: + resolution: {integrity: sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=} + engines: {node: '>=4'} + dev: true + + /ansi-regex/5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + dev: true + + /ansi-styles/3.2.1: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} + engines: {node: '>=4'} + dependencies: + color-convert: 1.9.3 + dev: true + + /ansi-styles/4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + dependencies: + color-convert: 2.0.1 + dev: true + + /anymatch/3.1.2: + resolution: {integrity: sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==} + engines: {node: '>= 8'} + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + dev: true + + /append-transform/2.0.0: + resolution: {integrity: sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==} + engines: {node: '>=8'} + dependencies: + default-require-extensions: 3.0.0 + dev: true + + /archy/1.0.0: + resolution: {integrity: sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=} + dev: true + + /argparse/1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + dependencies: + sprintf-js: 1.0.3 + dev: true + + /argparse/2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + dev: true + + /async/1.5.2: + resolution: {integrity: sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=} + dev: true + + /balanced-match/1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + dev: true + + /binary-extensions/2.2.0: + resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} + engines: {node: '>=8'} + dev: true + + /bitsyntax/0.1.0: + resolution: {integrity: sha512-ikAdCnrloKmFOugAfxWws89/fPc+nw0OOG1IzIE72uSOg/A3cYptKCjSUhDTuj7fhsJtzkzlv7l3b8PzRHLN0Q==} + engines: {node: '>=0.8'} + dependencies: + buffer-more-ints: 1.0.0 + debug: 2.6.9 + safe-buffer: 5.1.2 + dev: false + + /bluebird/3.7.2: + resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} + dev: true + + /boo/1.2.4: + resolution: {integrity: sha1-szMxw2xK552C9P0ORJBgTLfFE7U=} + dev: true + + /brace-expansion/1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + dev: true + + /braces/3.0.2: + resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} + engines: {node: '>=8'} + dependencies: + fill-range: 7.0.1 + dev: true + + /browser-stdout/1.3.1: + resolution: {integrity: sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==} + dev: true + + /browserslist/4.19.1: + resolution: {integrity: sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + dependencies: + caniuse-lite: 1.0.30001300 + electron-to-chromium: 1.4.47 + escalade: 3.1.1 + node-releases: 2.0.1 + picocolors: 1.0.0 + dev: true + + /buffer-more-ints/1.0.0: + resolution: {integrity: sha512-EMetuGFz5SLsT0QTnXzINh4Ksr+oo4i+UGTXEshiGCQWnsgSs7ZhJ8fzlwQ+OzEMs0MpDAMr1hxnblp5a4vcHg==} + dev: false + + /caching-transform/4.0.0: + resolution: {integrity: sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==} + engines: {node: '>=8'} + dependencies: + hasha: 5.2.2 + make-dir: 3.1.0 + package-hash: 4.0.0 + write-file-atomic: 3.0.3 + dev: true + + /camelcase/1.2.1: + resolution: {integrity: sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=} + engines: {node: '>=0.10.0'} + dev: true + + /camelcase/5.3.1: + resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} + engines: {node: '>=6'} + dev: true + + /camelcase/6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} + dev: true + + /caniuse-lite/1.0.30001300: + resolution: {integrity: sha512-cVjiJHWGcNlJi8TZVKNMnvMid3Z3TTdDHmLDzlOdIiZq138Exvo0G+G0wTdVYolxKb4AYwC+38pxodiInVtJSA==} + dev: true + + /center-align/0.1.3: + resolution: {integrity: sha1-qg0yYptu6XIgBBHL1EYckHvCt60=} + engines: {node: '>=0.10.0'} + dependencies: + align-text: 0.1.4 + lazy-cache: 1.0.4 + dev: true + + /chalk/2.4.2: + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} + engines: {node: '>=4'} + dependencies: + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 + dev: true + + /chalk/4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + dev: true + + /chokidar/3.5.1: + resolution: {integrity: sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==} + engines: {node: '>= 8.10.0'} + dependencies: + anymatch: 3.1.2 + braces: 3.0.2 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.5.0 + optionalDependencies: + fsevents: 2.3.2 + dev: true + + /claire/0.4.1: + resolution: {integrity: sha1-ynDcEmHd2PJaGvq604BcOfziY7w=} + dependencies: + boo: 1.2.4 + flaw: 0.1.0 + prelude-ls: 0.6.0 + dev: true + + /clean-stack/2.2.0: + resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} + engines: {node: '>=6'} + dev: true + + /cliui/2.1.0: + resolution: {integrity: sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=} + dependencies: + center-align: 0.1.3 + right-align: 0.1.3 + wordwrap: 0.0.2 + dev: true + + /cliui/6.0.0: + resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 6.2.0 + dev: true + + /cliui/7.0.4: + resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + dev: true + + /color-convert/1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + dependencies: + color-name: 1.1.3 + dev: true + + /color-convert/2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + dependencies: + color-name: 1.1.4 + dev: true + + /color-name/1.1.3: + resolution: {integrity: sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=} + dev: true + + /color-name/1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + dev: true + + /commondir/1.0.1: + resolution: {integrity: sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=} + dev: true + + /concat-map/0.0.1: + resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=} + dev: true + + /convert-source-map/1.8.0: + resolution: {integrity: sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==} + dependencies: + safe-buffer: 5.1.2 + dev: true + + /cross-spawn/7.0.3: + resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + engines: {node: '>= 8'} + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + dev: true + + /debug/2.6.9: + resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} + dependencies: + ms: 2.0.0 + dev: false + + /debug/4.3.1_supports-color@8.1.1: + resolution: {integrity: sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.2 + supports-color: 8.1.1 + dev: true + + /debug/4.3.3: + resolution: {integrity: sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.2 + dev: true + + /decamelize/1.2.0: + resolution: {integrity: sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=} + engines: {node: '>=0.10.0'} + dev: true + + /decamelize/4.0.0: + resolution: {integrity: sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==} + engines: {node: '>=10'} + dev: true + + /deep-is/0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + dev: true + + /default-require-extensions/3.0.0: + resolution: {integrity: sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg==} + engines: {node: '>=8'} + dependencies: + strip-bom: 4.0.0 + dev: true + + /diff/5.0.0: + resolution: {integrity: sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==} + engines: {node: '>=0.3.1'} + dev: true + + /electron-to-chromium/1.4.47: + resolution: {integrity: sha512-ZHc8i3/cgeCRK/vC7W2htAG6JqUmOUgDNn/f9yY9J8UjfLjwzwOVEt4MWmgJAdvmxyrsR5KIFA/6+kUHGY0eUA==} + dev: true + + /emoji-regex/8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + dev: true + + /es6-error/4.1.1: + resolution: {integrity: sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==} + dev: true + + /escalade/3.1.1: + resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} + engines: {node: '>=6'} + dev: true + + /escape-string-regexp/1.0.5: + resolution: {integrity: sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=} + engines: {node: '>=0.8.0'} + dev: true + + /escape-string-regexp/4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + dev: true + + /escodegen/1.8.1: + resolution: {integrity: sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg=} + engines: {node: '>=0.12.0'} + hasBin: true + dependencies: + esprima: 2.7.3 + estraverse: 1.9.3 + esutils: 2.0.3 + optionator: 0.8.3 + optionalDependencies: + source-map: 0.2.0 + dev: true + + /esprima/2.7.3: + resolution: {integrity: sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=} + engines: {node: '>=0.10.0'} + hasBin: true + dev: true + + /esprima/4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + dev: true + + /estraverse/1.9.3: + resolution: {integrity: sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q=} + engines: {node: '>=0.10.0'} + dev: true + + /esutils/2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + dev: true + + /fast-levenshtein/2.0.6: + resolution: {integrity: sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=} + dev: true + + /fill-range/7.0.1: + resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} + engines: {node: '>=8'} + dependencies: + to-regex-range: 5.0.1 + dev: true + + /find-cache-dir/3.3.2: + resolution: {integrity: sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==} + engines: {node: '>=8'} + dependencies: + commondir: 1.0.1 + make-dir: 3.1.0 + pkg-dir: 4.2.0 + dev: true + + /find-up/4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + dev: true + + /find-up/5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + dev: true + + /flat/5.0.2: + resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} + hasBin: true + dev: true + + /flaw/0.1.0: + resolution: {integrity: sha1-wMPo+BYWdTh+2tofbOhNZ5sCUn8=} + dev: true + + /foreground-child/2.0.0: + resolution: {integrity: sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==} + engines: {node: '>=8.0.0'} + dependencies: + cross-spawn: 7.0.3 + signal-exit: 3.0.6 + dev: true + + /fromentries/1.3.2: + resolution: {integrity: sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==} + dev: true + + /fs.realpath/1.0.0: + resolution: {integrity: sha1-FQStJSMVjKpA20onh8sBQRmU6k8=} + dev: true + + /fsevents/2.3.2: + resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /gensync/1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + dev: true + + /get-caller-file/2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + dev: true + + /get-package-type/0.1.0: + resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} + engines: {node: '>=8.0.0'} + dev: true + + /glob-parent/5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + dependencies: + is-glob: 4.0.3 + dev: true + + /glob/5.0.15: + resolution: {integrity: sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=} + dependencies: + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.0.4 + once: 1.4.0 + path-is-absolute: 1.0.1 + dev: true + + /glob/7.1.6: + resolution: {integrity: sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==} + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.0.4 + once: 1.4.0 + path-is-absolute: 1.0.1 + dev: true + + /glob/7.2.0: + resolution: {integrity: sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==} + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.0.4 + once: 1.4.0 + path-is-absolute: 1.0.1 + dev: true + + /globals/11.12.0: + resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} + engines: {node: '>=4'} + dev: true + + /graceful-fs/4.2.9: + resolution: {integrity: sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==} + dev: true + + /growl/1.10.5: + resolution: {integrity: sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==} + engines: {node: '>=4.x'} + dev: true + + /handlebars/4.7.7: + resolution: {integrity: sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==} + engines: {node: '>=0.4.7'} + hasBin: true + dependencies: + minimist: 1.2.5 + neo-async: 2.6.2 + source-map: 0.6.1 + wordwrap: 1.0.0 + optionalDependencies: + uglify-js: 3.14.5 + dev: true + + /has-flag/1.0.0: + resolution: {integrity: sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=} + engines: {node: '>=0.10.0'} + dev: true + + /has-flag/3.0.0: + resolution: {integrity: sha1-tdRU3CGZriJWmfNGfloH87lVuv0=} + engines: {node: '>=4'} + dev: true + + /has-flag/4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + dev: true + + /hasha/5.2.2: + resolution: {integrity: sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==} + engines: {node: '>=8'} + dependencies: + is-stream: 2.0.1 + type-fest: 0.8.1 + dev: true + + /he/1.2.0: + resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} + hasBin: true + dev: true + + /html-escaper/2.0.2: + resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + dev: true + + /imurmurhash/0.1.4: + resolution: {integrity: sha1-khi5srkoojixPcT7a21XbyMUU+o=} + engines: {node: '>=0.8.19'} + dev: true + + /indent-string/4.0.0: + resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} + engines: {node: '>=8'} + dev: true + + /inflight/1.0.6: + resolution: {integrity: sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=} + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + dev: true + + /inherits/2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + /is-binary-path/2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + dependencies: + binary-extensions: 2.2.0 + dev: true + + /is-buffer/1.1.6: + resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==} + dev: true + + /is-extglob/2.1.1: + resolution: {integrity: sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=} + engines: {node: '>=0.10.0'} + dev: true + + /is-fullwidth-code-point/2.0.0: + resolution: {integrity: sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=} + engines: {node: '>=4'} + dev: true + + /is-fullwidth-code-point/3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + dev: true + + /is-glob/4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + dependencies: + is-extglob: 2.1.1 + dev: true + + /is-number/7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + dev: true + + /is-plain-obj/2.1.0: + resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==} + engines: {node: '>=8'} + dev: true + + /is-stream/2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + dev: true + + /is-typedarray/1.0.0: + resolution: {integrity: sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=} + dev: true + + /is-windows/1.0.2: + resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} + engines: {node: '>=0.10.0'} + dev: true + + /isexe/2.0.0: + resolution: {integrity: sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=} + dev: true + + /istanbul-lib-coverage/3.2.0: + resolution: {integrity: sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==} + engines: {node: '>=8'} + dev: true + + /istanbul-lib-hook/3.0.0: + resolution: {integrity: sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==} + engines: {node: '>=8'} + dependencies: + append-transform: 2.0.0 + dev: true + + /istanbul-lib-instrument/4.0.3: + resolution: {integrity: sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==} + engines: {node: '>=8'} + dependencies: + '@babel/core': 7.16.7 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-coverage: 3.2.0 + semver: 6.3.0 + transitivePeerDependencies: + - supports-color + dev: true + + /istanbul-lib-processinfo/2.0.2: + resolution: {integrity: sha512-kOwpa7z9hme+IBPZMzQ5vdQj8srYgAtaRqeI48NGmAQ+/5yKiHLV0QbYqQpxsdEF0+w14SoB8YbnHKcXE2KnYw==} + engines: {node: '>=8'} + dependencies: + archy: 1.0.0 + cross-spawn: 7.0.3 + istanbul-lib-coverage: 3.2.0 + make-dir: 3.1.0 + p-map: 3.0.0 + rimraf: 3.0.2 + uuid: 3.4.0 + dev: true + + /istanbul-lib-report/3.0.0: + resolution: {integrity: sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==} + engines: {node: '>=8'} + dependencies: + istanbul-lib-coverage: 3.2.0 + make-dir: 3.1.0 + supports-color: 7.2.0 + dev: true + + /istanbul-lib-source-maps/4.0.1: + resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} + engines: {node: '>=10'} + dependencies: + debug: 4.3.3 + istanbul-lib-coverage: 3.2.0 + source-map: 0.6.1 + transitivePeerDependencies: + - supports-color + dev: true + + /istanbul-reports/3.1.3: + resolution: {integrity: sha512-x9LtDVtfm/t1GFiLl3NffC7hz+I1ragvgX1P/Lg1NlIagifZDKUkuuaAxH/qpwj2IuEfD8G2Bs/UKp+sZ/pKkg==} + engines: {node: '>=8'} + dependencies: + html-escaper: 2.0.2 + istanbul-lib-report: 3.0.0 + dev: true + + /istanbul/0.4.5: + resolution: {integrity: sha1-ZcfXPUxNqE1POsMQuRj7C4Azczs=} + deprecated: |- + This module is no longer maintained, try this instead: + npm i nyc + Visit https://istanbul.js.org/integrations for other alternatives. + hasBin: true + dependencies: + abbrev: 1.0.9 + async: 1.5.2 + escodegen: 1.8.1 + esprima: 2.7.3 + glob: 5.0.15 + handlebars: 4.7.7 + js-yaml: 3.14.1 + mkdirp: 0.5.5 + nopt: 3.0.6 + once: 1.4.0 + resolve: 1.1.7 + supports-color: 3.2.3 + which: 1.3.1 + wordwrap: 1.0.0 + dev: true + + /js-tokens/4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + dev: true + + /js-yaml/3.14.1: + resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} + hasBin: true + dependencies: + argparse: 1.0.10 + esprima: 4.0.1 + dev: true + + /js-yaml/4.0.0: + resolution: {integrity: sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==} + hasBin: true + dependencies: + argparse: 2.0.1 + dev: true + + /jsesc/2.5.2: + resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} + engines: {node: '>=4'} + hasBin: true + dev: true + + /json5/2.2.0: + resolution: {integrity: sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==} + engines: {node: '>=6'} + hasBin: true + dependencies: + minimist: 1.2.5 + dev: true + + /kind-of/3.2.2: + resolution: {integrity: sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=} + engines: {node: '>=0.10.0'} + dependencies: + is-buffer: 1.1.6 + dev: true + + /lazy-cache/1.0.4: + resolution: {integrity: sha1-odePw6UEdMuAhF07O24dpJpEbo4=} + engines: {node: '>=0.10.0'} + dev: true + + /levn/0.3.0: + resolution: {integrity: sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=} + engines: {node: '>= 0.8.0'} + dependencies: + prelude-ls: 1.1.2 + type-check: 0.3.2 + dev: true + + /locate-path/5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + dependencies: + p-locate: 4.1.0 + dev: true + + /locate-path/6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + dependencies: + p-locate: 5.0.0 + dev: true + + /lodash.flattendeep/4.4.0: + resolution: {integrity: sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=} + dev: true + + /log-symbols/4.0.0: + resolution: {integrity: sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==} + engines: {node: '>=10'} + dependencies: + chalk: 4.1.2 + dev: true + + /longest/1.0.1: + resolution: {integrity: sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=} + engines: {node: '>=0.10.0'} + dev: true + + /make-dir/3.1.0: + resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} + engines: {node: '>=8'} + dependencies: + semver: 6.3.0 + dev: true + + /minimatch/3.0.4: + resolution: {integrity: sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==} + dependencies: + brace-expansion: 1.1.11 + dev: true + + /minimist/1.2.5: + resolution: {integrity: sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==} + dev: true + + /mkdirp/0.5.5: + resolution: {integrity: sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==} + hasBin: true + dependencies: + minimist: 1.2.5 + dev: true + + /mocha/8.4.0: + resolution: {integrity: sha512-hJaO0mwDXmZS4ghXsvPVriOhsxQ7ofcpQdm8dE+jISUOKopitvnXFQmpRR7jd2K6VBG6E26gU3IAbXXGIbu4sQ==} + engines: {node: '>= 10.12.0'} + hasBin: true + dependencies: + '@ungap/promise-all-settled': 1.1.2 + ansi-colors: 4.1.1 + browser-stdout: 1.3.1 + chokidar: 3.5.1 + debug: 4.3.1_supports-color@8.1.1 + diff: 5.0.0 + escape-string-regexp: 4.0.0 + find-up: 5.0.0 + glob: 7.1.6 + growl: 1.10.5 + he: 1.2.0 + js-yaml: 4.0.0 + log-symbols: 4.0.0 + minimatch: 3.0.4 + ms: 2.1.3 + nanoid: 3.1.20 + serialize-javascript: 5.0.1 + strip-json-comments: 3.1.1 + supports-color: 8.1.1 + which: 2.0.2 + wide-align: 1.1.3 + workerpool: 6.1.0 + yargs: 16.2.0 + yargs-parser: 20.2.4 + yargs-unparser: 2.0.0 + dev: true + + /ms/2.0.0: + resolution: {integrity: sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=} + dev: false + + /ms/2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + dev: true + + /ms/2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + dev: true + + /nanoid/3.1.20: + resolution: {integrity: sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + dev: true + + /neo-async/2.6.2: + resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + dev: true + + /node-preload/0.2.1: + resolution: {integrity: sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==} + engines: {node: '>=8'} + dependencies: + process-on-spawn: 1.0.0 + dev: true + + /node-releases/2.0.1: + resolution: {integrity: sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==} + dev: true + + /nopt/3.0.6: + resolution: {integrity: sha1-xkZdvwirzU2zWTF/eaxopkayj/k=} + hasBin: true + dependencies: + abbrev: 1.0.9 + dev: true + + /normalize-path/3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + dev: true + + /nyc/15.1.0: + resolution: {integrity: sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==} + engines: {node: '>=8.9'} + hasBin: true + dependencies: + '@istanbuljs/load-nyc-config': 1.1.0 + '@istanbuljs/schema': 0.1.3 + caching-transform: 4.0.0 + convert-source-map: 1.8.0 + decamelize: 1.2.0 + find-cache-dir: 3.3.2 + find-up: 4.1.0 + foreground-child: 2.0.0 + get-package-type: 0.1.0 + glob: 7.2.0 + istanbul-lib-coverage: 3.2.0 + istanbul-lib-hook: 3.0.0 + istanbul-lib-instrument: 4.0.3 + istanbul-lib-processinfo: 2.0.2 + istanbul-lib-report: 3.0.0 + istanbul-lib-source-maps: 4.0.1 + istanbul-reports: 3.1.3 + make-dir: 3.1.0 + node-preload: 0.2.1 + p-map: 3.0.0 + process-on-spawn: 1.0.0 + resolve-from: 5.0.0 + rimraf: 3.0.2 + signal-exit: 3.0.6 + spawn-wrap: 2.0.0 + test-exclude: 6.0.0 + yargs: 15.4.1 + transitivePeerDependencies: + - supports-color + dev: true + + /once/1.4.0: + resolution: {integrity: sha1-WDsap3WWHUsROsF9nFC6753Xa9E=} + dependencies: + wrappy: 1.0.2 + dev: true + + /optionator/0.8.3: + resolution: {integrity: sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==} + engines: {node: '>= 0.8.0'} + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.3.0 + prelude-ls: 1.1.2 + type-check: 0.3.2 + word-wrap: 1.2.3 + dev: true + + /p-limit/2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + dependencies: + p-try: 2.2.0 + dev: true + + /p-limit/3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + dependencies: + yocto-queue: 0.1.0 + dev: true + + /p-locate/4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + dependencies: + p-limit: 2.3.0 + dev: true + + /p-locate/5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + dependencies: + p-limit: 3.1.0 + dev: true + + /p-map/3.0.0: + resolution: {integrity: sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==} + engines: {node: '>=8'} + dependencies: + aggregate-error: 3.1.0 + dev: true + + /p-try/2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + dev: true + + /package-hash/4.0.0: + resolution: {integrity: sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==} + engines: {node: '>=8'} + dependencies: + graceful-fs: 4.2.9 + hasha: 5.2.2 + lodash.flattendeep: 4.4.0 + release-zalgo: 1.0.0 + dev: true + + /path-exists/4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + dev: true + + /path-is-absolute/1.0.1: + resolution: {integrity: sha1-F0uSaHNVNP+8es5r9TpanhtcX18=} + engines: {node: '>=0.10.0'} + dev: true + + /path-key/3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + dev: true + + /picocolors/1.0.0: + resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + dev: true + + /picomatch/2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + dev: true + + /pkg-dir/4.2.0: + resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} + engines: {node: '>=8'} + dependencies: + find-up: 4.1.0 + dev: true + + /prelude-ls/0.6.0: + resolution: {integrity: sha1-z4JLS0fMc8vZb56YhQc7Q6rqqzs=} + engines: {node: '>= 0.8.0'} + dev: true + + /prelude-ls/1.1.2: + resolution: {integrity: sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=} + engines: {node: '>= 0.8.0'} + dev: true + + /process-on-spawn/1.0.0: + resolution: {integrity: sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==} + engines: {node: '>=8'} + dependencies: + fromentries: 1.3.2 + dev: true + + /querystringify/2.2.0: + resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} + dev: false + + /randombytes/2.1.0: + resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + dependencies: + safe-buffer: 5.2.1 + dev: true + + /readable-stream/3.6.0: + resolution: {integrity: sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==} + engines: {node: '>= 6'} + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + dev: false + + /readdirp/3.5.0: + resolution: {integrity: sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==} + engines: {node: '>=8.10.0'} + dependencies: + picomatch: 2.3.1 + dev: true + + /release-zalgo/1.0.0: + resolution: {integrity: sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=} + engines: {node: '>=4'} + dependencies: + es6-error: 4.1.1 + dev: true + + /repeat-string/1.6.1: + resolution: {integrity: sha1-jcrkcOHIirwtYA//Sndihtp15jc=} + engines: {node: '>=0.10'} + dev: true + + /require-directory/2.1.1: + resolution: {integrity: sha1-jGStX9MNqxyXbiNE/+f3kqam30I=} + engines: {node: '>=0.10.0'} + dev: true + + /require-main-filename/2.0.0: + resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} + dev: true + + /requires-port/1.0.0: + resolution: {integrity: sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=} + dev: false + + /resolve-from/5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + dev: true + + /resolve/1.1.7: + resolution: {integrity: sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=} + dev: true + + /right-align/0.1.3: + resolution: {integrity: sha1-YTObci/mo1FWiSENJOFMlhSGE+8=} + engines: {node: '>=0.10.0'} + dependencies: + align-text: 0.1.4 + dev: true + + /rimraf/3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + hasBin: true + dependencies: + glob: 7.2.0 + dev: true + + /safe-buffer/5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + + /safe-buffer/5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + /semver/6.3.0: + resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} + hasBin: true + dev: true + + /serialize-javascript/5.0.1: + resolution: {integrity: sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==} + dependencies: + randombytes: 2.1.0 + dev: true + + /set-blocking/2.0.0: + resolution: {integrity: sha1-BF+XgtARrppoA93TgrJDkrPYkPc=} + dev: true + + /shebang-command/2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + dependencies: + shebang-regex: 3.0.0 + dev: true + + /shebang-regex/3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + dev: true + + /signal-exit/3.0.6: + resolution: {integrity: sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ==} + dev: true + + /source-map/0.2.0: + resolution: {integrity: sha1-2rc/vPwrqBm03gO9b26qSBZLP50=} + engines: {node: '>=0.8.0'} + dependencies: + amdefine: 1.0.1 + dev: true + optional: true + + /source-map/0.5.7: + resolution: {integrity: sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=} + engines: {node: '>=0.10.0'} + dev: true + + /source-map/0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + dev: true + + /spawn-wrap/2.0.0: + resolution: {integrity: sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==} + engines: {node: '>=8'} + dependencies: + foreground-child: 2.0.0 + is-windows: 1.0.2 + make-dir: 3.1.0 + rimraf: 3.0.2 + signal-exit: 3.0.6 + which: 2.0.2 + dev: true + + /sprintf-js/1.0.3: + resolution: {integrity: sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=} + dev: true + + /string-width/2.1.1: + resolution: {integrity: sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==} + engines: {node: '>=4'} + dependencies: + is-fullwidth-code-point: 2.0.0 + strip-ansi: 4.0.0 + dev: true + + /string-width/4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + dev: true + + /string_decoder/1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + dependencies: + safe-buffer: 5.2.1 + dev: false + + /strip-ansi/4.0.0: + resolution: {integrity: sha1-qEeQIusaw2iocTibY1JixQXuNo8=} + engines: {node: '>=4'} + dependencies: + ansi-regex: 3.0.0 + dev: true + + /strip-ansi/6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + dependencies: + ansi-regex: 5.0.1 + dev: true + + /strip-bom/4.0.0: + resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} + engines: {node: '>=8'} + dev: true + + /strip-json-comments/3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + dev: true + + /supports-color/3.2.3: + resolution: {integrity: sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=} + engines: {node: '>=0.8.0'} + dependencies: + has-flag: 1.0.0 + dev: true + + /supports-color/5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + dependencies: + has-flag: 3.0.0 + dev: true + + /supports-color/7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + dependencies: + has-flag: 4.0.0 + dev: true + + /supports-color/8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + dependencies: + has-flag: 4.0.0 + dev: true + + /test-exclude/6.0.0: + resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} + engines: {node: '>=8'} + dependencies: + '@istanbuljs/schema': 0.1.3 + glob: 7.2.0 + minimatch: 3.0.4 + dev: true + + /to-fast-properties/2.0.0: + resolution: {integrity: sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=} + engines: {node: '>=4'} + dev: true + + /to-regex-range/5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + dependencies: + is-number: 7.0.0 + dev: true + + /type-check/0.3.2: + resolution: {integrity: sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=} + engines: {node: '>= 0.8.0'} + dependencies: + prelude-ls: 1.1.2 + dev: true + + /type-fest/0.8.1: + resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==} + engines: {node: '>=8'} + dev: true + + /typedarray-to-buffer/3.1.5: + resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} + dependencies: + is-typedarray: 1.0.0 + dev: true + + /uglify-js/2.8.29: + resolution: {integrity: sha1-KcVzMUgFe7Th913zW3qcty5qWd0=} + engines: {node: '>=0.8.0'} + hasBin: true + dependencies: + source-map: 0.5.7 + yargs: 3.10.0 + optionalDependencies: + uglify-to-browserify: 1.0.2 + dev: true + + /uglify-js/3.14.5: + resolution: {integrity: sha512-qZukoSxOG0urUTvjc2ERMTcAy+BiFh3weWAkeurLwjrCba73poHmG3E36XEjd/JGukMzwTL7uCxZiAexj8ppvQ==} + engines: {node: '>=0.8.0'} + hasBin: true + dev: true + optional: true + + /uglify-to-browserify/1.0.2: + resolution: {integrity: sha1-bgkk1r2mta/jSeOabWMoUKD4grc=} + dev: true + optional: true + + /url-parse/1.4.7: + resolution: {integrity: sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg==} + dependencies: + querystringify: 2.2.0 + requires-port: 1.0.0 + dev: false + + /util-deprecate/1.0.2: + resolution: {integrity: sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=} + dev: false + + /uuid/3.4.0: + resolution: {integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==} + deprecated: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details. + hasBin: true + dev: true + + /which-module/2.0.0: + resolution: {integrity: sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=} + dev: true + + /which/1.3.1: + resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} + hasBin: true + dependencies: + isexe: 2.0.0 + dev: true + + /which/2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + dependencies: + isexe: 2.0.0 + dev: true + + /wide-align/1.1.3: + resolution: {integrity: sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==} + dependencies: + string-width: 2.1.1 + dev: true + + /window-size/0.1.0: + resolution: {integrity: sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=} + engines: {node: '>= 0.8.0'} + dev: true + + /word-wrap/1.2.3: + resolution: {integrity: sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==} + engines: {node: '>=0.10.0'} + dev: true + + /wordwrap/0.0.2: + resolution: {integrity: sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=} + engines: {node: '>=0.4.0'} + dev: true + + /wordwrap/1.0.0: + resolution: {integrity: sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=} + dev: true + + /workerpool/6.1.0: + resolution: {integrity: sha512-toV7q9rWNYha963Pl/qyeZ6wG+3nnsyvolaNUS8+R5Wtw6qJPTxIlOP1ZSvcGhEJw+l3HMMmtiNo9Gl61G4GVg==} + dev: true + + /wrap-ansi/6.2.0: + resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} + engines: {node: '>=8'} + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + dev: true + + /wrap-ansi/7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + dev: true + + /wrappy/1.0.2: + resolution: {integrity: sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=} + dev: true + + /write-file-atomic/3.0.3: + resolution: {integrity: sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==} + dependencies: + imurmurhash: 0.1.4 + is-typedarray: 1.0.0 + signal-exit: 3.0.6 + typedarray-to-buffer: 3.1.5 + dev: true + + /y18n/4.0.3: + resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} + dev: true + + /y18n/5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + dev: true + + /yargs-parser/18.1.3: + resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} + engines: {node: '>=6'} + dependencies: + camelcase: 5.3.1 + decamelize: 1.2.0 + dev: true + + /yargs-parser/20.2.4: + resolution: {integrity: sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==} + engines: {node: '>=10'} + dev: true + + /yargs-unparser/2.0.0: + resolution: {integrity: sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==} + engines: {node: '>=10'} + dependencies: + camelcase: 6.3.0 + decamelize: 4.0.0 + flat: 5.0.2 + is-plain-obj: 2.1.0 + dev: true + + /yargs/15.4.1: + resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} + engines: {node: '>=8'} + dependencies: + cliui: 6.0.0 + decamelize: 1.2.0 + find-up: 4.1.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + require-main-filename: 2.0.0 + set-blocking: 2.0.0 + string-width: 4.2.3 + which-module: 2.0.0 + y18n: 4.0.3 + yargs-parser: 18.1.3 + dev: true + + /yargs/16.2.0: + resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} + engines: {node: '>=10'} + dependencies: + cliui: 7.0.4 + escalade: 3.1.1 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 20.2.4 + dev: true + + /yargs/3.10.0: + resolution: {integrity: sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=} + dependencies: + camelcase: 1.2.1 + cliui: 2.1.0 + decamelize: 1.2.0 + window-size: 0.1.0 + dev: true + + /yocto-queue/0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + dev: true diff --git a/test/channel.js b/test/channel.js index 072c3354..875b7cbf 100644 --- a/test/channel.js +++ b/test/channel.js @@ -1,624 +1,779 @@ // Test the channel machinery -'use strict'; - -var assert = require('assert'); -var Promise = require('bluebird'); -var Channel = require('../lib/channel').Channel; -var Connection = require('../lib/connection').Connection; -var util = require('./util'); -var succeed = util.succeed, fail = util.fail, latch = util.latch; +"use strict"; + +var assert = require("assert"); +var Channel = require("../lib/channel").Channel; +var Connection = require("../lib/connection").Connection; +var util = require("./util"); +var succeed = util.succeed, + fail = util.fail, + latch = util.latch; var completes = util.completes; -var defs = require('../lib/defs'); -var conn_handshake = require('./connection').connection_handshake; -var OPEN_OPTS = require('./connection').OPEN_OPTS; -var Buffer = require('safe-buffer').Buffer; +var defs = require("../lib/defs"); +var conn_handshake = require("./connection").connection_handshake; +var OPEN_OPTS = require("./connection").OPEN_OPTS; +var Buffer = require("safe-buffer").Buffer; var LOG_ERRORS = process.env.LOG_ERRORS; function baseChannelTest(client, server) { - return function(done) { + return function (done) { var bothDone = latch(2, done); var pair = util.socketPair(); var c = new Connection(pair.client); - if (LOG_ERRORS) c.on('error', console.warn); + if (LOG_ERRORS) c.on("error", console.warn); - c.open(OPEN_OPTS, function(err, ok) { + c.open(OPEN_OPTS, function (err, ok) { if (err === null) client(c, bothDone); else fail(bothDone); }); pair.server.read(8); // discard the protocol header - var s = util.runServer(pair.server, function(send, wait) { - conn_handshake(send, wait) - .then(function() { - server(send, wait, bothDone); - }, fail(bothDone)); + var s = util.runServer(pair.server, function (send, wait) { + conn_handshake(send, wait).then(function () { + server(send, wait, bothDone); + }, fail(bothDone)); }); }; } function channelTest(client, server) { return baseChannelTest( - function(conn, done) { + function (conn, done) { var ch = new Channel(conn); - if (LOG_ERRORS) ch.on('error', console.warn); + if (LOG_ERRORS) ch.on("error", console.warn); client(ch, done, conn); }, - function(send, wait, done) { + function (send, wait, done) { channel_handshake(send, wait) - .then(function(ch) { - return server(send, wait, done, ch); - }).then(null, fail(done)); // so you can return a promise to let - // errors bubble out - } + .then(function (ch) { + return server(send, wait, done, ch); + }) + .then(null, fail(done)); // so you can return a promise to let + // errors bubble out + }, ); -}; +} function channel_handshake(send, wait) { - return wait(defs.ChannelOpen)() - .then(function(open) { - assert.notEqual(0, open.channel); - send(defs.ChannelOpenOk, {channelId: Buffer.from('')}, open.channel); - return open.channel; - }); + return wait(defs.ChannelOpen)().then(function (open) { + assert.notEqual(0, open.channel); + send(defs.ChannelOpenOk, { channelId: Buffer.from("") }, open.channel); + return open.channel; + }); } // fields for deliver and publish and get-ok var DELIVER_FIELDS = { - consumerTag: 'fake', + consumerTag: "fake", deliveryTag: 1, redelivered: false, - exchange: 'foo', - routingKey: 'bar', + exchange: "foo", + routingKey: "bar", replyCode: defs.constants.NO_ROUTE, - replyText: 'derp', + replyText: "derp", }; function open(ch) { - return Promise.try(function() { - ch.allocate(); - return Promise.fromCallback(function(cb) { - ch._rpc(defs.ChannelOpen, {outOfBand: ''}, defs.ChannelOpenOk, cb); - }); + debugger; + return new Promise(function (resolve) { + resolve( + (function () { + ch.allocate(); + return new Promise(function (resolve, reject) { + ch._rpc(defs.ChannelOpen, { outOfBand: "" }, defs.ChannelOpenOk, function (err, result) { + if (err) { + reject(err); + } else { + resolve(result); + } + }); + }); + })(), + ); }); } -suite("channel open and close", function() { - -test("open", channelTest( - function(ch, done) { - open(ch).then(succeed(done), fail(done)); - }, - function(send, wait, done) { - done(); - })); - -test("bad server", baseChannelTest( - function(c, done) { - var ch = new Channel(c); - open(ch).then(fail(done), succeed(done)); - }, - function(send, wait, done) { - return wait(defs.ChannelOpen)() - .then(function(open) { - send(defs.ChannelCloseOk, {}, open.channel); - }).then(succeed(done), fail(done)); - })); - -test("open, close", channelTest( - function(ch, done) { - open(ch) - .then(function() { - return new Promise(function(resolve) { - ch.closeBecause("Bye", defs.constants.REPLY_SUCCESS, resolve); - }); - }) - .then(succeed(done), fail(done)); - }, - function(send, wait, done, ch) { - return wait(defs.ChannelClose)() - .then(function(close) { - send(defs.ChannelCloseOk, {}, ch); - }).then(succeed(done), fail(done)); - })); - -test("server close", channelTest( - function(ch, done) { - ch.on('error', function(error) { - assert.strictEqual(504, error.code); - assert.strictEqual(0, error.classId); - assert.strictEqual(0, error.methodId); - succeed(done)(); - }); - open(ch); - }, - function(send, wait, done, ch) { - send(defs.ChannelClose, { - replyText: 'Forced close', - replyCode: defs.constants.CHANNEL_ERROR, - classId: 0, methodId: 0 - }, ch); - wait(defs.ChannelCloseOk)() - .then(succeed(done), fail(done)); - })); - -test("overlapping channel/server close", channelTest( - function(ch, done, conn) { - var both = latch(2, done); - conn.on('error', succeed(both)); - ch.on('close', succeed(both)); - open(ch).then(function() { - ch.closeBecause("Bye", defs.constants.REPLY_SUCCESS); - }, fail(both)); - }, - function(send, wait, done, ch) { - wait(defs.ChannelClose)() - .then(function() { - send(defs.ConnectionClose, { - replyText: 'Got there first', - replyCode: defs.constants.INTERNAL_ERROR, - classId: 0, methodId: 0 - }, 0); - }) - .then(wait(defs.ConnectionCloseOk)) - .then(succeed(done), fail(done)); - })); - -test("double close", channelTest( - function(ch, done) { - open(ch).then(function() { - ch.closeBecause("First close", defs.constants.REPLY_SUCCESS); - // NB no synchronisation, we do this straight away - assert.throws(function() { - ch.closeBecause("Second close", defs.constants.REPLY_SUCCESS); - }); - }).then(succeed(done), fail(done)); - }, - function(send, wait, done, ch) { - wait(defs.ChannelClose)() - .then(function() { - send(defs.ChannelCloseOk, { - }, ch); - }) - .then(succeed(done), fail(done)); - })); +suite("channel open and close", function () { + test( + "open", + channelTest( + function (ch, done) { + open(ch).then(succeed(done), fail(done)); + }, + function (send, wait, done) { + done(); + }, + ), + ); -}); //suite + test( + "bad server", + baseChannelTest( + function (c, done) { + var ch = new Channel(c); + open(ch).then(fail(done), succeed(done)); + }, + function (send, wait, done) { + return wait(defs.ChannelOpen)() + .then(function (open) { + send(defs.ChannelCloseOk, {}, open.channel); + }) + .then(succeed(done), fail(done)); + }, + ), + ); -suite("channel machinery", function() { - -test("RPC", channelTest( - function(ch, done) { - var rpcLatch = latch(3, done); - open(ch).then(function() { - - function wheeboom(err, f) { - if (err !== null) rpcLatch(err); - else rpcLatch(); - } - - var fields = { - prefetchCount: 10, - prefetchSize: 0, - global: false - }; - - ch._rpc(defs.BasicQos, fields, defs.BasicQosOk, wheeboom); - ch._rpc(defs.BasicQos, fields, defs.BasicQosOk, wheeboom); - ch._rpc(defs.BasicQos, fields, defs.BasicQosOk, wheeboom); - }).then(null, fail(rpcLatch)); - }, - function(send, wait, done, ch) { - function sendOk(f) { - send(defs.BasicQosOk, {}, ch); - } - - return wait(defs.BasicQos)() - .then(sendOk) - .then(wait(defs.BasicQos)) - .then(sendOk) - .then(wait(defs.BasicQos)) - .then(sendOk) - .then(succeed(done), fail(done)); - })); - -test("Bad RPC", channelTest( - function(ch, done) { - // We want to see the RPC rejected and the channel closed (with an - // error) - var errLatch = latch(2, done); - ch.on('error', function(error) { - assert.strictEqual(505, error.code); - assert.strictEqual(60, error.classId); - assert.strictEqual(72, error.methodId); - succeed(errLatch)(); - }); + test( + "open, close", + channelTest( + function (ch, done) { + open(ch) + .then(function () { + return new Promise(function (resolve) { + ch.closeBecause("Bye", defs.constants.REPLY_SUCCESS, resolve); + }); + }) + .then(succeed(done), fail(done)); + }, + function (send, wait, done, ch) { + return wait(defs.ChannelClose)() + .then(function (close) { + send(defs.ChannelCloseOk, {}, ch); + }) + .then(succeed(done), fail(done)); + }, + ), + ); - open(ch) - .then(function() { - ch._rpc(defs.BasicRecover, {requeue: true}, defs.BasicRecoverOk, - function(err) { - if (err !== null) errLatch(); - else errLatch(new Error('Expected RPC failure')); - }); - }, fail(errLatch)); - }, - function(send, wait, done, ch) { - return wait()() - .then(function() { - send(defs.BasicGetEmpty, {clusterId: ''}, ch); - }) // oh wait! that was wrong! expect a channel close - .then(wait(defs.ChannelClose)) - .then(function() { - send(defs.ChannelCloseOk, {}, ch); - }).then(succeed(done), fail(done)); - })); - -test("RPC on closed channel", channelTest( - function(ch, done) { - open(ch); - - var close = new Promise(function(resolve) { - ch.on('error', function(error) { + test( + "server close", + channelTest( + function (ch, done) { + ch.on("error", function (error) { assert.strictEqual(504, error.code); assert.strictEqual(0, error.classId); assert.strictEqual(0, error.methodId); - resolve(); - }); - }); + succeed(done)(); + }); + open(ch); + }, + function (send, wait, done, ch) { + send( + defs.ChannelClose, + { + replyText: "Forced close", + replyCode: defs.constants.CHANNEL_ERROR, + classId: 0, + methodId: 0, + }, + ch, + ); + wait(defs.ChannelCloseOk)().then(succeed(done), fail(done)); + }, + ), + ); - function failureCb(resolve, reject) { - return function(err) { - if (err !== null) resolve(); - else reject(); - } - } + test( + "overlapping channel/server close", + channelTest( + function (ch, done, conn) { + var both = latch(2, done); + conn.on("error", succeed(both)); + ch.on("close", succeed(both)); + open(ch).then(function () { + ch.closeBecause("Bye", defs.constants.REPLY_SUCCESS); + }, fail(both)); + }, + function (send, wait, done, ch) { + wait(defs.ChannelClose)() + .then(function () { + send( + defs.ConnectionClose, + { + replyText: "Got there first", + replyCode: defs.constants.INTERNAL_ERROR, + classId: 0, + methodId: 0, + }, + 0, + ); + }) + .then(wait(defs.ConnectionCloseOk)) + .then(succeed(done), fail(done)); + }, + ), + ); - var fail1 = new Promise(function(resolve, reject) { - return ch._rpc(defs.BasicRecover, {requeue:true}, defs.BasicRecoverOk, - failureCb(resolve, reject)); - }); + test( + "double close", + channelTest( + function (ch, done) { + open(ch) + .then(function () { + ch.closeBecause("First close", defs.constants.REPLY_SUCCESS); + // NB no synchronisation, we do this straight away + assert.throws(function () { + ch.closeBecause("Second close", defs.constants.REPLY_SUCCESS); + }); + }) + .then(succeed(done), fail(done)); + }, + function (send, wait, done, ch) { + wait(defs.ChannelClose)() + .then(function () { + send(defs.ChannelCloseOk, {}, ch); + }) + .then(succeed(done), fail(done)); + }, + ), + ); +}); //suite - var fail2 = new Promise(function(resolve, reject) { - return ch._rpc(defs.BasicRecover, {requeue:true}, defs.BasicRecoverOk, - failureCb(resolve, reject)); - }); +suite("channel machinery", function () { + test( + "RPC", + channelTest( + function (ch, done) { + var rpcLatch = latch(3, done); + open(ch) + .then(function () { + function wheeboom(err, f) { + if (err !== null) rpcLatch(err); + else rpcLatch(); + } + + var fields = { + prefetchCount: 10, + prefetchSize: 0, + global: false, + }; + + ch._rpc(defs.BasicQos, fields, defs.BasicQosOk, wheeboom); + ch._rpc(defs.BasicQos, fields, defs.BasicQosOk, wheeboom); + ch._rpc(defs.BasicQos, fields, defs.BasicQosOk, wheeboom); + }) + .then(null, fail(rpcLatch)); + }, + function (send, wait, done, ch) { + function sendOk(f) { + send(defs.BasicQosOk, {}, ch); + } + + return wait(defs.BasicQos)().then(sendOk).then(wait(defs.BasicQos)).then(sendOk).then(wait(defs.BasicQos)).then(sendOk).then(succeed(done), fail(done)); + }, + ), + ); - Promise.join(close, fail1, fail2) - .then(succeed(done)) - .catch(fail(done)); - }, - function(send, wait, done, ch) { - wait(defs.BasicRecover)() - .then(function() { - send(defs.ChannelClose, { - replyText: 'Nuh-uh!', - replyCode: defs.constants.CHANNEL_ERROR, - methodId: 0, classId: 0 - }, ch); - return wait(defs.ChannelCloseOk); - }) - .then(succeed(done)) - .catch(fail(done)); - })); - -test("publish all < single chunk threshold", channelTest( - function(ch, done) { - open(ch) - .then(function() { - ch.sendMessage({ - exchange: 'foo', routingKey: 'bar', - mandatory: false, immediate: false, ticket: 0 - }, {}, Buffer.from('foobar')); - }) - .then(succeed(done), fail(done)); - }, - function(send, wait, done, ch) { - wait(defs.BasicPublish)() - .then(wait(defs.BasicProperties)) - .then(wait(undefined)) // content frame - .then(function(f) { - assert.equal('foobar', f.content.toString()); - }).then(succeed(done), fail(done)); - })); - -test("publish content > single chunk threshold", channelTest( - function(ch, done) { - open(ch); - completes(function() { - ch.sendMessage({ - exchange: 'foo', routingKey: 'bar', - mandatory: false, immediate: false, ticket: 0 - }, {}, Buffer.alloc(3000)); - }, done); - }, - function(send, wait, done, ch) { - wait(defs.BasicPublish)() - .then(wait(defs.BasicProperties)) - .then(wait(undefined)) // content frame - .then(function(f) { - assert.equal(3000, f.content.length); - }).then(succeed(done), fail(done)); - })); - -test("publish method & headers > threshold", channelTest( - function(ch, done) { - open(ch); - completes(function() { - ch.sendMessage({ - exchange: 'foo', routingKey: 'bar', - mandatory: false, immediate: false, ticket: 0 - }, { - headers: {foo: Buffer.alloc(3000)} - }, Buffer.from('foobar')); - }, done); - }, - function(send, wait, done, ch) { - wait(defs.BasicPublish)() - .then(wait(defs.BasicProperties)) - .then(wait(undefined)) // content frame - .then(function(f) { - assert.equal('foobar', f.content.toString()); - }).then(succeed(done), fail(done)); - })); - -test("publish zero-length message", channelTest( - function(ch, done) { - open(ch); - completes(function() { - ch.sendMessage({ - exchange: 'foo', routingKey: 'bar', - mandatory: false, immediate: false, ticket: 0 - }, {}, Buffer.alloc(0)); - ch.sendMessage({ - exchange: 'foo', routingKey: 'bar', - mandatory: false, immediate: false, ticket: 0 - }, {}, Buffer.alloc(0)); - }, done); - }, - function(send, wait, done, ch) { - wait(defs.BasicPublish)() - .then(wait(defs.BasicProperties)) - // no content frame for a zero-length message - .then(wait(defs.BasicPublish)) - .then(succeed(done), fail(done)); - })); - -test("delivery", channelTest( - function(ch, done) { - open(ch); - ch.on('delivery', function(m) { - completes(function() { - assert.equal('barfoo', m.content.toString()); - }, done); - }); - }, - function(send, wait, done, ch) { - completes(function() { - send(defs.BasicDeliver, DELIVER_FIELDS, ch, Buffer.from('barfoo')); - }, done); - })); - -test("zero byte msg", channelTest( - function(ch, done) { - open(ch); - ch.on('delivery', function(m) { - completes(function() { - assert.deepEqual(Buffer.alloc(0), m.content); - }, done); - }); - }, - function(send, wait, done, ch) { - completes(function() { - send(defs.BasicDeliver, DELIVER_FIELDS, ch, Buffer.from('')); - }, done); - })); - -test("bad delivery", channelTest( - function(ch, done) { - var errorAndClose = latch(2, done); - ch.on('error', function(error) { - assert.strictEqual(505, error.code); - assert.strictEqual(60, error.classId); - assert.strictEqual(60, error.methodId); - succeed(errorAndClose)(); - }); - ch.on('close', succeed(errorAndClose)); - open(ch); - }, - function(send, wait, done, ch) { - send(defs.BasicDeliver, DELIVER_FIELDS, ch); - // now send another deliver without having sent the content - send(defs.BasicDeliver, DELIVER_FIELDS, ch); - return wait(defs.ChannelClose)() - .then(function() { - send(defs.ChannelCloseOk, {}, ch); - }).then(succeed(done), fail(done)); - })); - -test("bad content send", channelTest( - function(ch, done) { - completes(function() { - open(ch); - assert.throws(function() { - ch.sendMessage({routingKey: 'foo', - exchange: 'amq.direct'}, - {}, null); - }); - }, done); - }, - function(send, wait, done, ch) { - done(); - })); - -test("bad properties send", channelTest( - function(ch, done) { - completes(function() { - open(ch); - assert.throws(function() { - ch.sendMessage({routingKey: 'foo', - exchange: 'amq.direct'}, - {contentEncoding: 7}, - Buffer.from('foobar')); - }); - }, done); - }, - function(send, wait, done, ch) { - done(); - })); - -test("bad consumer", channelTest( - function(ch, done) { - var errorAndClose = latch(2, done); - ch.on('delivery', function() { - throw new Error("I am a bad consumer"); - }); - ch.on('error', function(error) { - assert.strictEqual(541, error.code); - assert.strictEqual(undefined, error.classId); - assert.strictEqual(undefined, error.methodId); - succeed(errorAndClose)(); - }); - ch.on('close', succeed(errorAndClose)); - open(ch); - }, - function(send, wait, done, ch) { - send(defs.BasicDeliver, DELIVER_FIELDS, ch, Buffer.from('barfoo')); - return wait(defs.ChannelClose)() - .then(function() { - send(defs.ChannelCloseOk, {}, ch); - }).then(succeed(done), fail(done)); - })); - -test("bad send in consumer", channelTest( - function(ch, done) { - var errorAndClose = latch(2, done); - ch.on('close', succeed(errorAndClose)); - ch.on('error', function(error) { - assert.strictEqual(541, error.code); - assert.strictEqual(undefined, error.classId); - assert.strictEqual(undefined, error.methodId); - succeed(errorAndClose)(); - }); + test( + "Bad RPC", + channelTest( + function (ch, done) { + // We want to see the RPC rejected and the channel closed (with an + // error) + var errLatch = latch(2, done); + ch.on("error", function (error) { + assert.strictEqual(505, error.code); + assert.strictEqual(60, error.classId); + assert.strictEqual(72, error.methodId); + succeed(errLatch)(); + }); - ch.on('delivery', function() { - ch.sendMessage({routingKey: 'foo', - exchange: 'amq.direct'}, - {}, null); // can't send null - }); + open(ch).then(function () { + ch._rpc(defs.BasicRecover, { requeue: true }, defs.BasicRecoverOk, function (err) { + if (err !== null) errLatch(); + else errLatch(new Error("Expected RPC failure")); + }); + }, fail(errLatch)); + }, + function (send, wait, done, ch) { + return wait()() + .then(function () { + send(defs.BasicGetEmpty, { clusterId: "" }, ch); + }) // oh wait! that was wrong! expect a channel close + .then(wait(defs.ChannelClose)) + .then(function () { + send(defs.ChannelCloseOk, {}, ch); + }) + .then(succeed(done), fail(done)); + }, + ), + ); - open(ch); - }, - function(send, wait, done, ch) { - completes(function() { - send(defs.BasicDeliver, DELIVER_FIELDS, ch, - Buffer.from('barfoo')); - }, done); - return wait(defs.ChannelClose)() - .then(function() { - send(defs.ChannelCloseOk, {}, ch); - }).then(succeed(done), fail(done)); - })); - -test("return", channelTest( - function(ch, done) { - ch.on('return', function(m) { - completes(function() { - assert.equal('barfoo', m.content.toString()); - }, done); - }); - open(ch); - }, - function(send, wait, done, ch) { - completes(function() { - send(defs.BasicReturn, DELIVER_FIELDS, ch, Buffer.from('barfoo')); - }, done); - })); - -test("cancel", channelTest( - function(ch, done) { - ch.on('cancel', function(f) { - completes(function() { - assert.equal('product of society', f.consumerTag); - }, done); - }); - open(ch); - }, - function(send, wait, done, ch) { - completes(function() { - send(defs.BasicCancel, { - consumerTag: 'product of society', - nowait: false - }, ch); - }, done); - })); - -function confirmTest(variety, Method) { - return test('confirm ' + variety, channelTest( - function(ch, done) { - ch.on(variety, function(f) { - completes(function() { - assert.equal(1, f.deliveryTag); + test( + "RPC on closed channel", + channelTest( + function (ch, done) { + open(ch); + + var close = new Promise(function (resolve) { + ch.on("error", function (error) { + assert.strictEqual(504, error.code); + assert.strictEqual(0, error.classId); + assert.strictEqual(0, error.methodId); + resolve(); + }); + }); + + function failureCb(resolve, reject) { + return function (err) { + if (err !== null) resolve(); + else reject(); + }; + } + + var fail1 = new Promise(function (resolve, reject) { + return ch._rpc(defs.BasicRecover, { requeue: true }, defs.BasicRecoverOk, failureCb(resolve, reject)); + }); + + var fail2 = new Promise(function (resolve, reject) { + return ch._rpc(defs.BasicRecover, { requeue: true }, defs.BasicRecoverOk, failureCb(resolve, reject)); + }); + + Promise.all([close, fail1, fail2]).then(succeed(done)).catch(fail(done)); + }, + function (send, wait, done, ch) { + wait(defs.BasicRecover)() + .then(function () { + send( + defs.ChannelClose, + { + replyText: "Nuh-uh!", + replyCode: defs.constants.CHANNEL_ERROR, + methodId: 0, + classId: 0, + }, + ch, + ); + return wait(defs.ChannelCloseOk); + }) + .then(succeed(done)) + .catch(fail(done)); + }, + ), + ); + + test( + "publish all < single chunk threshold", + channelTest( + function (ch, done) { + open(ch) + .then(function () { + ch.sendMessage( + { + exchange: "foo", + routingKey: "bar", + mandatory: false, + immediate: false, + ticket: 0, + }, + {}, + Buffer.from("foobar"), + ); + }) + .then(succeed(done), fail(done)); + }, + function (send, wait, done, ch) { + wait(defs.BasicPublish)() + .then(wait(defs.BasicProperties)) + .then(wait(undefined)) // content frame + .then(function (f) { + assert.equal("foobar", f.content.toString()); + }) + .then(succeed(done), fail(done)); + }, + ), + ); + + test( + "publish content > single chunk threshold", + channelTest( + function (ch, done) { + open(ch); + completes(function () { + ch.sendMessage( + { + exchange: "foo", + routingKey: "bar", + mandatory: false, + immediate: false, + ticket: 0, + }, + {}, + Buffer.alloc(3000), + ); }, done); - }); - open(ch); - }, - function(send, wait, done, ch) { - completes(function() { - send(Method, { - deliveryTag: 1, - multiple: false - }, ch); - }, done); - })); -} + }, + function (send, wait, done, ch) { + wait(defs.BasicPublish)() + .then(wait(defs.BasicProperties)) + .then(wait(undefined)) // content frame + .then(function (f) { + assert.equal(3000, f.content.length); + }) + .then(succeed(done), fail(done)); + }, + ), + ); -confirmTest("ack", defs.BasicAck); -confirmTest("nack", defs.BasicNack); + test( + "publish method & headers > threshold", + channelTest( + function (ch, done) { + open(ch); + completes(function () { + ch.sendMessage( + { + exchange: "foo", + routingKey: "bar", + mandatory: false, + immediate: false, + ticket: 0, + }, + { + headers: { foo: Buffer.alloc(3000) }, + }, + Buffer.from("foobar"), + ); + }, done); + }, + function (send, wait, done, ch) { + wait(defs.BasicPublish)() + .then(wait(defs.BasicProperties)) + .then(wait(undefined)) // content frame + .then(function (f) { + assert.equal("foobar", f.content.toString()); + }) + .then(succeed(done), fail(done)); + }, + ), + ); -test("out-of-order acks", channelTest( - function(ch, done) { - var allConfirms = latch(3, function() { - completes(function() { - assert.equal(0, ch.unconfirmed.length); - assert.equal(4, ch.lwm); - }, done); - }); - ch.pushConfirmCallback(allConfirms); - ch.pushConfirmCallback(allConfirms); - ch.pushConfirmCallback(allConfirms); - open(ch); - }, - function(send, wait, done, ch) { - completes(function() { - send(defs.BasicAck, {deliveryTag: 2, multiple: false}, ch); - send(defs.BasicAck, {deliveryTag: 3, multiple: false}, ch); - send(defs.BasicAck, {deliveryTag: 1, multiple: false}, ch); - }, done); - })); - -test("not all out-of-order acks", channelTest( - function(ch, done) { - var allConfirms = latch(2, function() { - completes(function() { - assert.equal(1, ch.unconfirmed.length); - assert.equal(3, ch.lwm); - }, done); - }); - ch.pushConfirmCallback(allConfirms); // tag = 1 - ch.pushConfirmCallback(allConfirms); // tag = 2 - ch.pushConfirmCallback(function() { - done(new Error('Confirm callback should not be called')); - }); - open(ch); - }, - function(send, wait, done, ch) { - completes(function() { - send(defs.BasicAck, {deliveryTag: 2, multiple: false}, ch); - send(defs.BasicAck, {deliveryTag: 1, multiple: false}, ch); - }, done); - })); + test( + "publish zero-length message", + channelTest( + function (ch, done) { + open(ch); + completes(function () { + ch.sendMessage( + { + exchange: "foo", + routingKey: "bar", + mandatory: false, + immediate: false, + ticket: 0, + }, + {}, + Buffer.alloc(0), + ); + ch.sendMessage( + { + exchange: "foo", + routingKey: "bar", + mandatory: false, + immediate: false, + ticket: 0, + }, + {}, + Buffer.alloc(0), + ); + }, done); + }, + function (send, wait, done, ch) { + wait(defs.BasicPublish)() + .then(wait(defs.BasicProperties)) + // no content frame for a zero-length message + .then(wait(defs.BasicPublish)) + .then(succeed(done), fail(done)); + }, + ), + ); + + test( + "delivery", + channelTest( + function (ch, done) { + open(ch); + ch.on("delivery", function (m) { + completes(function () { + assert.equal("barfoo", m.content.toString()); + }, done); + }); + }, + function (send, wait, done, ch) { + completes(function () { + send(defs.BasicDeliver, DELIVER_FIELDS, ch, Buffer.from("barfoo")); + }, done); + }, + ), + ); + + test( + "zero byte msg", + channelTest( + function (ch, done) { + open(ch); + ch.on("delivery", function (m) { + completes(function () { + assert.deepEqual(Buffer.alloc(0), m.content); + }, done); + }); + }, + function (send, wait, done, ch) { + completes(function () { + send(defs.BasicDeliver, DELIVER_FIELDS, ch, Buffer.from("")); + }, done); + }, + ), + ); + test( + "bad delivery", + channelTest( + function (ch, done) { + var errorAndClose = latch(2, done); + ch.on("error", function (error) { + assert.strictEqual(505, error.code); + assert.strictEqual(60, error.classId); + assert.strictEqual(60, error.methodId); + succeed(errorAndClose)(); + }); + ch.on("close", succeed(errorAndClose)); + open(ch); + }, + function (send, wait, done, ch) { + send(defs.BasicDeliver, DELIVER_FIELDS, ch); + // now send another deliver without having sent the content + send(defs.BasicDeliver, DELIVER_FIELDS, ch); + return wait(defs.ChannelClose)() + .then(function () { + send(defs.ChannelCloseOk, {}, ch); + }) + .then(succeed(done), fail(done)); + }, + ), + ); + + test( + "bad content send", + channelTest( + function (ch, done) { + completes(function () { + open(ch); + assert.throws(function () { + ch.sendMessage({ routingKey: "foo", exchange: "amq.direct" }, {}, null); + }); + }, done); + }, + function (send, wait, done, ch) { + done(); + }, + ), + ); + + test( + "bad properties send", + channelTest( + function (ch, done) { + completes(function () { + open(ch); + assert.throws(function () { + ch.sendMessage({ routingKey: "foo", exchange: "amq.direct" }, { contentEncoding: 7 }, Buffer.from("foobar")); + }); + }, done); + }, + function (send, wait, done, ch) { + done(); + }, + ), + ); + + test( + "bad consumer", + channelTest( + function (ch, done) { + var errorAndClose = latch(2, done); + ch.on("delivery", function () { + throw new Error("I am a bad consumer"); + }); + ch.on("error", function (error) { + assert.strictEqual(541, error.code); + assert.strictEqual(undefined, error.classId); + assert.strictEqual(undefined, error.methodId); + succeed(errorAndClose)(); + }); + ch.on("close", succeed(errorAndClose)); + open(ch); + }, + function (send, wait, done, ch) { + send(defs.BasicDeliver, DELIVER_FIELDS, ch, Buffer.from("barfoo")); + return wait(defs.ChannelClose)() + .then(function () { + send(defs.ChannelCloseOk, {}, ch); + }) + .then(succeed(done), fail(done)); + }, + ), + ); + + test( + "bad send in consumer", + channelTest( + function (ch, done) { + var errorAndClose = latch(2, done); + ch.on("close", succeed(errorAndClose)); + ch.on("error", function (error) { + assert.strictEqual(541, error.code); + assert.strictEqual(undefined, error.classId); + assert.strictEqual(undefined, error.methodId); + succeed(errorAndClose)(); + }); + + ch.on("delivery", function () { + ch.sendMessage({ routingKey: "foo", exchange: "amq.direct" }, {}, null); // can't send null + }); + + open(ch); + }, + function (send, wait, done, ch) { + completes(function () { + send(defs.BasicDeliver, DELIVER_FIELDS, ch, Buffer.from("barfoo")); + }, done); + return wait(defs.ChannelClose)() + .then(function () { + send(defs.ChannelCloseOk, {}, ch); + }) + .then(succeed(done), fail(done)); + }, + ), + ); + + test( + "return", + channelTest( + function (ch, done) { + ch.on("return", function (m) { + completes(function () { + assert.equal("barfoo", m.content.toString()); + }, done); + }); + open(ch); + }, + function (send, wait, done, ch) { + completes(function () { + send(defs.BasicReturn, DELIVER_FIELDS, ch, Buffer.from("barfoo")); + }, done); + }, + ), + ); + + test( + "cancel", + channelTest( + function (ch, done) { + ch.on("cancel", function (f) { + completes(function () { + assert.equal("product of society", f.consumerTag); + }, done); + }); + open(ch); + }, + function (send, wait, done, ch) { + completes(function () { + send( + defs.BasicCancel, + { + consumerTag: "product of society", + nowait: false, + }, + ch, + ); + }, done); + }, + ), + ); + + function confirmTest(variety, Method) { + return test( + "confirm " + variety, + channelTest( + function (ch, done) { + ch.on(variety, function (f) { + completes(function () { + assert.equal(1, f.deliveryTag); + }, done); + }); + open(ch); + }, + function (send, wait, done, ch) { + completes(function () { + send( + Method, + { + deliveryTag: 1, + multiple: false, + }, + ch, + ); + }, done); + }, + ), + ); + } + + confirmTest("ack", defs.BasicAck); + confirmTest("nack", defs.BasicNack); + + test( + "out-of-order acks", + channelTest( + function (ch, done) { + var allConfirms = latch(3, function () { + completes(function () { + assert.equal(0, ch.unconfirmed.length); + assert.equal(4, ch.lwm); + }, done); + }); + ch.pushConfirmCallback(allConfirms); + ch.pushConfirmCallback(allConfirms); + ch.pushConfirmCallback(allConfirms); + open(ch); + }, + function (send, wait, done, ch) { + completes(function () { + send(defs.BasicAck, { deliveryTag: 2, multiple: false }, ch); + send(defs.BasicAck, { deliveryTag: 3, multiple: false }, ch); + send(defs.BasicAck, { deliveryTag: 1, multiple: false }, ch); + }, done); + }, + ), + ); + + test( + "not all out-of-order acks", + channelTest( + function (ch, done) { + var allConfirms = latch(2, function () { + completes(function () { + assert.equal(1, ch.unconfirmed.length); + assert.equal(3, ch.lwm); + }, done); + }); + ch.pushConfirmCallback(allConfirms); // tag = 1 + ch.pushConfirmCallback(allConfirms); // tag = 2 + ch.pushConfirmCallback(function () { + done(new Error("Confirm callback should not be called")); + }); + open(ch); + }, + function (send, wait, done, ch) { + completes(function () { + send(defs.BasicAck, { deliveryTag: 2, multiple: false }, ch); + send(defs.BasicAck, { deliveryTag: 1, multiple: false }, ch); + }, done); + }, + ), + ); }); diff --git a/test/channel_api.js b/test/channel_api.js index bd5473f0..98f7e8d6 100644 --- a/test/channel_api.js +++ b/test/channel_api.js @@ -1,548 +1,537 @@ -'use strict'; +"use strict"; -var assert = require('assert'); -var api = require('../channel_api'); -var util = require('./util'); -var succeed = util.succeed, fail = util.fail; +var assert = require("assert"); +var api = require("../channel_api"); +var util = require("./util"); +var succeed = util.succeed, + fail = util.fail; var schedule = util.schedule; var randomString = util.randomString; -var Promise = require('bluebird'); -var Buffer = require('safe-buffer').Buffer; +var Buffer = require("safe-buffer").Buffer; -var URL = process.env.URL || 'amqp://localhost'; +var URL = process.env.URL || "amqp://localhost"; function connect() { - return api.connect(URL); + return api.connect(URL, {}); } // Expect this promise to fail, and flip the results accordingly. function expectFail(promise) { - return new Promise(function(resolve, reject) { + return new Promise(function (resolve, reject) { return promise.then(reject).catch(resolve); }); } // I'll rely on operations being rejected, rather than the channel // close error, to detect failure. -function ignore () {} +function ignore() {} function ignoreErrors(c) { - c.on('error', ignore); return c; + c.on("error", ignore); + return c; } function logErrors(c) { - c.on('error', console.warn); return c; + c.on("error", console.warn); + return c; } // Run a test with `name`, given a function that takes an open // channel, and returns a promise that is resolved on test success or // rejected on test failure. function channel_test(chmethod, name, chfun) { - test(name, function(done) { - connect(URL).then(logErrors).then(function(c) { - c[chmethod]().then(ignoreErrors).then(chfun) - .then(succeed(done), fail(done)) - // close the connection regardless of what happens with the test - .finally(function() {c.close();}); - }); + test(name, function (done) { + connect(URL) + .then(logErrors) + .then(function (c) { + c[chmethod]() + .then(ignoreErrors) + .then(chfun) + .then(succeed(done), fail(done)) + // close the connection regardless of what happens with the test + .finally(function () { + c.close(); + }); + }); }); } -var chtest = channel_test.bind(null, 'createChannel'); +var chtest = channel_test.bind(null, "createChannel"); -suite("connect", function() { - -test("at all", function(done) { - connect(URL).then(function(c) { - return c.close() - ;}).then(succeed(done), fail(done)); -}); - -chtest("create channel", ignore); // i.e., just don't bork +suite("connect", function () { + test("at all", function (done) { + connect(URL) + .then(function (c) { + return c.close(); + }) + .then(succeed(done), fail(done)); + }); + chtest("create channel", ignore); // i.e., just don't bork }); -var QUEUE_OPTS = {durable: false}; -var EX_OPTS = {durable: false}; +var QUEUE_OPTS = { durable: false }; +var EX_OPTS = { durable: false }; -suite("assert, check, delete", function() { +suite("assert, check, delete", function () { + chtest("assert and check queue", function (ch) { + return ch.assertQueue("test.check-queue", QUEUE_OPTS).then(function (qok) { + return ch.checkQueue("test.check-queue"); + }); + }); -chtest("assert and check queue", function(ch) { - return ch.assertQueue('test.check-queue', QUEUE_OPTS) - .then(function(qok) { - return ch.checkQueue('test.check-queue'); + chtest("assert and check exchange", function (ch) { + return ch.assertExchange("test.check-exchange", "direct", EX_OPTS).then(function (eok) { + assert.equal("test.check-exchange", eok.exchange); + return ch.checkExchange("test.check-exchange"); }); -}); + }); -chtest("assert and check exchange", function(ch) { - return ch.assertExchange('test.check-exchange', 'direct', EX_OPTS) - .then(function(eok) { - assert.equal('test.check-exchange', eok.exchange); - return ch.checkExchange('test.check-exchange'); + chtest("fail on reasserting queue with different options", function (ch) { + var q = "test.reassert-queue"; + return ch.assertQueue(q, { durable: false, autoDelete: true }).then(function () { + return expectFail(ch.assertQueue(q, { durable: false, autoDelete: false })); }); -}); + }); -chtest("fail on reasserting queue with different options", - function(ch) { - var q = 'test.reassert-queue'; - return ch.assertQueue( - q, {durable: false, autoDelete: true}) - .then(function() { - return expectFail( - ch.assertQueue(q, {durable: false, - autoDelete: false})); - }); - }); - -chtest("fail on checking a queue that's not there", function(ch) { - return expectFail(ch.checkQueue('test.random-' + randomString())); -}); + chtest("fail on checking a queue that's not there", function (ch) { + return expectFail(ch.checkQueue("test.random-" + randomString())); + }); -chtest("fail on checking an exchange that's not there", function(ch) { - return expectFail(ch.checkExchange('test.random-' + randomString())); -}); + chtest("fail on checking an exchange that's not there", function (ch) { + return expectFail(ch.checkExchange("test.random-" + randomString())); + }); -chtest("fail on reasserting exchange with different type", - function(ch) { - var ex = 'test.reassert-ex'; - return ch.assertExchange(ex, 'fanout', EX_OPTS) - .then(function() { - return expectFail( - ch.assertExchange(ex, 'direct', EX_OPTS)); - }); - }); - -chtest("channel break on publishing to non-exchange", function(ch) { - return new Promise(function(resolve) { - ch.on('error', resolve); - ch.publish(randomString(), '', Buffer.from('foobar')); + chtest("fail on reasserting exchange with different type", function (ch) { + var ex = "test.reassert-ex"; + return ch.assertExchange(ex, "fanout", EX_OPTS).then(function () { + return expectFail(ch.assertExchange(ex, "direct", EX_OPTS)); + }); }); -}); -chtest("delete queue", function(ch) { - var q = 'test.delete-queue'; - return Promise.join( - ch.assertQueue(q, QUEUE_OPTS), - ch.checkQueue(q)) - .then(function() { - return ch.deleteQueue(q);}) - .then(function() { - return expectFail(ch.checkQueue(q));}); -}); + chtest("channel break on publishing to non-exchange", function (ch) { + return new Promise(function (resolve) { + ch.on("error", resolve); + ch.publish(randomString(), "", Buffer.from("foobar")); + }); + }); -chtest("delete exchange", function(ch) { - var ex = 'test.delete-exchange'; - return Promise.join( - ch.assertExchange(ex, 'fanout', EX_OPTS), - ch.checkExchange(ex)) - .then(function() { - return ch.deleteExchange(ex);}) - .then(function() { - return expectFail(ch.checkExchange(ex));}); -}); + chtest("delete queue", function (ch) { + var q = "test.delete-queue"; + return Promise.all([ch.assertQueue(q, QUEUE_OPTS), ch.checkQueue(q)]) + .then(function () { + return ch.deleteQueue(q); + }) + .then(function () { + return expectFail(ch.checkQueue(q)); + }); + }); + chtest("delete exchange", function (ch) { + var ex = "test.delete-exchange"; + return Promise.all([ch.assertExchange(ex, "fanout", EX_OPTS), ch.checkExchange(ex)]) + .then(function () { + return ch.deleteExchange(ex); + }) + .then(function () { + return expectFail(ch.checkExchange(ex)); + }); + }); }); // Wait for the queue to meet the condition; useful for waiting for // messages to arrive, for example. function waitForQueue(q, condition) { - return connect(URL).then(function(c) { - return c.createChannel() - .then(function(ch) { - return ch.checkQueue(q).then(function(qok) { - function check() { - return ch.checkQueue(q).then(function(qok) { - if (condition(qok)) { - c.close(); - return qok; - } - else schedule(check); - }); - } - return check(); - }); + return connect(URL).then(function (c) { + return c.createChannel().then(function (ch) { + return ch.checkQueue(q).then(function (qok) { + function check() { + return ch.checkQueue(q).then(function (qok) { + if (condition(qok)) { + c.close(); + return qok; + } else schedule(check); + }); + } + return check(); }); + }); }); } // Return a promise that resolves when the queue has at least `num` // messages. If num is not supplied its assumed to be 1. function waitForMessages(q, num) { - var min = (num === undefined) ? 1 : num; - return waitForQueue(q, function(qok) { + var min = num === undefined ? 1 : num; + return waitForQueue(q, function (qok) { return qok.messageCount >= min; }); } -suite("sendMessage", function() { - -// publish different size messages -chtest("send to queue and get from queue", function(ch) { - var q = 'test.send-to-q'; - var msg = randomString(); - return Promise.join(ch.assertQueue(q, QUEUE_OPTS), ch.purgeQueue(q)) - .then(function() { - ch.sendToQueue(q, Buffer.from(msg)); - return waitForMessages(q); - }) - .then(function() { - return ch.get(q, {noAck: true}); - }) - .then(function(m) { - assert(m); - assert.equal(msg, m.content.toString()); - }); -}); - -chtest("send (and get) zero content to queue", function(ch) { - var q = 'test.send-to-q'; - var msg = Buffer.alloc(0); - return Promise.join( - ch.assertQueue(q, QUEUE_OPTS), - ch.purgeQueue(q)) - .then(function() { - ch.sendToQueue(q, msg); - return waitForMessages(q);}) - .then(function() { - return ch.get(q, {noAck: true});}) - .then(function(m) { - assert(m); - assert.deepEqual(msg, m.content); - }); -}); +suite("sendMessage", function () { + // publish different size messages + chtest("send to queue and get from queue", function (ch) { + var q = "test.send-to-q"; + var msg = randomString(); + return Promise.all([ch.assertQueue(q, QUEUE_OPTS), ch.purgeQueue(q)]) + .then(function () { + ch.sendToQueue(q, Buffer.from(msg)); + return waitForMessages(q); + }) + .then(function () { + return ch.get(q, { noAck: true }); + }) + .then(function (m) { + assert(m); + assert.equal(msg, m.content.toString()); + }); + }); + chtest("send (and get) zero content to queue", function (ch) { + var q = "test.send-to-q"; + var msg = Buffer.alloc(0); + return Promise.all([ch.assertQueue(q, QUEUE_OPTS), ch.purgeQueue(q)]) + .then(function () { + ch.sendToQueue(q, msg); + return waitForMessages(q); + }) + .then(function () { + return ch.get(q, { noAck: true }); + }) + .then(function (m) { + assert(m); + assert.deepEqual(msg, m.content); + }); + }); }); -suite("binding, consuming", function() { - -// bind, publish, get -chtest("route message", function(ch) { - var ex = 'test.route-message'; - var q = 'test.route-message-q'; - var msg = randomString(); - - return Promise.join( - ch.assertExchange(ex, 'fanout', EX_OPTS), - ch.assertQueue(q, QUEUE_OPTS), - ch.purgeQueue(q), - ch.bindQueue(q, ex, '', {})) - .then(function() { - ch.publish(ex, '', Buffer.from(msg)); - return waitForMessages(q);}) - .then(function() { - return ch.get(q, {noAck: true});}) - .then(function(m) { - assert(m); - assert.equal(msg, m.content.toString()); - }); -}); +suite("binding, consuming", function () { + // bind, publish, get + chtest("route message", function (ch) { + var ex = "test.route-message"; + var q = "test.route-message-q"; + var msg = randomString(); + + return Promise.all([ch.assertExchange(ex, "fanout", EX_OPTS), ch.assertQueue(q, QUEUE_OPTS), ch.purgeQueue(q), ch.bindQueue(q, ex, "", {})]) + .then(function () { + ch.publish(ex, "", Buffer.from(msg)); + return waitForMessages(q); + }) + .then(function () { + return ch.get(q, { noAck: true }); + }) + .then(function (m) { + assert(m); + assert.equal(msg, m.content.toString()); + }); + }); -// send to queue, purge, get-empty -chtest("purge queue", function(ch) { - var q = 'test.purge-queue'; - return ch.assertQueue(q, {durable: false}) - .then(function() { - ch.sendToQueue(q, Buffer.from('foobar')); - return waitForMessages(q);}) - .then(function() { - ch.purgeQueue(q); - return ch.get(q, {noAck: true});}) - .then(function(m) { - assert(!m); // get-empty - }); -}); + // send to queue, purge, get-empty + chtest("purge queue", function (ch) { + var q = "test.purge-queue"; + return ch + .assertQueue(q, { durable: false }) + .then(function () { + ch.sendToQueue(q, Buffer.from("foobar")); + return waitForMessages(q); + }) + .then(function () { + ch.purgeQueue(q); + return ch.get(q, { noAck: true }); + }) + .then(function (m) { + assert(!m); // get-empty + }); + }); -// bind again, unbind, publish, get-empty -chtest("unbind queue", function(ch) { - var ex = 'test.unbind-queue-ex'; - var q = 'test.unbind-queue'; - var viabinding = randomString(); - var direct = randomString(); - - return Promise.join( - ch.assertExchange(ex, 'fanout', EX_OPTS), - ch.assertQueue(q, QUEUE_OPTS), - ch.purgeQueue(q), - ch.bindQueue(q, ex, '', {})) - .then(function() { - ch.publish(ex, '', Buffer.from('foobar')); - return waitForMessages(q);}) - .then(function() { // message got through! - return ch.get(q, {noAck:true}) - .then(function(m) {assert(m);});}) - .then(function() { - return ch.unbindQueue(q, ex, '', {});}) - .then(function() { - // via the no-longer-existing binding - ch.publish(ex, '', Buffer.from(viabinding)); - // direct to the queue - ch.sendToQueue(q, Buffer.from(direct)); - return waitForMessages(q);}) - .then(function() {return ch.get(q)}) - .then(function(m) { - // the direct to queue message got through, the via-binding - // message (sent first) did not - assert.equal(direct, m.content.toString()); - }); -}); + // bind again, unbind, publish, get-empty + chtest("unbind queue", function (ch) { + var ex = "test.unbind-queue-ex"; + var q = "test.unbind-queue"; + var viabinding = randomString(); + var direct = randomString(); + + return Promise.all([ch.assertExchange(ex, "fanout", EX_OPTS), ch.assertQueue(q, QUEUE_OPTS), ch.purgeQueue(q), ch.bindQueue(q, ex, "", {})]) + .then(function () { + ch.publish(ex, "", Buffer.from("foobar")); + return waitForMessages(q); + }) + .then(function () { + // message got through! + return ch.get(q, { noAck: true }).then(function (m) { + assert(m); + }); + }) + .then(function () { + return ch.unbindQueue(q, ex, "", {}); + }) + .then(function () { + // via the no-longer-existing binding + ch.publish(ex, "", Buffer.from(viabinding)); + // direct to the queue + ch.sendToQueue(q, Buffer.from(direct)); + return waitForMessages(q); + }) + .then(function () { + return ch.get(q); + }) + .then(function (m) { + // the direct to queue message got through, the via-binding + // message (sent first) did not + assert.equal(direct, m.content.toString()); + }); + }); -// To some extent this is now just testing semantics of the server, -// but we can at least try out a few settings, and consume. -chtest("consume via exchange-exchange binding", function(ch) { - var ex1 = 'test.ex-ex-binding1', ex2 = 'test.ex-ex-binding2'; - var q = 'test.ex-ex-binding-q'; - var rk = 'test.routing.key', msg = randomString(); - return Promise.join( - ch.assertExchange(ex1, 'direct', EX_OPTS), - ch.assertExchange(ex2, 'fanout', - {durable: false, internal: true}), - ch.assertQueue(q, QUEUE_OPTS), - ch.purgeQueue(q), - ch.bindExchange(ex2, ex1, rk, {}), - ch.bindQueue(q, ex2, '', {})) - .then(function() { - return new Promise(function(resolve, reject) { + // To some extent this is now just testing semantics of the server, + // but we can at least try out a few settings, and consume. + chtest("consume via exchange-exchange binding", function (ch) { + var ex1 = "test.ex-ex-binding1", + ex2 = "test.ex-ex-binding2"; + var q = "test.ex-ex-binding-q"; + var rk = "test.routing.key", + msg = randomString(); + return Promise.all([ch.assertExchange(ex1, "direct", EX_OPTS), ch.assertExchange(ex2, "fanout", { durable: false, internal: true }), ch.assertQueue(q, QUEUE_OPTS), ch.purgeQueue(q), ch.bindExchange(ex2, ex1, rk, {}), ch.bindQueue(q, ex2, "", {})]).then(function () { + return new Promise(function (resolve, reject) { function delivery(m) { if (m.content.toString() === msg) resolve(); else reject(new Error("Wrong message")); } - ch.consume(q, delivery, {noAck: true}) - .then(function() { - ch.publish(ex1, rk, Buffer.from(msg)); - }); + ch.consume(q, delivery, { noAck: true }).then(function () { + ch.publish(ex1, rk, Buffer.from(msg)); + }); }); }); -}); + }); -// bind again, unbind, publish, get-empty -chtest("unbind exchange", function(ch) { - var source = 'test.unbind-ex-source'; - var dest = 'test.unbind-ex-dest'; - var q = 'test.unbind-ex-queue'; - var viabinding = randomString(); - var direct = randomString(); - - return Promise.join( - ch.assertExchange(source, 'fanout', EX_OPTS), - ch.assertExchange(dest, 'fanout', EX_OPTS), - ch.assertQueue(q, QUEUE_OPTS), - ch.purgeQueue(q), - ch.bindExchange(dest, source, '', {}), - ch.bindQueue(q, dest, '', {})) - .then(function() { - ch.publish(source, '', Buffer.from('foobar')); - return waitForMessages(q);}) - .then(function() { // message got through! - return ch.get(q, {noAck:true}) - .then(function(m) {assert(m);});}) - .then(function() { - return ch.unbindExchange(dest, source, '', {});}) - .then(function() { - // via the no-longer-existing binding - ch.publish(source, '', Buffer.from(viabinding)); - // direct to the queue - ch.sendToQueue(q, Buffer.from(direct)); - return waitForMessages(q);}) - .then(function() {return ch.get(q)}) - .then(function(m) { - // the direct to queue message got through, the via-binding - // message (sent first) did not - assert.equal(direct, m.content.toString()); + // bind again, unbind, publish, get-empty + chtest("unbind exchange", function (ch) { + var source = "test.unbind-ex-source"; + var dest = "test.unbind-ex-dest"; + var q = "test.unbind-ex-queue"; + var viabinding = randomString(); + var direct = randomString(); + + return Promise.all([ch.assertExchange(source, "fanout", EX_OPTS), ch.assertExchange(dest, "fanout", EX_OPTS), ch.assertQueue(q, QUEUE_OPTS), ch.purgeQueue(q), ch.bindExchange(dest, source, "", {}), ch.bindQueue(q, dest, "", {})]) + .then(function () { + ch.publish(source, "", Buffer.from("foobar")); + return waitForMessages(q); + }) + .then(function () { + // message got through! + return ch.get(q, { noAck: true }).then(function (m) { + assert(m); + }); + }) + .then(function () { + return ch.unbindExchange(dest, source, "", {}); + }) + .then(function () { + // via the no-longer-existing binding + ch.publish(source, "", Buffer.from(viabinding)); + // direct to the queue + ch.sendToQueue(q, Buffer.from(direct)); + return waitForMessages(q); + }) + .then(function () { + return ch.get(q); + }) + .then(function (m) { + // the direct to queue message got through, the via-binding + // message (sent first) did not + assert.equal(direct, m.content.toString()); + }); + }); + + // This is a bit convoluted. Sorry. + chtest("cancel consumer", function (ch) { + var q = "test.consumer-cancel"; + var ctag; + var recv1 = new Promise(function (resolve, reject) { + Promise.all([ + ch.assertQueue(q, QUEUE_OPTS), + ch.purgeQueue(q), + // My callback is 'resolve the promise in `arrived`' + ch.consume(q, resolve, { noAck: true }).then(function (ok) { + ctag = ok.consumerTag; + ch.sendToQueue(q, Buffer.from("foo")); + }), + ]); }); -}); -// This is a bit convoluted. Sorry. -chtest("cancel consumer", function(ch) { - var q = 'test.consumer-cancel'; - var ctag; - var recv1 = new Promise(function (resolve, reject) { - Promise.join( - ch.assertQueue(q, QUEUE_OPTS), - ch.purgeQueue(q), - // My callback is 'resolve the promise in `arrived`' - ch.consume(q, resolve, {noAck:true}) - .then(function(ok) { - ctag = ok.consumerTag; - ch.sendToQueue(q, Buffer.from('foo')); - })); - }); - - // A message should arrive because of the consume - return recv1.then(function() { - var recv2 = Promise.join( - ch.cancel(ctag).then(function() { - return ch.sendToQueue(q, Buffer.from('bar')); - }), - // but check a message did arrive in the queue - waitForMessages(q)) - .then(function() { - return ch.get(q, {noAck:true}); - }) - .then(function(m) { - // I'm going to reject it, because I flip succeed/fail - // just below - if (m.content.toString() === 'bar') { - throw new Error(); - } - }); + // A message should arrive because of the consume + return recv1.then(function () { + var recv2 = Promise.all([ + ch.cancel(ctag).then(function () { + return ch.sendToQueue(q, Buffer.from("bar")); + }), + // but check a message did arrive in the queue + waitForMessages(q), + ]) + .then(function () { + return ch.get(q, { noAck: true }); + }) + .then(function (m) { + // I'm going to reject it, because I flip succeed/fail + // just below + if (m.content.toString() === "bar") { + throw new Error(); + } + }); return expectFail(recv2); + }); }); -}); -chtest("cancelled consumer", function(ch) { - var q = 'test.cancelled-consumer'; - return new Promise(function(resolve, reject) { - return Promise.join( - ch.assertQueue(q), - ch.purgeQueue(q), - ch.consume(q, function(msg) { - if (msg === null) resolve(); - else reject(new Error('Message not expected')); - })) - .then(function() { + chtest("cancelled consumer", function (ch) { + var q = "test.cancelled-consumer"; + return new Promise(function (resolve, reject) { + return Promise.all([ + ch.assertQueue(q), + ch.purgeQueue(q), + ch.consume(q, function (msg) { + if (msg === null) resolve(); + else reject(new Error("Message not expected")); + }), + ]).then(function () { return ch.deleteQueue(q); }); + }); }); -}); -// ack, by default, removes a single message from the queue -chtest("ack", function(ch) { - var q = 'test.ack'; - var msg1 = randomString(), msg2 = randomString(); - - return Promise.join( - ch.assertQueue(q, QUEUE_OPTS), - ch.purgeQueue(q)) - .then(function() { - ch.sendToQueue(q, Buffer.from(msg1)); - ch.sendToQueue(q, Buffer.from(msg2)); - return waitForMessages(q, 2); - }) - .then(function() { - return ch.get(q, {noAck: false}) - }) - .then(function(m) { - assert.equal(msg1, m.content.toString()); - ch.ack(m); - // %%% is there a race here? may depend on - // rabbitmq-sepcific semantics - return ch.get(q); - }) - .then(function(m) { - assert(m); - assert.equal(msg2, m.content.toString()); - }); -}); + // ack, by default, removes a single message from the queue + chtest("ack", function (ch) { + var q = "test.ack"; + var msg1 = randomString(), + msg2 = randomString(); + + return Promise.all([ch.assertQueue(q, QUEUE_OPTS), ch.purgeQueue(q)]) + .then(function () { + ch.sendToQueue(q, Buffer.from(msg1)); + ch.sendToQueue(q, Buffer.from(msg2)); + return waitForMessages(q, 2); + }) + .then(function () { + return ch.get(q, { noAck: false }); + }) + .then(function (m) { + assert.equal(msg1, m.content.toString()); + ch.ack(m); + // %%% is there a race here? may depend on + // rabbitmq-sepcific semantics + return ch.get(q); + }) + .then(function (m) { + assert(m); + assert.equal(msg2, m.content.toString()); + }); + }); -// Nack, by default, puts a message back on the queue (where in the -// queue is up to the server) -chtest("nack", function(ch) { - var q = 'test.nack'; - var msg1 = randomString(); - - return Promise.join( - ch.assertQueue(q, QUEUE_OPTS), ch.purgeQueue(q)) - .then(function() { - ch.sendToQueue(q, Buffer.from(msg1)); - return waitForMessages(q);}) - .then(function() { - return ch.get(q, {noAck: false})}) - .then(function(m) { - assert.equal(msg1, m.content.toString()); - ch.nack(m); - return waitForMessages(q);}) - .then(function() { - return ch.get(q);}) - .then(function(m) { - assert(m); - assert.equal(msg1, m.content.toString()); - }); -}); + // Nack, by default, puts a message back on the queue (where in the + // queue is up to the server) + chtest("nack", function (ch) { + var q = "test.nack"; + var msg1 = randomString(); -// reject is a near-synonym for nack, the latter of which is not -// available in earlier RabbitMQ (or in AMQP proper). -chtest("reject", function(ch) { - var q = 'test.reject'; - var msg1 = randomString(); - - return Promise.join( - ch.assertQueue(q, QUEUE_OPTS), ch.purgeQueue(q)) - .then(function() { - ch.sendToQueue(q, Buffer.from(msg1)); - return waitForMessages(q);}) - .then(function() { - return ch.get(q, {noAck: false})}) - .then(function(m) { - assert.equal(msg1, m.content.toString()); - ch.reject(m); - return waitForMessages(q);}) - .then(function() { - return ch.get(q);}) - .then(function(m) { - assert(m); - assert.equal(msg1, m.content.toString()); - }); -}); + return Promise.all([ch.assertQueue(q, QUEUE_OPTS), ch.purgeQueue(q)]) + .then(function () { + ch.sendToQueue(q, Buffer.from(msg1)); + return waitForMessages(q); + }) + .then(function () { + return ch.get(q, { noAck: false }); + }) + .then(function (m) { + assert.equal(msg1, m.content.toString()); + ch.nack(m); + return waitForMessages(q); + }) + .then(function () { + return ch.get(q); + }) + .then(function (m) { + assert(m); + assert.equal(msg1, m.content.toString()); + }); + }); -chtest("prefetch", function(ch) { - var q = 'test.prefetch'; - return Promise.join( - ch.assertQueue(q, QUEUE_OPTS), ch.purgeQueue(q), - ch.prefetch(1)) - .then(function() { - ch.sendToQueue(q, Buffer.from('foobar')); - ch.sendToQueue(q, Buffer.from('foobar')); - return waitForMessages(q, 2); - }) - .then(function() { - return new Promise(function(resolve) { - var messageCount = 0; - function receive(msg) { - ch.ack(msg); - if (++messageCount > 1) { - resolve(messageCount); - } - } - return ch.consume(q, receive, {noAck: false}) + // reject is a near-synonym for nack, the latter of which is not + // available in earlier RabbitMQ (or in AMQP proper). + chtest("reject", function (ch) { + var q = "test.reject"; + var msg1 = randomString(); + + return Promise.all([ch.assertQueue(q, QUEUE_OPTS), ch.purgeQueue(q)]) + .then(function () { + ch.sendToQueue(q, Buffer.from(msg1)); + return waitForMessages(q); + }) + .then(function () { + return ch.get(q, { noAck: false }); + }) + .then(function (m) { + assert.equal(msg1, m.content.toString()); + ch.reject(m); + return waitForMessages(q); + }) + .then(function () { + return ch.get(q); + }) + .then(function (m) { + assert(m); + assert.equal(msg1, m.content.toString()); }); - }) - .then(function(c) { - return assert.equal(2, c); - }); -}); + }); -chtest('close', function(ch) { - // Resolving promise guarantees - // channel is closed - return ch.close(); -}); + chtest("prefetch", function (ch) { + var q = "test.prefetch"; + return Promise.all([ch.assertQueue(q, QUEUE_OPTS), ch.purgeQueue(q), ch.prefetch(1)]) + .then(function () { + ch.sendToQueue(q, Buffer.from("foobar")); + ch.sendToQueue(q, Buffer.from("foobar")); + return waitForMessages(q, 2); + }) + .then(function () { + return new Promise(function (resolve) { + var messageCount = 0; + function receive(msg) { + ch.ack(msg); + if (++messageCount > 1) { + resolve(messageCount); + } + } + return ch.consume(q, receive, { noAck: false }); + }); + }) + .then(function (c) { + return assert.equal(2, c); + }); + }); + chtest("close", function (ch) { + // Resolving promise guarantees + // channel is closed + return ch.close(); + }); }); -var confirmtest = channel_test.bind(null, 'createConfirmChannel'); +var confirmtest = channel_test.bind(null, "createConfirmChannel"); -suite("confirms", function() { - -confirmtest('message is confirmed', function(ch) { - var q = 'test.confirm-message'; - return Promise.join( - ch.assertQueue(q, QUEUE_OPTS), ch.purgeQueue(q)) - .then(function() { - return ch.sendToQueue(q, Buffer.from('bleep')); +suite("confirms", function () { + confirmtest("message is confirmed", function (ch) { + var q = "test.confirm-message"; + return Promise.all([ch.assertQueue(q, QUEUE_OPTS), ch.purgeQueue(q)]).then(function () { + return ch.sendToQueue(q, Buffer.from("bleep")); }); -}); + }); -// Usually one can provoke the server into confirming more than one -// message in an ack by simply sending a few messages in quick -// succession; a bit unscientific I know. Luckily we can eavesdrop on -// the acknowledgements coming through to see if we really did get a -// multi-ack. -confirmtest('multiple confirms', function(ch) { - var q = 'test.multiple-confirms'; - return Promise.join( - ch.assertQueue(q, QUEUE_OPTS), ch.purgeQueue(q)) - .then(function() { + // Usually one can provoke the server into confirming more than one + // message in an ack by simply sending a few messages in quick + // succession; a bit unscientific I know. Luckily we can eavesdrop on + // the acknowledgements coming through to see if we really did get a + // multi-ack. + confirmtest("multiple confirms", function (ch) { + var q = "test.multiple-confirms"; + return Promise.all([ch.assertQueue(q, QUEUE_OPTS), ch.purgeQueue(q)]).then(function () { var multipleRainbows = false; - ch.on('ack', function(a) { + ch.on("ack", function (a) { if (a.multiple) multipleRainbows = true; }); @@ -550,20 +539,17 @@ confirmtest('multiple confirms', function(ch) { var cs = []; function sendAndPushPromise() { - var conf = Promise.fromCallback(function(cb) { - return ch.sendToQueue(q, Buffer.from('bleep'), {}, cb); + var conf = Promise.fromCallback(function (cb) { + return ch.sendToQueue(q, Buffer.from("bleep"), {}, cb); }); cs.push(conf); } - for (var i=0; i < num; i++) sendAndPushPromise(); + for (var i = 0; i < num; i++) sendAndPushPromise(); - return Promise.all(cs).then(function() { + return Promise.all(cs).then(function () { if (multipleRainbows) return true; - else if (num > 500) throw new Error( - "Couldn't provoke the server" + - " into multi-acking with " + num + - " messages; giving up"); + else if (num > 500) throw new Error("Couldn't provoke the server" + " into multi-acking with " + num + " messages; giving up"); else { //console.warn("Failed with " + num + "; trying " + num * 2); return prod(num * 2); @@ -572,26 +558,31 @@ confirmtest('multiple confirms', function(ch) { } return prod(5); }); -}); + }); -confirmtest('wait for confirms', function(ch) { - for (var i=0; i < 1000; i++) { - ch.publish('', '', Buffer.from('foobar'), {}); - } - return ch.waitForConfirms(); -}) - -confirmtest('works when channel is closed', function(ch) { - for (var i=0; i < 1000; i++) { - ch.publish('', '', Buffer.from('foobar'), {}); - } - return ch.close().then(function () { - return ch.waitForConfirms() - }).then(function () { - assert.strictEqual(true, false, 'Wait should have failed.') - }, function (e) { - assert.strictEqual(e.message, 'channel closed') + confirmtest("wait for confirms", function (ch) { + for (var i = 0; i < 1000; i++) { + ch.publish("", "", Buffer.from("foobar"), {}); + } + return ch.waitForConfirms(); }); -}); + confirmtest("works when channel is closed", function (ch) { + for (var i = 0; i < 1000; i++) { + ch.publish("", "", Buffer.from("foobar"), {}); + } + return ch + .close() + .then(function () { + return ch.waitForConfirms(); + }) + .then( + function () { + assert.strictEqual(true, false, "Wait should have failed."); + }, + function (e) { + assert.strictEqual(e.message, "channel closed"); + }, + ); + }); }); diff --git a/test/util.js b/test/util.js index a41a8eb3..8bef18e5 100644 --- a/test/util.js +++ b/test/util.js @@ -1,24 +1,19 @@ -'use strict'; +"use strict"; -var Promise = require('bluebird'); -var crypto = require('crypto'); -var Connection = require('../lib/connection').Connection; -var PassThrough = - require('stream').PassThrough || - require('readable-stream/passthrough'); -var defs = require('../lib/defs'); -var assert = require('assert'); +var crypto = require("crypto"); +var Connection = require("../lib/connection").Connection; +var PassThrough = require("stream").PassThrough || require("readable-stream/passthrough"); +var defs = require("../lib/defs"); +var assert = require("assert"); -var schedule = (typeof setImmediate === 'function') ? - setImmediate : process.nextTick; +var schedule = typeof setImmediate === "function" ? setImmediate : process.nextTick; function randomString() { - var hash = crypto.createHash('sha1'); + var hash = crypto.createHash("sha1"); hash.update(crypto.randomBytes(64)); - return hash.digest('base64'); + return hash.digest("base64"); } - // Set up a socket pair {client, server}, such that writes to the // client are readable from the server, and writes to the server are // readable at the client. @@ -47,7 +42,7 @@ function socketPair() { server.end = end.bind(client); client.end = end.bind(server); - return {client: client, server: server}; + return { client: client, server: server }; } function runServer(socket, run) { @@ -63,34 +58,27 @@ function runServer(socket, run) { function send(id, fields, channel, content) { channel = channel || 0; if (content) { - schedule(function() { - frames.sendMessage(channel, id, fields, - defs.BasicProperties, fields, - content); + schedule(function () { + frames.sendMessage(channel, id, fields, defs.BasicProperties, fields, content); }); - } - else { - schedule(function() { + } else { + schedule(function () { frames.sendMethod(channel, id, fields); }); } } function wait(method) { - return function() { - return new Promise(function(resolve, reject) { + return function () { + return new Promise(function (resolve, reject) { if (method) { - frames.step(function(e, f) { + frames.step(function (e, f) { if (e !== null) return reject(e); - if (f.id === method) - resolve(f); - else - reject(new Error("Expected method: " + method + - ", got " + f.id)); + if (f.id === method) resolve(f); + else reject(new Error("Expected method: " + method + ", got " + f.id)); }); - } - else { - frames.step(function(e, f) { + } else { + frames.step(function (e, f) { if (e !== null) return reject(e); else resolve(f); }); @@ -104,14 +92,16 @@ function runServer(socket, run) { // Produce a callback that will complete the test successfully function succeed(done) { - return function() { done(); } + return function () { + done(); + }; } // Produce a callback that will complete the test successfully // only if the value is an object, it has the specified // attribute, and its value is equals to the expected value function succeedIfAttributeEquals(attribute, value, done) { - return function(object) { + return function (object) { if (object && !(object instanceof Error) && value === object[attribute]) { return done(); } @@ -124,10 +114,10 @@ function succeedIfAttributeEquals(attribute, value, done) { // (to be used as a failure continuation) or any other value (to be // used as a success continuation when failure is expected) function fail(done) { - return function(err) { + return function (err) { if (err instanceof Error) done(err); else done(new Error("Expected to fail, instead got " + err.toString())); - } + }; } // Create a function that will call done once it's been called itself @@ -136,12 +126,11 @@ function fail(done) { function latch(count, done) { var awaiting = count; var alive = true; - return function(err) { + return function (err) { if (err instanceof Error && alive) { alive = false; done(err); - } - else { + } else { awaiting--; if (awaiting === 0 && alive) { alive = false; @@ -157,14 +146,15 @@ function completes(thunk, done) { try { thunk(); done(); + } catch (e) { + done(e); } - catch (e) { done(e); } } // Construct a Node.JS-style callback from a success continuation and // an error continuation function kCallback(k, ek) { - return function(err, val) { + return function (err, val) { if (err === null) k && k(val); else ek && ek(err); }; @@ -172,37 +162,37 @@ function kCallback(k, ek) { // A noddy way to make tests depend on the node version. function versionGreaterThan(actual, spec) { + function int(e) { + return parseInt(e); + } - function int(e) { return parseInt(e); } - - var version = actual.split('.').map(int); - var desired = spec.split('.').map(int); - for (var i=0; i < desired.length; i++) { - var a = version[i], b = desired[i]; + var version = actual.split(".").map(int); + var desired = spec.split(".").map(int); + for (var i = 0; i < desired.length; i++) { + var a = version[i], + b = desired[i]; if (a != b) return a > b; } return false; } -suite('versionGreaterThan', function() { - -test('full spec', function() { - assert(versionGreaterThan('0.8.26', '0.6.12')); - assert(versionGreaterThan('0.8.26', '0.8.21')); -}); +suite("versionGreaterThan", function () { + test("full spec", function () { + assert(versionGreaterThan("0.8.26", "0.6.12")); + assert(versionGreaterThan("0.8.26", "0.8.21")); + }); -test('partial spec', function() { - assert(versionGreaterThan('0.9.12', '0.8')); -}); - -test('not greater', function() { - assert(!versionGreaterThan('0.8.12', '0.8.26')); - assert(!versionGreaterThan('0.6.2', '0.6.12')); - assert(!versionGreaterThan('0.8.29', '0.8')); -}); + test("partial spec", function () { + assert(versionGreaterThan("0.9.12", "0.8")); + }); -test + test("not greater", function () { + assert(!versionGreaterThan("0.8.12", "0.8.26")); + assert(!versionGreaterThan("0.6.2", "0.6.12")); + assert(!versionGreaterThan("0.8.29", "0.8")); + }); + test; }); module.exports = { @@ -216,5 +206,5 @@ module.exports = { kCallback: kCallback, schedule: schedule, randomString: randomString, - versionGreaterThan: versionGreaterThan + versionGreaterThan: versionGreaterThan, };