From 5c5ca3b265e4a3307d0943334c77283150bae0e5 Mon Sep 17 00:00:00 2001 From: Charlike Mike Reagent Date: Wed, 29 Jan 2020 10:57:51 +0200 Subject: [PATCH 01/19] feat: introduce Plugins API, fix tests Signed-off-by: Charlike Mike Reagent --- README.md | 62 ++++++ src/Formidable.js | 306 +++++------------------------- src/parsers/Dummy.js | 3 +- src/parsers/JSON.js | 3 +- src/parsers/Multipart.js | 3 +- src/parsers/OctetStream.js | 7 +- src/parsers/Querystring.js | 5 +- src/plugins/json.js | 36 ++++ src/plugins/multipart.js | 153 +++++++++++++++ src/plugins/octetstream.js | 74 ++++++++ src/plugins/querystring.js | 36 ++++ test/integration/test-fixtures.js | 2 +- test/unit/test-incoming-form.js | 52 ++--- 13 files changed, 452 insertions(+), 290 deletions(-) create mode 100644 src/plugins/json.js create mode 100644 src/plugins/multipart.js create mode 100644 src/plugins/octetstream.js create mode 100644 src/plugins/querystring.js diff --git a/README.md b/README.md index 96ba65a3..f28ccd0b 100644 --- a/README.md +++ b/README.md @@ -167,6 +167,7 @@ See it's defaults in [src/Formidable.js](./src/Formidable.js#L14-L22) (the `DEFA - `options.maxFields` **{number}** - default `1000`; limit the number of fields that the Querystring parser will decode, set 0 for unlimited - `options.hash` **{boolean}** - default `false`; include checksums calculated for incoming files, set this to some hash algorithm, see [crypto.createHash](https://nodejs.org/api/crypto.html#crypto_crypto_createhash_algorithm_options) for available algorithms - `options.multiples` **{boolean}** - default `false`; when you call the `.parse` method, the `files` argument (of the callback) will contain arrays of files for inputs which submit multiple files using the HTML5 `multiple` attribute. Also, the `fields` argument will contain arrays of values for fields that have names ending with '[]'. +- `options.enabledPlugins` **{array}** - default `['octetstream', 'urlencoded', 'multipart', 'json']`; list of enabled built-in plugins, for custom ones use `form.use(() => {})` before the `.parse()` method, see [plugins](#plugins) _**Note:** If this value is exceeded, an `'error'` event is emitted._ @@ -250,6 +251,67 @@ form.on('data', ({ name, key, value, buffer, start, end, ...more }) => { }); ``` +### .use(plugin: Plugin) + +A method that allows you to extend the Formidable library. By default we include 4 plugins, +which esentially are adapters to plug the different built-in parsers. + +**The plugins added by this method are always enabled.** + +_See [src/plugins/](./src/plugins/) for more detailed look on default plugins._ + +The `plugin` param has such signature: + +```typescript +function(formidable: Formidable, options: Options): void; +``` + +The architecture is simple. The `plugin` is a function that is passed with +the Formidable instance (the `form` across the README examples) and the options. + +**Note:** the plugin function's `this` context is also the same instance. + +```js +const formidable = require('formidable'); + +const form = formidable({ keepExtensions: true }); + +form.use((self, options) => { + // self === this === form + console.log('woohoo, custom plugin'); + // do your stuff; check `src/plugins` for inspiration +}); + +form.parse(req, (error, fields, files) => { + console.log('done!'); +}); +``` + +**Important to note**, is that inside plugin `this.options`, `self.options` and `options` +MAY or MAY NOT be the same. General best practice is to always use the `this`, so you can +later test your plugin independently and more easily. + +If you want to disable some parsing capabilities of Formidable, you can disable the plugin +which corresponds to the parser. For example, if you want to disable multipart parsing +(so the [src/parsers/Multipart.js](./src/parsers/Multipart.js) which is used in [src/plugins/multipart.js](./src/plugins/multipart.js)), then you can remove it from +the `options.enabledPlugins`, like so + +```js +const { Formidable } = require('formidable'); + +const form = new Formidable({ + hash: 'sha1', + enabledPlugins: ['octetstream', 'querystring', 'json'], +}); +``` + +**Be aware** that the order _MAY_ be important too. The names corresponds 1:1 +to files in [src/plugins/](./src/plugins) folder. + +Pull requests for new built-in plugins MAY be accepted - for example, +more advanced querystring parser. Add your plugin as a new file +in `src/plugins/` folder (lowercased) and follow how the other plugins are made. + ### form.onPart If you want to use Formidable to only handle certain parts for you, you can do something similar. diff --git a/src/Formidable.js b/src/Formidable.js index d4454f7b..f51e2236 100644 --- a/src/Formidable.js +++ b/src/Formidable.js @@ -7,7 +7,6 @@ const os = require('os'); const fs = require('fs'); const path = require('path'); const crypto = require('crypto'); -const { Stream } = require('stream'); const { EventEmitter } = require('events'); const { StringDecoder } = require('string_decoder'); @@ -19,16 +18,12 @@ const DEFAULT_OPTIONS = { encoding: 'utf-8', hash: false, multiples: false, + enabledPlugins: ['octetstream', 'querystring', 'multipart', 'json'], }; const File = require('./File'); - -/** Parsers */ -const JSONParser = require('./parsers/JSON'); const DummyParser = require('./parsers/Dummy'); -const OctetParser = require('./parsers/OctetStream'); const MultipartParser = require('./parsers/Multipart'); -const QuerystringParser = require('./parsers/Querystring'); function hasOwnProp(obj, key) { return Object.prototype.hasOwnProperty.call(obj, key); @@ -40,7 +35,7 @@ class IncomingForm extends EventEmitter { this.error = null; this.ended = false; - Object.assign(this, DEFAULT_OPTIONS, options); + this.options = { ...DEFAULT_OPTIONS, ...options }; this.uploadDir = this.uploadDir || os.tmpdir(); this.headers = null; @@ -53,7 +48,22 @@ class IncomingForm extends EventEmitter { this._flushing = 0; this._fieldsSize = 0; this._fileSize = 0; + this._plugins = []; this.openedFiles = []; + + this.options.enabledPlugins.forEach((pluginName) => { + const plgName = pluginName.toLowerCase(); + // eslint-disable-next-line import/no-dynamic-require, global-require + this.use(require(path.join(__dirname, 'plugins', `${plgName}.js`))); + }); + } + + use(plugin) { + if (typeof plugin !== 'function') { + throw new Error('.use: expect `plugin` to be a function'); + } + this._plugins.push(plugin.bind(this)); + return this; } parse(req, cb) { @@ -93,7 +103,7 @@ class IncomingForm extends EventEmitter { this.on('field', (name, value) => { // TODO: too much nesting - if (this.multiples && name.slice(-2) === '[]') { + if (this.options.multiples && name.slice(-2) === '[]') { const realName = name.slice(0, name.length - 2); if (hasOwnProp(fields, realName)) { if (!Array.isArray(fields[realName])) { @@ -113,7 +123,7 @@ class IncomingForm extends EventEmitter { }); this.on('file', (name, file) => { // TODO: too much nesting - if (this.multiples) { + if (this.options.multiples) { if (hasOwnProp(files, name)) { if (!Array.isArray(files[name])) { files[name] = [files[name]]; @@ -207,10 +217,10 @@ class IncomingForm extends EventEmitter { onPart(part) { // this method can be overwritten by the user - this.handlePart(part); + this._handlePart(part); } - handlePart(part) { + _handlePart(part) { if (part.filename && typeof part.filename !== 'string') { this._error(new Error(`the part.filename should be string when exists`)); return; @@ -228,14 +238,16 @@ class IncomingForm extends EventEmitter { // ? NOTE(@tunnckocore): filename is an empty string when a field? if (!part.mime) { let value = ''; - const decoder = new StringDecoder(part.transferEncoding || this.encoding); + const decoder = new StringDecoder( + part.transferEncoding || this.options.encoding, + ); part.on('data', (buffer) => { this._fieldsSize += buffer.length; - if (this._fieldsSize > this.maxFieldsSize) { + if (this._fieldsSize > this.options.maxFieldsSize) { this._error( new Error( - `maxFieldsSize exceeded, received ${this._fieldsSize} bytes of field data`, + `options.maxFieldsSize exceeded, received ${this._fieldsSize} bytes of field data`, ), ); return; @@ -255,7 +267,7 @@ class IncomingForm extends EventEmitter { path: this._uploadPath(part.filename), name: part.filename, type: part.mime, - hash: this.hash, + hash: this.options.hash, }); this.emit('fileBegin', part.name, file); @@ -265,10 +277,10 @@ class IncomingForm extends EventEmitter { part.on('data', (buffer) => { this._fileSize += buffer.length; - if (this._fileSize > this.maxFileSize) { + if (this._fileSize > this.options.maxFileSize) { this._error( new Error( - `maxFileSize exceeded, received ${this._fileSize} bytes of file data`, + `options.maxFileSize exceeded, received ${this._fileSize} bytes of file data`, ), ); return; @@ -294,7 +306,7 @@ class IncomingForm extends EventEmitter { // eslint-disable-next-line max-statements _parseContentType() { if (this.bytesExpected === 0) { - this._parser = new DummyParser(this); + this._parser = new DummyParser(this, this.options); return; } @@ -303,40 +315,23 @@ class IncomingForm extends EventEmitter { return; } - if (this.headers['content-type'].match(/octet-stream/i)) { - this._initOctetStream(); - return; - } + const results = []; - if (this.headers['content-type'].match(/urlencoded/i)) { - this._initUrlencoded(); - return; - } + // eslint-disable-next-line no-plusplus + for (let idx = 0; idx < this._plugins.length; idx++) { + const plugin = this._plugins[idx].bind(this); - if (this.headers['content-type'].match(/multipart/i)) { - const m = this.headers['content-type'].match( - /boundary=(?:"([^"]+)"|([^;]+))/i, - ); - if (m) { - this._initMultipart(m[1] || m[2]); - } else { - this._error( - new Error('bad content-type header, no multipart boundary'), - ); - } - return; + const res = plugin.call(this, this, this.options); + results.push(res); } - if (this.headers['content-type'].match(/json/i)) { - this._initJSONencoded(); - return; + if (results.length === 0 && results.length !== this._plugins.length) { + this._error( + new Error( + `bad content-type header, unknown content-type: ${this.headers['content-type']}`, + ), + ); } - - this._error( - new Error( - `bad content-type header, unknown content-type: ${this.headers['content-type']}`, - ), - ); } _error(err) { @@ -369,133 +364,10 @@ class IncomingForm extends EventEmitter { } _newParser() { - return new MultipartParser(); + return new MultipartParser(this.options); } - _initMultipart(boundary) { - this.type = 'multipart'; - - const parser = new MultipartParser(); - let headerField; - let headerValue; - let part; - - parser.initWithBoundary(boundary); - - // eslint-disable-next-line max-statements, consistent-return - parser.on('data', ({ name, buffer, start, end }) => { - if (name === 'partBegin') { - part = new Stream(); - part.readable = true; - part.headers = {}; - part.name = null; - part.filename = null; - part.mime = null; - - part.transferEncoding = 'binary'; - part.transferBuffer = ''; - - headerField = ''; - headerValue = ''; - } else if (name === 'headerField') { - headerField += buffer.toString(this.encoding, start, end); - } else if (name === 'headerValue') { - headerValue += buffer.toString(this.encoding, start, end); - } else if (name === 'headerEnd') { - headerField = headerField.toLowerCase(); - part.headers[headerField] = headerValue; - - // matches either a quoted-string or a token (RFC 2616 section 19.5.1) - const m = headerValue.match( - // eslint-disable-next-line no-useless-escape - /\bname=("([^"]*)"|([^\(\)<>@,;:\\"\/\[\]\?=\{\}\s\t/]+))/i, - ); - if (headerField === 'content-disposition') { - if (m) { - part.name = m[2] || m[3] || ''; - } - - part.filename = this._fileName(headerValue); - } else if (headerField === 'content-type') { - part.mime = headerValue; - } else if (headerField === 'content-transfer-encoding') { - part.transferEncoding = headerValue.toLowerCase(); - } - - headerField = ''; - headerValue = ''; - } else if (name === 'headersEnd') { - switch (part.transferEncoding) { - case 'binary': - case '7bit': - case '8bit': { - const dataPropagation = (ctx) => { - if (ctx.name === 'partData') { - part.emit('data', ctx.buffer.slice(ctx.start, ctx.end)); - } - }; - const dataStopPropagation = (ctx) => { - if (ctx.name === 'partEnd') { - part.emit('end'); - parser.off('data', dataPropagation); - parser.off('data', dataStopPropagation); - } - }; - parser.on('data', dataPropagation); - parser.on('data', dataStopPropagation); - break; - } - case 'base64': { - const dataPropagation = (ctx) => { - if (ctx.name === 'partData') { - part.transferBuffer += ctx.buffer - .slice(ctx.start, ctx.end) - .toString('ascii'); - - /* - four bytes (chars) in base64 converts to three bytes in binary - encoding. So we should always work with a number of bytes that - can be divided by 4, it will result in a number of buytes that - can be divided vy 3. - */ - const offset = parseInt(part.transferBuffer.length / 4, 10) * 4; - part.emit( - 'data', - Buffer.from( - part.transferBuffer.substring(0, offset), - 'base64', - ), - ); - part.transferBuffer = part.transferBuffer.substring(offset); - } - }; - const dataStopPropagation = (ctx) => { - if (ctx.name === 'partEnd') { - part.emit('data', Buffer.from(part.transferBuffer, 'base64')); - part.emit('end'); - parser.off('data', dataPropagation); - parser.off('data', dataStopPropagation); - } - }; - parser.on('data', dataPropagation); - parser.on('data', dataStopPropagation); - break; - } - default: - return this._error(new Error('unknown transfer-encoding')); - } - - this.onPart(part); - } else if (name === 'end') { - this.ended = true; - this._maybeEnd(); - } - }); - - this._parser = parser; - } - - _fileName(headerValue) { + _getFileName(headerValue) { // matches either a quoted-string or a token (RFC 2616 section 19.5.1) const m = headerValue.match( // eslint-disable-next-line no-useless-escape @@ -512,99 +384,11 @@ class IncomingForm extends EventEmitter { return filename; } - _initUrlencoded() { - this.type = 'urlencoded'; - - const parser = new QuerystringParser(this.maxFields); - - parser.on('data', ({ key, value }) => { - this.emit('field', key, value); - }); - - parser.once('end', () => { - this.ended = true; - this._maybeEnd(); - }); - - this._parser = parser; - } - - _initOctetStream() { - this.type = 'octet-stream'; - const filename = this.headers['x-file-name']; - const mime = this.headers['content-type']; - - const file = new File({ - path: this._uploadPath(filename), - name: filename, - type: mime, - }); - - this.emit('fileBegin', filename, file); - file.open(); - this.openedFiles.push(file); - this._flushing += 1; - - this._parser = new OctetParser(); - - // Keep track of writes that haven't finished so we don't emit the file before it's done being written - let outstandingWrites = 0; - - this._parser.on('data', (buffer) => { - this.pause(); - outstandingWrites += 1; - - file.write(buffer, () => { - outstandingWrites -= 1; - this.resume(); - - if (this.ended) { - this._parser.emit('doneWritingFile'); - } - }); - }); - - this._parser.on('end', () => { - this._flushing -= 1; - this.ended = true; - - const done = () => { - file.end(() => { - this.emit('file', 'file', file); - this._maybeEnd(); - }); - }; - - if (outstandingWrites === 0) { - done(); - } else { - this._parser.once('doneWritingFile', done); - } - }); - } - - _initJSONencoded() { - this.type = 'json'; - - const parser = new JSONParser(); - - parser.on('data', ({ key, value }) => { - this.emit('field', key, value); - }); - - parser.once('end', () => { - this.ended = true; - this._maybeEnd(); - }); - - this._parser = parser; - } - _uploadPath(filename) { const buf = crypto.randomBytes(16); let name = `upload_${buf.toString('hex')}`; - if (this.keepExtensions) { + if (this.options.keepExtensions) { let ext = path.extname(filename); ext = ext.replace(/(\.[a-z0-9]+).*/i, '$1'); diff --git a/src/parsers/Dummy.js b/src/parsers/Dummy.js index f9240f21..63409597 100644 --- a/src/parsers/Dummy.js +++ b/src/parsers/Dummy.js @@ -5,8 +5,9 @@ const { Transform } = require('stream'); class DummyParser extends Transform { - constructor(incomingForm) { + constructor(incomingForm, options = {}) { super(); + this.globalOptions = { ...options }; this.incomingForm = incomingForm; } diff --git a/src/parsers/JSON.js b/src/parsers/JSON.js index 6b2a15ab..9a096c25 100644 --- a/src/parsers/JSON.js +++ b/src/parsers/JSON.js @@ -5,9 +5,10 @@ const { Transform } = require('stream'); class JSONParser extends Transform { - constructor() { + constructor(options = {}) { super({ readableObjectMode: true }); this.chunks = []; + this.globalOptions = { ...options }; } _transform(chunk, encoding, callback) { diff --git a/src/parsers/Multipart.js b/src/parsers/Multipart.js index 93a8a475..9adad9fa 100644 --- a/src/parsers/Multipart.js +++ b/src/parsers/Multipart.js @@ -43,7 +43,7 @@ Object.keys(STATE).forEach((stateName) => { }); class MultipartParser extends Transform { - constructor() { + constructor(options = {}) { super({ readableObjectMode: true }); this.boundary = null; this.boundaryChars = null; @@ -51,6 +51,7 @@ class MultipartParser extends Transform { this.bufferLength = 0; this.state = STATE.PARSER_UNINITIALIZED; + this.globalOptions = { ...options }; this.index = null; this.flags = 0; } diff --git a/src/parsers/OctetStream.js b/src/parsers/OctetStream.js index 2e402405..cdf55f23 100644 --- a/src/parsers/OctetStream.js +++ b/src/parsers/OctetStream.js @@ -2,6 +2,11 @@ const { PassThrough } = require('stream'); -class OctetStreamParser extends PassThrough {} +class OctetStreamParser extends PassThrough { + constructor(options = {}) { + super(); + this.globalOptions = { ...options }; + } +} module.exports = OctetStreamParser; diff --git a/src/parsers/Querystring.js b/src/parsers/Querystring.js index b18c5c32..bfa91889 100644 --- a/src/parsers/Querystring.js +++ b/src/parsers/Querystring.js @@ -8,9 +8,10 @@ const querystring = require('querystring'); // This is a buffering parser, not quite as nice as the multipart one. // If I find time I'll rewrite this to be fully streaming as well class QuerystringParser extends Transform { - constructor(maxKeys) { + constructor(options = {}) { super({ readableObjectMode: true }); - this.maxKeys = maxKeys; + this.globalOptions = { ...options }; + this.maxKeys = this.globalOptions.maxFields; this.buffer = ''; this.bufferLength = 0; } diff --git a/src/plugins/json.js b/src/plugins/json.js new file mode 100644 index 00000000..e4d41d58 --- /dev/null +++ b/src/plugins/json.js @@ -0,0 +1,36 @@ +/* eslint-disable no-underscore-dangle */ + +'use strict'; + +const JSONParser = require('../parsers/JSON'); + +// the `options` is also available through the `this.options` / `formidable.options` +module.exports = function plugin(formidable, options) { + // the `this` context is always formidable, as the first argument of a plugin + // but this allows us to customize/test each plugin + const self = this || formidable; + + if (/json/i.test(self.headers['content-type'])) { + initJSONencoded.call(self, self, options); + } +}; + +// Note that it's a good practice (but it's up to you) to use the `this.options` instead +// of the passed `options` (second) param, because when you decide +// to test the plugin you can pass custom `this` context to it (and so `this.options`) +function initJSONencoded() { + this.type = 'json'; + + const parser = new JSONParser(this.options); + + parser.on('data', ({ key, value }) => { + this.emit('field', key, value); + }); + + parser.once('end', () => { + this.ended = true; + this._maybeEnd(); + }); + + this._parser = parser; +} diff --git a/src/plugins/multipart.js b/src/plugins/multipart.js new file mode 100644 index 00000000..2af13340 --- /dev/null +++ b/src/plugins/multipart.js @@ -0,0 +1,153 @@ +/* eslint-disable no-underscore-dangle */ + +'use strict'; + +const { Stream } = require('stream'); +const MultipartParser = require('../parsers/Multipart'); + +// the `options` is also available through the `options` / `formidable.options` +module.exports = function plugin(formidable, options) { + // the `this` context is always formidable, as the first argument of a plugin + // but this allows us to customize/test each plugin + const self = this || formidable; + + if (/multipart/i.test(self.headers['content-type'])) { + const m = self.headers['content-type'].match( + /boundary=(?:"([^"]+)"|([^;]+))/i, + ); + if (m) { + const initMultipart = createInitMultipart(m[1] || m[2]); + initMultipart.call(self, self, options); + } else { + self._error(new Error('bad content-type header, no multipart boundary')); + } + } +}; + +// Note that it's a good practice (but it's up to you) to use the `this.options` instead +// of the passed `options` (second) param, because when you decide +// to test the plugin you can pass custom `this` context to it (and so `this.options`) +function createInitMultipart(boundary) { + return function initMultipart() { + this.type = 'multipart'; + + const parser = new MultipartParser(this.options); + let headerField; + let headerValue; + let part; + + parser.initWithBoundary(boundary); + + // eslint-disable-next-line max-statements, consistent-return + parser.on('data', ({ name, buffer, start, end }) => { + if (name === 'partBegin') { + part = new Stream(); + part.readable = true; + part.headers = {}; + part.name = null; + part.filename = null; + part.mime = null; + + part.transferEncoding = 'binary'; + part.transferBuffer = ''; + + headerField = ''; + headerValue = ''; + } else if (name === 'headerField') { + headerField += buffer.toString(this.options.encoding, start, end); + } else if (name === 'headerValue') { + headerValue += buffer.toString(this.options.encoding, start, end); + } else if (name === 'headerEnd') { + headerField = headerField.toLowerCase(); + part.headers[headerField] = headerValue; + + // matches either a quoted-string or a token (RFC 2616 section 19.5.1) + const m = headerValue.match( + // eslint-disable-next-line no-useless-escape + /\bname=("([^"]*)"|([^\(\)<>@,;:\\"\/\[\]\?=\{\}\s\t/]+))/i, + ); + if (headerField === 'content-disposition') { + if (m) { + part.name = m[2] || m[3] || ''; + } + + part.filename = this._getFileName(headerValue); + } else if (headerField === 'content-type') { + part.mime = headerValue; + } else if (headerField === 'content-transfer-encoding') { + part.transferEncoding = headerValue.toLowerCase(); + } + + headerField = ''; + headerValue = ''; + } else if (name === 'headersEnd') { + switch (part.transferEncoding) { + case 'binary': + case '7bit': + case '8bit': { + const dataPropagation = (ctx) => { + if (ctx.name === 'partData') { + part.emit('data', ctx.buffer.slice(ctx.start, ctx.end)); + } + }; + const dataStopPropagation = (ctx) => { + if (ctx.name === 'partEnd') { + part.emit('end'); + parser.off('data', dataPropagation); + parser.off('data', dataStopPropagation); + } + }; + parser.on('data', dataPropagation); + parser.on('data', dataStopPropagation); + break; + } + case 'base64': { + const dataPropagation = (ctx) => { + if (ctx.name === 'partData') { + part.transferBuffer += ctx.buffer + .slice(ctx.start, ctx.end) + .toString('ascii'); + + /* + four bytes (chars) in base64 converts to three bytes in binary + encoding. So we should always work with a number of bytes that + can be divided by 4, it will result in a number of buytes that + can be divided vy 3. + */ + const offset = parseInt(part.transferBuffer.length / 4, 10) * 4; + part.emit( + 'data', + Buffer.from( + part.transferBuffer.substring(0, offset), + 'base64', + ), + ); + part.transferBuffer = part.transferBuffer.substring(offset); + } + }; + const dataStopPropagation = (ctx) => { + if (ctx.name === 'partEnd') { + part.emit('data', Buffer.from(part.transferBuffer, 'base64')); + part.emit('end'); + parser.off('data', dataPropagation); + parser.off('data', dataStopPropagation); + } + }; + parser.on('data', dataPropagation); + parser.on('data', dataStopPropagation); + break; + } + default: + return this._error(new Error('unknown transfer-encoding')); + } + + this.onPart(part); + } else if (name === 'end') { + this.ended = true; + this._maybeEnd(); + } + }); + + this._parser = parser; + }; +} diff --git a/src/plugins/octetstream.js b/src/plugins/octetstream.js new file mode 100644 index 00000000..10279217 --- /dev/null +++ b/src/plugins/octetstream.js @@ -0,0 +1,74 @@ +/* eslint-disable no-underscore-dangle */ + +'use strict'; + +const File = require('../File'); +const OctetStreamParser = require('../parsers/OctetStream'); + +// the `options` is also available through the `options` / `formidable.options` +module.exports = function plugin(formidable, options) { + // the `this` context is always formidable, as the first argument of a plugin + // but this allows us to customize/test each plugin + const self = this || formidable; + + if (/octet-stream/i.test(self.headers['content-type'])) { + initOctetStream.call(self, self, options); + } +}; + +// Note that it's a good practice (but it's up to you) to use the `this.options` instead +// of the passed `options` (second) param, because when you decide +// to test the plugin you can pass custom `this` context to it (and so `this.options`) +function initOctetStream() { + this.type = 'octet-stream'; + const filename = this.headers['x-file-name']; + const mime = this.headers['content-type']; + + const file = new File({ + path: this._uploadPath(filename), + name: filename, + type: mime, + }); + + this.emit('fileBegin', filename, file); + file.open(); + this.openedFiles.push(file); + this._flushing += 1; + + this._parser = new OctetStreamParser(this.options); + + // Keep track of writes that haven't finished so we don't emit the file before it's done being written + let outstandingWrites = 0; + + this._parser.on('data', (buffer) => { + this.pause(); + outstandingWrites += 1; + + file.write(buffer, () => { + outstandingWrites -= 1; + this.resume(); + + if (this.ended) { + this._parser.emit('doneWritingFile'); + } + }); + }); + + this._parser.on('end', () => { + this._flushing -= 1; + this.ended = true; + + const done = () => { + file.end(() => { + this.emit('file', 'file', file); + this._maybeEnd(); + }); + }; + + if (outstandingWrites === 0) { + done(); + } else { + this._parser.once('doneWritingFile', done); + } + }); +} diff --git a/src/plugins/querystring.js b/src/plugins/querystring.js new file mode 100644 index 00000000..ff5dff05 --- /dev/null +++ b/src/plugins/querystring.js @@ -0,0 +1,36 @@ +/* eslint-disable no-underscore-dangle */ + +'use strict'; + +const QuerystringParser = require('../parsers/Querystring'); + +// the `options` is also available through the `this.options` / `formidable.options` +module.exports = function plugin(formidable, options) { + // the `this` context is always formidable, as the first argument of a plugin + // but this allows us to customize/test each plugin + const self = this || formidable; + + if (/urlencoded/i.test(self.headers['content-type'])) { + initQuerystring.call(self, self, options); + } +}; + +// Note that it's a good practice (but it's up to you) to use the `this.options` instead +// of the passed `options` (second) param, because when you decide +// to test the plugin you can pass custom `this` context to it (and so `this.options`) +function initQuerystring() { + this.type = 'urlencoded'; + + const parser = new QuerystringParser(this.options); + + parser.on('data', ({ key, value }) => { + this.emit('field', key, value); + }); + + parser.once('end', () => { + this.ended = true; + this._maybeEnd(); + }); + + this._parser = parser; +} diff --git a/test/integration/test-fixtures.js b/test/integration/test-fixtures.js index 0b54d598..aef8b6dd 100644 --- a/test/integration/test-fixtures.js +++ b/test/integration/test-fixtures.js @@ -77,7 +77,7 @@ function testNext(results) { assert.strictEqual( file.hash, expectedPart.sha1, - `error ${file.name} on ${file.path}`, + `SHA1 error ${file.name} on ${file.path}`, ); } } diff --git a/test/unit/test-incoming-form.js b/test/unit/test-incoming-form.js index f578a8a4..c2008428 100644 --- a/test/unit/test-incoming-form.js +++ b/test/unit/test-incoming-form.js @@ -17,60 +17,64 @@ let form; form = name === 'formidable' ? mod.formidable() : new mod[name](); }, - [`${name}#_fileName with regular characters`]: () => { + [`${name}#_getFileName with regular characters`]: () => { const filename = 'foo.txt'; - assert.equal(form._fileName(makeHeader(filename)), 'foo.txt'); + assert.strictEqual(form._getFileName(makeHeader(filename)), 'foo.txt'); }, - [`${name}#_fileName with unescaped quote`]: () => { + [`${name}#_getFileName with unescaped quote`]: () => { const filename = 'my".txt'; - assert.equal(form._fileName(makeHeader(filename)), 'my".txt'); + assert.strictEqual(form._getFileName(makeHeader(filename)), 'my".txt'); }, - [`${name}#_fileName with escaped quote`]: () => { + [`${name}#_getFileName with escaped quote`]: () => { const filename = 'my%22.txt'; - assert.equal(form._fileName(makeHeader(filename)), 'my".txt'); + assert.strictEqual(form._getFileName(makeHeader(filename)), 'my".txt'); }, - [`${name}#_fileName with bad quote and additional sub-header`]: () => { + [`${name}#_getFileName with bad quote and additional sub-header`]: () => { const filename = 'my".txt'; const header = `${makeHeader(filename)}; foo="bar"`; - assert.equal(form._fileName(header), filename); + assert.strictEqual(form._getFileName(header), filename); }, - [`${name}#_fileName with semicolon`]: () => { + [`${name}#_getFileName with semicolon`]: () => { const filename = 'my;.txt'; - assert.equal(form._fileName(makeHeader(filename)), 'my;.txt'); + assert.strictEqual(form._getFileName(makeHeader(filename)), 'my;.txt'); }, - [`${name}#_fileName with utf8 character`]: () => { + [`${name}#_getFileName with utf8 character`]: () => { const filename = 'my☃.txt'; - assert.equal(form._fileName(makeHeader(filename)), 'my☃.txt'); + assert.strictEqual(form._getFileName(makeHeader(filename)), 'my☃.txt'); }, [`${name}#_uploadPath strips harmful characters from extension when keepExtensions`]: () => { - form.keepExtensions = true; + const opts = { + keepExtensions: true, + }; + + form = name === 'formidable' ? mod.formidable(opts) : new mod[name](opts); let ext = path.extname(form._uploadPath('fine.jpg?foo=bar')); - assert.equal(ext, '.jpg'); + assert.strictEqual(ext, '.jpg'); ext = path.extname(form._uploadPath('fine?foo=bar')); - assert.equal(ext, ''); + assert.strictEqual(ext, ''); ext = path.extname(form._uploadPath('super.cr2+dsad')); - assert.equal(ext, '.cr2'); + assert.strictEqual(ext, '.cr2'); ext = path.extname(form._uploadPath('super.bar')); - assert.equal(ext, '.bar'); + assert.strictEqual(ext, '.bar'); ext = path.extname(form._uploadPath('file.aAa')); - assert.equal(ext, '.aAa'); + assert.strictEqual(ext, '.aAa'); }, [`${name}#_Array parameters support`]: () => { @@ -78,11 +82,15 @@ let form; form = name === 'formidable' ? mod.formidable(opts) : new mod[name](opts); const req = new Request(); - req.headers = 'content-type: json; content-length:8'; + req.headers = { + 'content-type': 'json', + 'content-length': 8, + }; + form.parse(req, (error, fields) => { - assert.equal(Array.isArray(fields.a), true); - assert.equal(fields.a[0], 1); - assert.equal(fields.a[1], 2); + assert.strictEqual(Array.isArray(fields.a), true); + assert.strictEqual(fields.a[0], 1); + assert.strictEqual(fields.a[1], 2); }); form.emit('field', 'a[]', 1); form.emit('field', 'a[]', 2); From 0aab094a8bde3e585cb2d0cb02d6264d1783b4e2 Mon Sep 17 00:00:00 2001 From: Charlike Mike Reagent Date: Wed, 29 Jan 2020 11:04:05 +0200 Subject: [PATCH 02/19] chore: update changelog Signed-off-by: Charlike Mike Reagent --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 53ce00df..da0ba03a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ * fix(tests): include multipart and qs parser unit tests, part of [#415](https://github.com/node-formidable/node-formidable/issues/415) * fix: reorganize exports + move parsers to `src/parsers/` * fix: update docs and examples [#544](https://github.com/node-formidable/node-formidable/pull/544) ([#248](https://github.com/node-formidable/node-formidable/issues/248), [#335](https://github.com/node-formidable/node-formidable/issues/335), [#371](https://github.com/node-formidable/node-formidable/issues/371), [#372](https://github.com/node-formidable/node-formidable/issues/372), [#387](https://github.com/node-formidable/node-formidable/issues/387), partly [#471](https://github.com/node-formidable/node-formidable/issues/471), [#535](https://github.com/node-formidable/node-formidable/issues/535)) + * feat: introduce Plugins API, fix silent failing tests ([#545](https://github.com/node-formidable/node-formidable/pull/545)) ### v1.2.1 (2018-03-20) From 7568d088403ee5f20f6e209f0daf0ec0cb704544 Mon Sep 17 00:00:00 2001 From: Charlike Mike Reagent Date: Wed, 29 Jan 2020 11:08:18 +0200 Subject: [PATCH 03/19] chore: lgtm tweaks? Signed-off-by: Charlike Mike Reagent --- src/plugins/json.js | 4 ++-- src/plugins/octetstream.js | 4 ++-- src/plugins/querystring.js | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/plugins/json.js b/src/plugins/json.js index e4d41d58..9657ade5 100644 --- a/src/plugins/json.js +++ b/src/plugins/json.js @@ -11,14 +11,14 @@ module.exports = function plugin(formidable, options) { const self = this || formidable; if (/json/i.test(self.headers['content-type'])) { - initJSONencoded.call(self, self, options); + init.call(self, self, options); } }; // Note that it's a good practice (but it's up to you) to use the `this.options` instead // of the passed `options` (second) param, because when you decide // to test the plugin you can pass custom `this` context to it (and so `this.options`) -function initJSONencoded() { +function init(_self, _opts) { this.type = 'json'; const parser = new JSONParser(this.options); diff --git a/src/plugins/octetstream.js b/src/plugins/octetstream.js index 10279217..fc6a3883 100644 --- a/src/plugins/octetstream.js +++ b/src/plugins/octetstream.js @@ -12,14 +12,14 @@ module.exports = function plugin(formidable, options) { const self = this || formidable; if (/octet-stream/i.test(self.headers['content-type'])) { - initOctetStream.call(self, self, options); + init.call(self, self, options); } }; // Note that it's a good practice (but it's up to you) to use the `this.options` instead // of the passed `options` (second) param, because when you decide // to test the plugin you can pass custom `this` context to it (and so `this.options`) -function initOctetStream() { +function init(_self, _opts) { this.type = 'octet-stream'; const filename = this.headers['x-file-name']; const mime = this.headers['content-type']; diff --git a/src/plugins/querystring.js b/src/plugins/querystring.js index ff5dff05..8ec89ab4 100644 --- a/src/plugins/querystring.js +++ b/src/plugins/querystring.js @@ -11,14 +11,14 @@ module.exports = function plugin(formidable, options) { const self = this || formidable; if (/urlencoded/i.test(self.headers['content-type'])) { - initQuerystring.call(self, self, options); + init.call(self, self, options); } }; // Note that it's a good practice (but it's up to you) to use the `this.options` instead // of the passed `options` (second) param, because when you decide // to test the plugin you can pass custom `this` context to it (and so `this.options`) -function initQuerystring() { +function init(_self, _opts) { this.type = 'urlencoded'; const parser = new QuerystringParser(this.options); From 7fed5448a9da6e28ea262f188953d25057d47bc8 Mon Sep 17 00:00:00 2001 From: Charlike Mike Reagent Date: Wed, 29 Jan 2020 12:02:48 +0200 Subject: [PATCH 04/19] start plugins tests; update exports Signed-off-by: Charlike Mike Reagent --- src/Formidable.js | 17 +++++- src/index.js | 27 +++++---- src/parsers/index.js | 17 ++++++ src/plugins/index.js | 13 +++++ test/unit/test-custom-plugins.js | 97 ++++++++++++++++++++++++++++++++ 5 files changed, 156 insertions(+), 15 deletions(-) create mode 100644 src/parsers/index.js create mode 100644 src/plugins/index.js create mode 100644 test/unit/test-custom-plugins.js diff --git a/src/Formidable.js b/src/Formidable.js index f51e2236..5283c867 100644 --- a/src/Formidable.js +++ b/src/Formidable.js @@ -321,10 +321,24 @@ class IncomingForm extends EventEmitter { for (let idx = 0; idx < this._plugins.length; idx++) { const plugin = this._plugins[idx].bind(this); - const res = plugin.call(this, this, this.options); + let res = null; + + try { + res = plugin.call(this, this, this.options); + } catch (err) { + this._error( + new Error(`plugin on index ${idx} failed with ${err.message}`), + ); + break; + } + + // todo: use Set/Map and pass plugin name instead of the `idx` index + this.emit('pluginReturn', idx, res); results.push(res); } + this.emit('pluginReturns', results); + if (results.length === 0 && results.length !== this._plugins.length) { this._error( new Error( @@ -410,4 +424,5 @@ class IncomingForm extends EventEmitter { } } +IncomingForm.DEFAULT_OPTIONS = DEFAULT_OPTIONS; module.exports = IncomingForm; diff --git a/src/index.js b/src/index.js index 011434de..f08819c1 100644 --- a/src/index.js +++ b/src/index.js @@ -3,11 +3,8 @@ const File = require('./File'); const Formidable = require('./Formidable'); -const JSONParser = require('./parsers/JSON'); -const DummyParser = require('./parsers/Dummy'); -const MultipartParser = require('./parsers/Multipart'); -const OctetStreamParser = require('./parsers/OctetStream'); -const QuerystringParser = require('./parsers/Querystring'); +const plugins = require('./plugins/index'); +const parsers = require('./parsers/index'); // make it available without requiring the `new` keyword // if you want it access `const formidable.IncomingForm` as v1 @@ -22,13 +19,15 @@ module.exports = Object.assign(formidable, { IncomingForm: Formidable, // parsers - JSONParser, - DummyParser, - MultipartParser, - OctetStreamParser, - QuerystringParser, - - // typo aliases - OctetstreamParser: OctetStreamParser, - QueryStringParser: QuerystringParser, + ...parsers, + parsers, + + // misc + defaultOptions: Formidable.DEFAULT_OPTIONS, + enabledPlugins: Formidable.DEFAULT_OPTIONS.enabledPlugins, + + // plugins + plugins: { + ...plugins, + }, }); diff --git a/src/parsers/index.js b/src/parsers/index.js new file mode 100644 index 00000000..bbf9ef63 --- /dev/null +++ b/src/parsers/index.js @@ -0,0 +1,17 @@ +'use strict'; + +const JSONParser = require('./JSON'); +const DummyParser = require('./Dummy'); +const MultipartParser = require('./Multipart'); +const OctetStreamParser = require('./OctetStream'); +const QueryStringParser = require('./Querystring'); + +Object.assign(exports, { + JSONParser, + DummyParser, + MultipartParser, + OctetStreamParser, + OctetstreamParser: OctetStreamParser, + QueryStringParser, + QuerystringParser: QueryStringParser, +}); diff --git a/src/plugins/index.js b/src/plugins/index.js new file mode 100644 index 00000000..cbd491af --- /dev/null +++ b/src/plugins/index.js @@ -0,0 +1,13 @@ +'use strict'; + +const octetstream = require('./octetstream'); +const querystring = require('./querystring'); +const multipart = require('./multipart'); +const json = require('./json'); + +Object.assign(exports, { + octetstream, + querystring, + multipart, + json, +}); diff --git a/test/unit/test-custom-plugins.js b/test/unit/test-custom-plugins.js new file mode 100644 index 00000000..dafe6465 --- /dev/null +++ b/test/unit/test-custom-plugins.js @@ -0,0 +1,97 @@ +/* eslint-disable no-underscore-dangle */ + +'use strict'; + +// ! TODO: doesn't actually pass, should switch the test runner first, +// ! before finishing the plugins tests + +const http = require('http'); +const assert = require('assert'); +const test = require('utest'); + +const { formidable } = require('../../src/index'); + +function makeRequest(server) { + server.listen(0, () => { + const choosenPort = server.address().port; + + const request = http.request({ + port: choosenPort, + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + }); + + request.write(JSON.stringify({ qux: 'zaz' })); + request.end(); + }); +} + +function onDone({ server, form, req, res }) { + form.parse(req, (err, fields) => { + assert.strictEqual(fields.qux, 'zaz'); + + setTimeout(() => { + res.end(); + server.close(); + }, 200); + }); +} + +test('custom plugins', { + 'should have 3 custom plugins, and all be called when .parse() is called': () => { + const server = http.createServer((req, res) => { + const form = formidable(); + + form.on('pluginReturns', (results) => { + assert.strictEqual(results.length, 3, 'three plugins should be called'); + }); + form.on('end', () => { + assert.strictEqual(form.__customPlugin1, 111); + assert.strictEqual(form.__customPlugin2, 222); + assert.strictEqual(form.__customPlugin3, 333); + }); + + form.use((inst) => { + const self = inst; + self.__customPlugin1 = 111; + }); + form.use((inst) => { + const self = inst; + self.__customPlugin2 = 222; + }); + form.use((inst) => { + const self = inst; + self.__customPlugin3 = 333; + }); + + onDone({ server, form, req, res }); + }); + + makeRequest(server); + }, + + 'should emit `error` event when some plugin fail': () => { + const server = http.createServer((req, res) => { + const form = formidable(); + // console.log(form); + + form.once('error', (err) => { + assert.strictEqual( + err.message.includes('custom plugin err'), + true, + 'should have error', + ); + console.log('should print here!'); + }); + + form.use(() => { + console.log('should be called'); + throw new Error('custom plugin err'); + }); + + onDone({ server, form, req, res }); + }); + + makeRequest(server); + }, +}); From aa0cc85210d195a4fe68fad377826ae5b3007c7c Mon Sep 17 00:00:00 2001 From: Charlike Mike Reagent Date: Wed, 29 Jan 2020 12:26:51 +0200 Subject: [PATCH 05/19] chore(custom-plugins-tests): make it really passing Signed-off-by: Charlike Mike Reagent --- test/unit/test-custom-plugins.js | 191 ++++++++++++++++++++----------- 1 file changed, 121 insertions(+), 70 deletions(-) diff --git a/test/unit/test-custom-plugins.js b/test/unit/test-custom-plugins.js index dafe6465..9ff39033 100644 --- a/test/unit/test-custom-plugins.js +++ b/test/unit/test-custom-plugins.js @@ -5,93 +5,144 @@ // ! TODO: doesn't actually pass, should switch the test runner first, // ! before finishing the plugins tests -const http = require('http'); +// const http = require('http'); +const { ClientRequest } = require('http'); const assert = require('assert'); const test = require('utest'); const { formidable } = require('../../src/index'); -function makeRequest(server) { - server.listen(0, () => { - const choosenPort = server.address().port; +// function makeRequest(server) { +// server.listen(0, () => { +// const choosenPort = server.address().port; - const request = http.request({ - port: choosenPort, - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - }); +// const request = http.request({ +// port: choosenPort, +// method: 'POST', +// headers: { 'Content-Type': 'application/json' }, +// }); - request.write(JSON.stringify({ qux: 'zaz' })); - request.end(); - }); -} +// request.write(JSON.stringify({ qux: 'zaz' })); +// request.end(); +// }); +// } -function onDone({ server, form, req, res }) { - form.parse(req, (err, fields) => { - assert.strictEqual(fields.qux, 'zaz'); +// function onDone({ server, form, req, res }) { +// form.parse(req, (err, fields) => { +// assert.strictEqual(fields.qux, 'zaz'); - setTimeout(() => { - res.end(); - server.close(); - }, 200); - }); -} +// setTimeout(() => { +// res.end(); +// server.close(); +// }, 200); +// }); +// } test('custom plugins', { - 'should have 3 custom plugins, and all be called when .parse() is called': () => { - const server = http.createServer((req, res) => { - const form = formidable(); - - form.on('pluginReturns', (results) => { - assert.strictEqual(results.length, 3, 'three plugins should be called'); - }); - form.on('end', () => { - assert.strictEqual(form.__customPlugin1, 111); - assert.strictEqual(form.__customPlugin2, 222); - assert.strictEqual(form.__customPlugin3, 333); - }); - - form.use((inst) => { - const self = inst; - self.__customPlugin1 = 111; - }); - form.use((inst) => { - const self = inst; - self.__customPlugin2 = 222; - }); - form.use((inst) => { - const self = inst; - self.__customPlugin3 = 333; - }); - - onDone({ server, form, req, res }); + 'should call 3 custom and 1 builtin plugins, when .parse() is called': () => { + const form = formidable({ enabledPlugins: ['json'] }); + + form.on('pluginReturns', (results) => { + assert.strictEqual( + results.length, + 4, + `4 plugins should be called, but: ${results.length}`, + ); + }); + form.on('end', () => { + assert.strictEqual(form.__customPlugin1, 111); + assert.strictEqual(form.__customPlugin2, 222); + assert.strictEqual(form.__customPlugin3, 333); + const len = form._plugins.length; + assert.strictEqual(len, 4, `3 custom + 1 builtin plugins, but: ${len}`); + }); + + form.use((inst) => { + const self = inst; + self.__customPlugin1 = 111; + }); + form.use((inst) => { + const self = inst; + self.__customPlugin2 = 222; + }); + form.use((inst) => { + const self = inst; + self.__customPlugin3 = 333; }); - makeRequest(server); + const req = new ClientRequest(); + req.headers = { + 'content-type': 'json', + 'content-length': 6, + }; + form.parse(req); + form.emit('field', 'qux', 'zaz'); + form.emit('end'); }, 'should emit `error` event when some plugin fail': () => { - const server = http.createServer((req, res) => { - const form = formidable(); - // console.log(form); - - form.once('error', (err) => { - assert.strictEqual( - err.message.includes('custom plugin err'), - true, - 'should have error', - ); - console.log('should print here!'); - }); - - form.use(() => { - console.log('should be called'); - throw new Error('custom plugin err'); - }); - - onDone({ server, form, req, res }); + const form = formidable({ enabledPlugins: ['json'] }); + let cnt = 0; + + form.on('pluginReturn', () => { + cnt += 1; + }); + + form.once('error', (err) => { + assert.strictEqual( + err.message.includes('custom plugin err'), + true, + 'should have error', + ); + + const len = form._plugins.length; + assert.strictEqual(len, 2, `should call only two plugins, but: ${len}`); + + assert.strictEqual( + cnt, + 1, + `should emit \`pluginReturn\` one time (because the second plugin errors), but: ${cnt}`, + ); + console.log('should print here!'); }); - makeRequest(server); + form.use(() => { + console.log('should be called'); + throw new Error('custom plugin err'); + }); + + const req = new ClientRequest(); + req.headers = { + 'content-type': 'json', + 'content-length': 6, + }; + form.parse(req); + form.emit('field', 'qux', 'zaz'); + form.emit('end'); }, + + // 'should emit `error` event when some plugin fail': () => { + // const server = http.createServer((req, res) => { + // const form = formidable(); + // // console.log(form); + + // form.once('error', (err) => { + // assert.strictEqual( + // err.message.includes('custom plugin err'), + // true, + // 'should have error', + // ); + // console.log('should print here!'); + // }); + + // form.use(() => { + // console.log('should be called'); + // throw new Error('custom plugin err'); + // }); + + // // onDone({ server, form, req, res }); + // }); + + // makeRequest(server); + // }, }); From 308333d2c32036ea2783e815e9d667c17ab09bef Mon Sep 17 00:00:00 2001 From: Charlike Mike Reagent Date: Wed, 29 Jan 2020 15:17:41 +0200 Subject: [PATCH 06/19] chore: more tests; add nyc test coverage Signed-off-by: Charlike Mike Reagent --- .prettierrc.js | 2 +- .travis.yml | 4 + CODE_OF_CONDUCT.md | 22 +- nyc.config.js | 13 + package.json | 8 +- src/Formidable.js | 44 +- src/plugins/json.js | 2 + src/plugins/multipart.js | 6 +- src/plugins/octetstream.js | 2 + src/plugins/querystring.js | 2 + test-legacy/README.md | 3 +- test/standalone/test-connection-aborted.js | 7 +- test/standalone/test-issue-46.js | 6 +- test/standalone/test-keep-alive-error.js | 3 +- test/unit/test-custom-plugins.js | 172 +++-- yarn.lock | 704 ++++++++++++++++++++- 16 files changed, 908 insertions(+), 92 deletions(-) create mode 100644 nyc.config.js diff --git a/.prettierrc.js b/.prettierrc.js index 2a02d8c0..98ff364a 100644 --- a/.prettierrc.js +++ b/.prettierrc.js @@ -1,3 +1,3 @@ 'use strict'; -module.exports = require( '@tunnckocore/prettier-config'); +module.exports = require('@tunnckocore/prettier-config'); diff --git a/.travis.yml b/.travis.yml index 2bc4f39c..effb091c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,3 +2,7 @@ language: node_js node_js: - 10 - 12 + +cache: yarn + +script: nyc yarn test diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 97ced15a..b71f5427 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -14,21 +14,21 @@ orientation. Examples of behavior that contributes to creating a positive environment include: -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members +- Using welcoming and inclusive language +- Being respectful of differing viewpoints and experiences +- Gracefully accepting constructive criticism +- Focusing on what is best for the community +- Showing empathy towards other community members Examples of unacceptable behavior by participants include: -* The use of sexualized language or imagery and unwelcome sexual attention or -advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic +- The use of sexualized language or imagery and unwelcome sexual attention or + advances +- Trolling, insulting/derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or electronic address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a +- Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities diff --git a/nyc.config.js b/nyc.config.js new file mode 100644 index 00000000..da9fab8d --- /dev/null +++ b/nyc.config.js @@ -0,0 +1,13 @@ +'use strict'; + +module.exports = { + statements: 85, + branches: 78, + functions: 85, + lines: 85, + + 'check-coverage': true, + exclude: ['test'], + include: ['src'], + reporter: ['text', 'text-summary', 'lcov', 'clover'], +}; diff --git a/package.json b/package.json index 6d90d803..c95c0245 100644 --- a/package.json +++ b/package.json @@ -16,9 +16,12 @@ }, "scripts": { "cleanup": "rm -rf test/tmp", + "fmt": "prettier '**/*.{md,js,json}' --write", "lint": "eslint . --cache --fix --quiet --format codeframe", - "pretest": "yarn run cleanup", - "test": "mkdir test/tmp && node test/run.js" + "pretest": "yarn run cleanup && mkdir test/tmp", + "test": "node test/run.js", + "pretest:cov": "yarn pretest", + "test:cov": "nyc node test/run.js" }, "devDependencies": { "@tunnckocore/prettier-config": "^1.2.0", @@ -27,6 +30,7 @@ "eslint-config-prettier": "^6.10.0", "eslint-plugin-import": "^2.20.0", "eslint-plugin-prettier": "^3.1.2", + "nyc": "^15.0.0", "prettier": "^1.19.1", "prettier-plugin-pkgjson": "^0.2.0", "request": "^2.88.0", diff --git a/src/Formidable.js b/src/Formidable.js index 5283c867..43f2cbe4 100644 --- a/src/Formidable.js +++ b/src/Formidable.js @@ -51,6 +51,16 @@ class IncomingForm extends EventEmitter { this._plugins = []; this.openedFiles = []; + const enabledPlugins = [] + .concat(this.options.enabledPlugins) + .filter(Boolean); + + if (enabledPlugins.length === 0) { + throw new Error( + 'expect at least 1 enabled builtin plugin, see options.enabledPlugins', + ); + } + this.options.enabledPlugins.forEach((pluginName) => { const plgName = pluginName.toLowerCase(); // eslint-disable-next-line import/no-dynamic-require, global-require @@ -172,8 +182,10 @@ class IncomingForm extends EventEmitter { if (this.error) { return; } - - this._parser.end(); + if (this._parser) { + this._parser.end(); + } + this._maybeEnd(); }); return this; @@ -183,9 +195,20 @@ class IncomingForm extends EventEmitter { this.headers = headers; this._parseContentLength(); this._parseContentType(); - this._parser.once('error', (error) => { - this._error(error); - }); + + // in case plugin fails + if (this._parser) { + this._parser.once('error', (error) => { + this._error(error); + }); + } else { + // when there is no argument, + // it will get the `this.error` which is manually set + // only on one case - when a plugin throw/fail + // this.emit('error', this.error); + // this._error(); + // this._maybeEnd(); + } } write(buffer) { @@ -326,10 +349,9 @@ class IncomingForm extends EventEmitter { try { res = plugin.call(this, this, this.options); } catch (err) { - this._error( - new Error(`plugin on index ${idx} failed with ${err.message}`), - ); - break; + const msg = `plugin on index ${idx} failed with: ${err.message}`; + this.error = new Error(msg); + // break; } // todo: use Set/Map and pass plugin name instead of the `idx` index @@ -349,6 +371,10 @@ class IncomingForm extends EventEmitter { } _error(err) { + if (!err && this.error) { + this.emit('error', this.error); + return; + } if (this.error || this.ended) { return; } diff --git a/src/plugins/json.js b/src/plugins/json.js index 9657ade5..20d3b261 100644 --- a/src/plugins/json.js +++ b/src/plugins/json.js @@ -8,6 +8,8 @@ const JSONParser = require('../parsers/JSON'); module.exports = function plugin(formidable, options) { // the `this` context is always formidable, as the first argument of a plugin // but this allows us to customize/test each plugin + + /* istanbul ignore next */ const self = this || formidable; if (/json/i.test(self.headers['content-type'])) { diff --git a/src/plugins/multipart.js b/src/plugins/multipart.js index 2af13340..4215a3b0 100644 --- a/src/plugins/multipart.js +++ b/src/plugins/multipart.js @@ -9,9 +9,11 @@ const MultipartParser = require('../parsers/Multipart'); module.exports = function plugin(formidable, options) { // the `this` context is always formidable, as the first argument of a plugin // but this allows us to customize/test each plugin + + /* istanbul ignore next */ const self = this || formidable; - if (/multipart/i.test(self.headers['content-type'])) { + if (/multipart|form-data/i.test(self.headers['content-type'])) { const m = self.headers['content-type'].match( /boundary=(?:"([^"]+)"|([^;]+))/i, ); @@ -19,7 +21,7 @@ module.exports = function plugin(formidable, options) { const initMultipart = createInitMultipart(m[1] || m[2]); initMultipart.call(self, self, options); } else { - self._error(new Error('bad content-type header, no multipart boundary')); + throw new Error('bad content-type header, no multipart boundary'); } } }; diff --git a/src/plugins/octetstream.js b/src/plugins/octetstream.js index fc6a3883..5209122a 100644 --- a/src/plugins/octetstream.js +++ b/src/plugins/octetstream.js @@ -9,6 +9,8 @@ const OctetStreamParser = require('../parsers/OctetStream'); module.exports = function plugin(formidable, options) { // the `this` context is always formidable, as the first argument of a plugin // but this allows us to customize/test each plugin + + /* istanbul ignore next */ const self = this || formidable; if (/octet-stream/i.test(self.headers['content-type'])) { diff --git a/src/plugins/querystring.js b/src/plugins/querystring.js index 8ec89ab4..1147503c 100644 --- a/src/plugins/querystring.js +++ b/src/plugins/querystring.js @@ -8,6 +8,8 @@ const QuerystringParser = require('../parsers/Querystring'); module.exports = function plugin(formidable, options) { // the `this` context is always formidable, as the first argument of a plugin // but this allows us to customize/test each plugin + + /* istanbul ignore next */ const self = this || formidable; if (/urlencoded/i.test(self.headers['content-type'])) { diff --git a/test-legacy/README.md b/test-legacy/README.md index 50d29897..cf6e4299 100644 --- a/test-legacy/README.md +++ b/test-legacy/README.md @@ -1,3 +1,2 @@ - These tests were deleted due to failures when removing the gently lib. -previously in `test/legacy` \ No newline at end of file +previously in `test/legacy` diff --git a/test/standalone/test-connection-aborted.js b/test/standalone/test-connection-aborted.js index 616c3b3f..a052f667 100644 --- a/test/standalone/test-connection-aborted.js +++ b/test/standalone/test-connection-aborted.js @@ -20,7 +20,12 @@ const server = http.createServer((req) => { form.on('end', () => { throw new Error('Unexpected "end" event'); }); - form.parse(req); + form.parse(req, () => { + assert( + abortedReceived, + 'from .parse() callback: Error event should follow aborted', + ); + }); }); server.listen(PORT, 'localhost', () => { diff --git a/test/standalone/test-issue-46.js b/test/standalone/test-issue-46.js index 903e995f..6037be2d 100644 --- a/test/standalone/test-issue-46.js +++ b/test/standalone/test-issue-46.js @@ -29,8 +29,9 @@ const server = http.createServer((req, res) => { const form = formidable(); form.parse(req, (err, fields, files) => { res.writeHead(200, { 'content-type': 'text/plain' }); - res.write(JSON.stringify({ err, fields, files })); - res.end(); + // ? old, makes more sense to be passed to `.end()`? + // res.write(JSON.stringify({ err, fields, files })); + res.end(JSON.stringify({ err, fields, files })); }); }); @@ -48,7 +49,6 @@ server.listen(PORT, () => { request({ method: 'POST', url, multipart: parts }, (e, res, body) => { const obj = JSON.parse(body); - console.log(obj); assert.strictEqual('foo' in obj.fields, true); assert.strictEqual('barry', obj.fields.foo); diff --git a/test/standalone/test-keep-alive-error.js b/test/standalone/test-keep-alive-error.js index 7a6c997d..4954239b 100644 --- a/test/standalone/test-keep-alive-error.js +++ b/test/standalone/test-keep-alive-error.js @@ -64,7 +64,8 @@ server.listen(PORT, () => { clientTwo.end(); setTimeout(() => { - assert.strictEqual(ok, 1, `should "ok" count === 1, has: ${ok}`); + // ? yup, quite true, it makes sense to be 2 + assert.strictEqual(ok, 2, `should "ok" count === 2, has: ${ok}`); server.close(); }, 300); diff --git a/test/unit/test-custom-plugins.js b/test/unit/test-custom-plugins.js index 9ff39033..5d0a2898 100644 --- a/test/unit/test-custom-plugins.js +++ b/test/unit/test-custom-plugins.js @@ -5,25 +5,37 @@ // ! TODO: doesn't actually pass, should switch the test runner first, // ! before finishing the plugins tests -// const http = require('http'); +const fs = require('fs'); +const path = require('path'); +const http = require('http'); const { ClientRequest } = require('http'); const assert = require('assert'); + +// const request = require('request'); const test = require('utest'); const { formidable } = require('../../src/index'); -// function makeRequest(server) { +function fromFixtures(...args) { + return path.join(process.cwd(), 'test', 'fixture', ...args); +} + +// function makeRequest(server, options) { // server.listen(0, () => { // const choosenPort = server.address().port; +// const url = `http://localhost:${choosenPort}`; +// console.log('Server up and running at:', url); -// const request = http.request({ +// const method = 'POST'; + +// const opts = { +// ...options, // port: choosenPort, -// method: 'POST', -// headers: { 'Content-Type': 'application/json' }, -// }); +// url, +// method, +// }; -// request.write(JSON.stringify({ qux: 'zaz' })); -// request.end(); +// return http.request(opts); // }); // } @@ -38,6 +50,8 @@ const { formidable } = require('../../src/index'); // }); // } +// ! tests + test('custom plugins', { 'should call 3 custom and 1 builtin plugins, when .parse() is called': () => { const form = formidable({ enabledPlugins: ['json'] }); @@ -75,25 +89,28 @@ test('custom plugins', { 'content-type': 'json', 'content-length': 6, }; - form.parse(req); + form.parse(req, (err, fields) => { + assert.strictEqual(fields.qux, 'zaz'); + }); form.emit('field', 'qux', 'zaz'); form.emit('end'); }, 'should emit `error` event when some plugin fail': () => { - const form = formidable({ enabledPlugins: ['json'] }); + const form = formidable({ enabledPlugins: ['octetstream'] }); let cnt = 0; + let onFileCalled = 0; + let failedIsOkay = false; + form.on('file', () => { + onFileCalled += 1; + }); form.on('pluginReturn', () => { cnt += 1; }); form.once('error', (err) => { - assert.strictEqual( - err.message.includes('custom plugin err'), - true, - 'should have error', - ); + assert(/custom pluginX err/i.test(err.message), 'should have error'); const len = form._plugins.length; assert.strictEqual(len, 2, `should call only two plugins, but: ${len}`); @@ -103,6 +120,12 @@ test('custom plugins', { 1, `should emit \`pluginReturn\` one time (because the second plugin errors), but: ${cnt}`, ); + + assert.strictEqual(onFileCalled, 1, 'expect `file` event to be fired'); + + failedIsOkay = true; + assert.strictEqual(failedIsOkay, true, 'should `error` handler be ok'); + console.log('should print here!'); }); @@ -112,37 +135,96 @@ test('custom plugins', { }); const req = new ClientRequest(); - req.headers = { - 'content-type': 'json', - 'content-length': 6, + + const reqStream = fs + .createReadStream(fromFixtures('file', 'plain.txt')) + .pipe(req); + + reqStream.headers = { + 'content-type': 'application/octet-stream', }; - form.parse(req); - form.emit('field', 'qux', 'zaz'); - form.emit('end'); + form.parse(reqStream, () => { + assert.strictEqual(failedIsOkay, true, 'should `error` handler be ok'); + + // setTimeout(() => { + // res.end(); + // server.close(); + // }, 300); + }); }, - // 'should emit `error` event when some plugin fail': () => { - // const server = http.createServer((req, res) => { - // const form = formidable(); - // // console.log(form); - - // form.once('error', (err) => { - // assert.strictEqual( - // err.message.includes('custom plugin err'), - // true, - // 'should have error', - // ); - // console.log('should print here!'); - // }); - - // form.use(() => { - // console.log('should be called'); - // throw new Error('custom plugin err'); - // }); - - // // onDone({ server, form, req, res }); - // }); - - // makeRequest(server); - // }, + 'multipart plugin emit error when malformed boundary': () => { + const server = http.createServer((req, res) => { + const form = formidable({ enabledPlugins: ['multipart'] }); + let failedIsOkay = false; + let errCount = 0; + + form.on('error', (err) => { + errCount += 1; + + const plgLen = form._plugins.length; + assert.strictEqual( + plgLen, + 1, + 'should have only one (multipart) plugin', + ); + + assert(err, 'should throw error'); + assert( + /bad content-type header, no multipart boundary/i.test(err.message), + 'expect at least 1 enabled plugin', + ); + failedIsOkay = true; + + console.log('should be here'); + }); + + // Should never be called when `error` + form.on('end', () => { + assert.strictEqual(failedIsOkay, true, 'should `error` handler be ok'); + failedIsOkay = 123; + }); + + form.parse(req, (err) => { + assert(err, 'should have error in .parse() callback'); + assert.strictEqual(failedIsOkay, true, 'should `error` handler be ok'); + assert.strictEqual(errCount, 1, 'should fire `error` event once'); + + setTimeout(() => { + res.end(); + server.close(); + }, 300); + }); + }); + + server.listen(0, () => { + const choosenPort = server.address().port; + const url = `http://localhost:${choosenPort}`; + console.log('Server up and running at:', url); + + const req = http.request({ + method: 'POST', + port: choosenPort, + headers: { + 'Content-Length': 1111111, + 'content-Disposition': 'form-data; bouZndary=', + 'Content-Type': 'multipart/form-data; bouZndary=', + }, + }); + + req.end(); + }); + }, + + 'should throw if not at least 1 builtin plugin in options.enabledPlugins': () => { + try { + formidable({ enabledPlugins: [] }); + } catch (err) { + assert(err, 'should throw error'); + assert( + /expect at least 1 enabled builtin/i.test(err.message), + 'expect at least 1 plugin in options.enabledPlugins', + ); + } + }, }); diff --git a/yarn.lock b/yarn.lock index 94cb978d..8887492f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,13 +2,76 @@ # yarn lockfile v1 -"@babel/code-frame@^7.0.0": +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e" integrity sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g== dependencies: "@babel/highlight" "^7.8.3" +"@babel/core@^7.7.5": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.8.3.tgz#30b0ebb4dd1585de6923a0b4d179e0b9f5d82941" + integrity sha512-4XFkf8AwyrEG7Ziu3L2L0Cv+WyY47Tcsp70JFmpftbAA1K7YL/sgE9jh9HyNj08Y/U50ItUchpN0w6HxAoX1rA== + dependencies: + "@babel/code-frame" "^7.8.3" + "@babel/generator" "^7.8.3" + "@babel/helpers" "^7.8.3" + "@babel/parser" "^7.8.3" + "@babel/template" "^7.8.3" + "@babel/traverse" "^7.8.3" + "@babel/types" "^7.8.3" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.1" + json5 "^2.1.0" + lodash "^4.17.13" + resolve "^1.3.2" + semver "^5.4.1" + source-map "^0.5.0" + +"@babel/generator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.8.3.tgz#0e22c005b0a94c1c74eafe19ef78ce53a4d45c03" + integrity sha512-WjoPk8hRpDRqqzRpvaR8/gDUPkrnOOeuT2m8cNICJtZH6mwaCo3v0OKMI7Y6SM1pBtyijnLtAL0HDi41pf41ug== + dependencies: + "@babel/types" "^7.8.3" + jsesc "^2.5.1" + lodash "^4.17.13" + source-map "^0.5.0" + +"@babel/helper-function-name@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz#eeeb665a01b1f11068e9fb86ad56a1cb1a824cca" + integrity sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA== + dependencies: + "@babel/helper-get-function-arity" "^7.8.3" + "@babel/template" "^7.8.3" + "@babel/types" "^7.8.3" + +"@babel/helper-get-function-arity@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz#b894b947bd004381ce63ea1db9f08547e920abd5" + integrity sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA== + dependencies: + "@babel/types" "^7.8.3" + +"@babel/helper-split-export-declaration@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz#31a9f30070f91368a7182cf05f831781065fc7a9" + integrity sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA== + dependencies: + "@babel/types" "^7.8.3" + +"@babel/helpers@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.8.3.tgz#382fbb0382ce7c4ce905945ab9641d688336ce85" + integrity sha512-LmU3q9Pah/XyZU89QvBgGt+BCsTPoQa+73RxAQh8fb8qkDyIfeQnmgs+hvzhTCKTzqOyk7JTkS3MS1S8Mq5yrQ== + dependencies: + "@babel/template" "^7.8.3" + "@babel/traverse" "^7.8.3" + "@babel/types" "^7.8.3" + "@babel/highlight@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.8.3.tgz#28f173d04223eaaa59bc1d439a3836e6d1265797" @@ -18,6 +81,59 @@ esutils "^2.0.2" js-tokens "^4.0.0" +"@babel/parser@^7.7.5", "@babel/parser@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.8.3.tgz#790874091d2001c9be6ec426c2eed47bc7679081" + integrity sha512-/V72F4Yp/qmHaTALizEm9Gf2eQHV3QyTL3K0cNfijwnMnb1L+LDlAubb/ZnSdGAVzVSWakujHYs1I26x66sMeQ== + +"@babel/template@^7.7.4", "@babel/template@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.8.3.tgz#e02ad04fe262a657809327f578056ca15fd4d1b8" + integrity sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ== + dependencies: + "@babel/code-frame" "^7.8.3" + "@babel/parser" "^7.8.3" + "@babel/types" "^7.8.3" + +"@babel/traverse@^7.7.4", "@babel/traverse@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.8.3.tgz#a826215b011c9b4f73f3a893afbc05151358bf9a" + integrity sha512-we+a2lti+eEImHmEXp7bM9cTxGzxPmBiVJlLVD+FuuQMeeO7RaDbutbgeheDkw+Xe3mCfJHnGOWLswT74m2IPg== + dependencies: + "@babel/code-frame" "^7.8.3" + "@babel/generator" "^7.8.3" + "@babel/helper-function-name" "^7.8.3" + "@babel/helper-split-export-declaration" "^7.8.3" + "@babel/parser" "^7.8.3" + "@babel/types" "^7.8.3" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.13" + +"@babel/types@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.8.3.tgz#5a383dffa5416db1b73dedffd311ffd0788fb31c" + integrity sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg== + dependencies: + esutils "^2.0.2" + lodash "^4.17.13" + to-fast-properties "^2.0.0" + +"@istanbuljs/load-nyc-config@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.0.0.tgz#10602de5570baea82f8afbfa2630b24e7a8cfe5b" + integrity sha512-ZR0rq/f/E4f4XcgnDvtMWXCUJpi8eO0rssVhmztsZqLIEFA9UUP9zmpE0VxlM+kv/E1ul2I876Fwil2ayptDVg== + dependencies: + camelcase "^5.3.1" + find-up "^4.1.0" + js-yaml "^3.13.1" + resolve-from "^5.0.0" + +"@istanbuljs/schema@^0.1.2": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.2.tgz#26520bf09abe4a5644cd5414e37125a8954241dd" + integrity sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw== + "@nodelib/fs.scandir@2.1.3": version "2.1.3" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz#3a582bdb53804c6ba6d146579c46e52130cf4a3b" @@ -44,6 +160,11 @@ resolved "https://registry.yarnpkg.com/@tunnckocore/prettier-config/-/prettier-config-1.2.0.tgz#4d2aab462d45353367656bc4b98b1065469bef7c" integrity sha512-/awVnPbFD2YMNbhfrhbAA7Z3jMTPmEYhbXZsqqVoC8nsP6GGELc5CFTPHAZHPFjJrjlwIDyJB6KRo+Rn46342g== +"@types/color-name@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" + integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== + "@types/events@*": version "3.0.0" resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7" @@ -64,9 +185,9 @@ integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== "@types/node@*": - version "13.5.0" - resolved "https://registry.yarnpkg.com/@types/node/-/node-13.5.0.tgz#4e498dbf355795a611a87ae5ef811a8660d42662" - integrity sha512-Onhn+z72D2O2Pb2ql2xukJ55rglumsVo1H6Fmyi8mlU9SvKdBk/pUSUAiBY/d9bAOF7VVWajX3sths/+g6ZiAQ== + version "13.5.1" + resolved "https://registry.yarnpkg.com/@types/node/-/node-13.5.1.tgz#6fae50892d1841f4b38b298e2f78fb68c5960cb9" + integrity sha512-Jj2W7VWQ2uM83f8Ls5ON9adxN98MvyJsMSASYFuSvrov8RMRY64Ayay7KV35ph1TSGIJ2gG9ZVDdEq3c3zaydA== acorn-jsx@^5.1.0: version "5.1.0" @@ -78,6 +199,14 @@ acorn@^7.1.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.1.0.tgz#949d36f2c292535da602283586c2477c57eb2d6c" integrity sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ== +aggregate-error@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.0.1.tgz#db2fe7246e536f40d9b5442a39e117d7dd6a24e0" + integrity sha512-quoaXsZ9/BLNae5yiNoUz+Nhkwz83GhWwtYFglcjEQB2NDHCIpApbqXxIFnm4Pq/Nvhrsq5sYJFyohrrxnTGAA== + dependencies: + clean-stack "^2.0.0" + indent-string "^4.0.0" + ajv@^6.10.0, ajv@^6.10.2, ajv@^6.5.5: version "6.11.0" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.11.0.tgz#c3607cbc8ae392d8a5a536f25b21f8e5f3f87fe9" @@ -112,6 +241,26 @@ ansi-styles@^3.2.0, ansi-styles@^3.2.1: dependencies: color-convert "^1.9.0" +ansi-styles@^4.0.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.2.1.tgz#90ae75c424d008d2624c5bf29ead3177ebfcf359" + integrity sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA== + dependencies: + "@types/color-name" "^1.1.1" + color-convert "^2.0.1" + +append-transform@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-2.0.0.tgz#99d9d29c7b38391e6f428d28ce136551f0b77e12" + integrity sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg== + dependencies: + default-require-extensions "^3.0.0" + +archy@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" + integrity sha1-+cjBN1fMHde8N5rHeyxipcKGjEA= + argparse@^1.0.7: version "1.0.10" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" @@ -200,11 +349,26 @@ braces@^3.0.1: dependencies: fill-range "^7.0.1" +caching-transform@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/caching-transform/-/caching-transform-4.0.0.tgz#00d297a4206d71e2163c39eaffa8157ac0651f0f" + integrity sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA== + dependencies: + hasha "^5.0.0" + make-dir "^3.0.0" + package-hash "^4.0.0" + write-file-atomic "^3.0.0" + callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== +camelcase@^5.0.0, camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + caseless@~0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" @@ -224,6 +388,11 @@ chardet@^0.7.0: resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== +clean-stack@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" + integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== + cli-cursor@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" @@ -236,6 +405,15 @@ cli-width@^2.0.0: resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk= +cliui@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" + integrity sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^6.2.0" + color-convert@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" @@ -243,11 +421,23 @@ color-convert@^1.9.0: dependencies: color-name "1.1.3" +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + color-name@1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + combined-stream@^1.0.6, combined-stream@~1.0.6: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" @@ -255,6 +445,11 @@ combined-stream@^1.0.6, combined-stream@~1.0.6: dependencies: delayed-stream "~1.0.0" +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= + concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -270,6 +465,13 @@ contains-path@^0.1.0: resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" integrity sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo= +convert-source-map@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" + integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== + dependencies: + safe-buffer "~5.1.1" + core-util-is@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" @@ -286,6 +488,15 @@ cross-spawn@^6.0.5: shebang-command "^1.2.0" which "^1.2.9" +cross-spawn@^7.0.0: + version "7.0.1" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.1.tgz#0ab56286e0f7c24e153d04cc2aa027e43a9a5d14" + integrity sha512-u7v4o84SwFpD32Z8IIcPZ6z1/ie24O6RU3RbtL5Y316l3KuHVPx9ItBgWQ6VlfAFnRnTtMUrsQ9MUUTuEZjogg== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + dashdash@^1.12.0: version "1.14.1" resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" @@ -300,18 +511,30 @@ debug@^2.6.9: dependencies: ms "2.0.0" -debug@^4.0.1: +debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== dependencies: ms "^2.1.1" +decamelize@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= + deep-is@~0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= +default-require-extensions@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-3.0.0.tgz#e03f93aac9b2b6443fc52e5e4a37b3ad9ad8df96" + integrity sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg== + dependencies: + strip-bom "^4.0.0" + define-properties@^1.1.2, define-properties@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" @@ -407,6 +630,11 @@ es-to-primitive@^1.2.1: is-date-object "^1.0.1" is-symbol "^1.0.2" +es6-error@^4.0.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d" + integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg== + escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" @@ -653,6 +881,15 @@ fill-range@^7.0.1: dependencies: to-regex-range "^5.0.1" +find-cache-dir@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.2.0.tgz#e7fe44c1abc1299f516146e563108fd1006c1874" + integrity sha512-1JKclkYYsf1q9WIJKLZa9S9muC+08RIjzAlLrK4QcYLJMS6mk9yombQ9qf+zJ7H9LS800k0s44L4sDq9VYzqyg== + dependencies: + commondir "^1.0.1" + make-dir "^3.0.0" + pkg-dir "^4.1.0" + find-up@^2.0.0, find-up@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" @@ -660,6 +897,14 @@ find-up@^2.0.0, find-up@^2.1.0: dependencies: locate-path "^2.0.0" +find-up@^4.0.0, find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + flat-cache@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" @@ -674,6 +919,14 @@ flatted@^2.0.0: resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.1.tgz#69e57caa8f0eacbc281d2e2cb458d46fdb449e08" integrity sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg== +foreground-child@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-2.0.0.tgz#71b32800c9f15aa8f2f83f4a6bd9bff35d861a53" + integrity sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA== + dependencies: + cross-spawn "^7.0.0" + signal-exit "^3.0.2" + forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" @@ -688,6 +941,11 @@ form-data@~2.3.2: combined-stream "^1.0.6" mime-types "^2.1.12" +fromentries@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/fromentries/-/fromentries-1.2.0.tgz#e6aa06f240d6267f913cea422075ef88b63e7897" + integrity sha512-33X7H/wdfO99GdRLLgkjUrD4geAFdq/Uv0kl3HD4da6HDixd2GUg8Mw7dahLCV9r/EARkmtYBB6Tch4EEokFTQ== + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -703,6 +961,16 @@ functional-red-black-tree@^1.0.1: resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= +gensync@^1.0.0-beta.1: + version "1.0.0-beta.1" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269" + integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg== + +get-caller-file@^2.0.1: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + get-stdin@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b" @@ -727,7 +995,7 @@ glob-parent@^5.0.0, glob-parent@^5.1.0: dependencies: is-glob "^4.0.1" -glob@^7.1.3: +glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: version "7.1.6" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== @@ -739,6 +1007,11 @@ glob@^7.1.3: once "^1.3.0" path-is-absolute "^1.0.0" +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + globals@^12.1.0: version "12.3.0" resolved "https://registry.yarnpkg.com/globals/-/globals-12.3.0.tgz#1e564ee5c4dded2ab098b0f88f24702a3c56be13" @@ -760,7 +1033,7 @@ globby@10.0.1: merge2 "^1.2.3" slash "^3.0.0" -graceful-fs@^4.1.2: +graceful-fs@^4.1.15, graceful-fs@^4.1.2: version "4.2.3" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423" integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ== @@ -783,6 +1056,11 @@ has-flag@^3.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + has-symbols@^1.0.0, has-symbols@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" @@ -795,11 +1073,24 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" +hasha@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/hasha/-/hasha-5.1.0.tgz#dd05ccdfcfe7dab626247ce2a58efe461922f4ca" + integrity sha512-OFPDWmzPN1l7atOV1TgBVmNtBxaIysToK6Ve9DK+vT6pYuklw/nPNT+HJbZi0KDcI6vWB+9tgvZ5YD7fA3CXcA== + dependencies: + is-stream "^2.0.0" + type-fest "^0.8.0" + hosted-git-info@^2.1.4: version "2.8.5" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.5.tgz#759cfcf2c4d156ade59b0b2dfabddc42a6b9c70c" integrity sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg== +html-escaper@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.0.tgz#71e87f931de3fe09e56661ab9a29aadec707b491" + integrity sha512-a4u9BeERWGu/S8JiWEAQcdrg9v4QArtP9keViQjGMdff20fBdd8waotXaNmODqBe6uZ3Nafi7K/ho4gCQHV3Ig== + http-signature@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" @@ -839,6 +1130,11 @@ imurmurhash@^0.1.4: resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= +indent-string@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" @@ -925,6 +1221,11 @@ is-regex@^1.0.5: dependencies: has "^1.0.3" +is-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3" + integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw== + is-string@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.5.tgz#40493ed198ef3ff477b8c7f92f644ec82a5cd3a6" @@ -937,11 +1238,16 @@ is-symbol@^1.0.2: dependencies: has-symbols "^1.0.1" -is-typedarray@~1.0.0: +is-typedarray@^1.0.0, is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= +is-windows@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== + isarray@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" @@ -957,6 +1263,70 @@ isstream@~0.1.2: resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.0.0-alpha.1: + version "3.0.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz#f5944a37c70b550b02a78a5c3b2055b280cec8ec" + integrity sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg== + +istanbul-lib-hook@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz#8f84c9434888cc6b1d0a9d7092a76d239ebf0cc6" + integrity sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ== + dependencies: + append-transform "^2.0.0" + +istanbul-lib-instrument@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.0.tgz#53321a7970f076262fd3292c8f9b2e4ac544aae1" + integrity sha512-Nm4wVHdo7ZXSG30KjZ2Wl5SU/Bw7bDx1PdaiIFzEStdjs0H12mOTncn1GVYuqQSaZxpg87VGBRsVRPGD2cD1AQ== + dependencies: + "@babel/core" "^7.7.5" + "@babel/parser" "^7.7.5" + "@babel/template" "^7.7.4" + "@babel/traverse" "^7.7.4" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.0.0" + semver "^6.3.0" + +istanbul-lib-processinfo@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.2.tgz#e1426514662244b2f25df728e8fd1ba35fe53b9c" + integrity sha512-kOwpa7z9hme+IBPZMzQ5vdQj8srYgAtaRqeI48NGmAQ+/5yKiHLV0QbYqQpxsdEF0+w14SoB8YbnHKcXE2KnYw== + dependencies: + archy "^1.0.0" + cross-spawn "^7.0.0" + istanbul-lib-coverage "^3.0.0-alpha.1" + make-dir "^3.0.0" + p-map "^3.0.0" + rimraf "^3.0.0" + uuid "^3.3.3" + +istanbul-lib-report@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6" + integrity sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw== + dependencies: + istanbul-lib-coverage "^3.0.0" + make-dir "^3.0.0" + supports-color "^7.1.0" + +istanbul-lib-source-maps@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz#75743ce6d96bb86dc7ee4352cf6366a23f0b1ad9" + integrity sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg== + dependencies: + debug "^4.1.1" + istanbul-lib-coverage "^3.0.0" + source-map "^0.6.1" + +istanbul-reports@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.0.0.tgz#d4d16d035db99581b6194e119bbf36c963c5eb70" + integrity sha512-2osTcC8zcOSUkImzN2EWQta3Vdi4WjjKw99P2yWx5mLnigAM0Rd5uYFn1cf2i/Ois45GkNjaoTqc5CxgMSX80A== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -975,6 +1345,11 @@ jsbn@~0.1.0: resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + json-schema-traverse@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" @@ -995,6 +1370,13 @@ json-stringify-safe@~5.0.1: resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= +json5@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.1.tgz#81b6cb04e9ba496f1c7005d07b4368a2638f90b6" + integrity sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ== + dependencies: + minimist "^1.2.0" + jsprim@^1.2.2: version "1.4.1" resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" @@ -1031,11 +1413,30 @@ locate-path@^2.0.0: p-locate "^2.0.0" path-exists "^3.0.0" -lodash@^4.17.14, lodash@^4.17.15: +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +lodash.flattendeep@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz#fb030917f86a3134e5bc9bec0d69e0013ddfedb2" + integrity sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI= + +lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15: version "4.17.15" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== +make-dir@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.0.0.tgz#1b5f39f6b9270ed33f9f054c5c0f84304989f801" + integrity sha512-grNJDhb8b1Jm1qeqW5R/O63wUo4UXo2v2HMic6YT9i/HBlF93S8jkMgH7yugvY9ABDShH4VZMn8I+U8+fCNegw== + dependencies: + semver "^6.0.0" + merge2@^1.2.3, merge2@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.3.0.tgz#5b366ee83b2f1582c48f87e47cf1a9352103ca81" @@ -1078,6 +1479,11 @@ minimist@0.0.8: resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= +minimist@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= + mkdirp@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" @@ -1110,6 +1516,13 @@ nice-try@^1.0.4: resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== +node-preload@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/node-preload/-/node-preload-0.2.1.tgz#c03043bb327f417a18fee7ab7ee57b408a144301" + integrity sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ== + dependencies: + process-on-spawn "^1.0.0" + normalize-package-data@^2.3.2: version "2.5.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" @@ -1120,6 +1533,40 @@ normalize-package-data@^2.3.2: semver "2 || 3 || 4 || 5" validate-npm-package-license "^3.0.1" +nyc@^15.0.0: + version "15.0.0" + resolved "https://registry.yarnpkg.com/nyc/-/nyc-15.0.0.tgz#eb32db2c0f29242c2414fe46357f230121cfc162" + integrity sha512-qcLBlNCKMDVuKb7d1fpxjPR8sHeMVX0CHarXAVzrVWoFrigCkYR8xcrjfXSPi5HXM7EU78L6ywO7w1c5rZNCNg== + dependencies: + "@istanbuljs/load-nyc-config" "^1.0.0" + "@istanbuljs/schema" "^0.1.2" + caching-transform "^4.0.0" + convert-source-map "^1.7.0" + decamelize "^1.2.0" + find-cache-dir "^3.2.0" + find-up "^4.1.0" + foreground-child "^2.0.0" + glob "^7.1.6" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-hook "^3.0.0" + istanbul-lib-instrument "^4.0.0" + istanbul-lib-processinfo "^2.0.2" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^4.0.0" + istanbul-reports "^3.0.0" + js-yaml "^3.13.1" + make-dir "^3.0.0" + node-preload "^0.2.0" + p-map "^3.0.0" + process-on-spawn "^1.0.0" + resolve-from "^5.0.0" + rimraf "^3.0.0" + signal-exit "^3.0.2" + spawn-wrap "^2.0.0" + test-exclude "^6.0.0" + uuid "^3.3.3" + yargs "^15.0.2" + oauth-sign@~0.9.0: version "0.9.0" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" @@ -1203,6 +1650,13 @@ p-limit@^1.1.0: dependencies: p-try "^1.0.0" +p-limit@^2.2.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.2.tgz#61279b67721f5287aa1c13a9a7fbbc48c9291b1e" + integrity sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ== + dependencies: + p-try "^2.0.0" + p-locate@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" @@ -1210,11 +1664,40 @@ p-locate@^2.0.0: dependencies: p-limit "^1.1.0" +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-map@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-3.0.0.tgz#d704d9af8a2ba684e2600d9a215983d4141a979d" + integrity sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ== + dependencies: + aggregate-error "^3.0.0" + p-try@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +package-hash@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/package-hash/-/package-hash-4.0.0.tgz#3537f654665ec3cc38827387fc904c163c54f506" + integrity sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ== + dependencies: + graceful-fs "^4.1.15" + hasha "^5.0.0" + lodash.flattendeep "^4.4.0" + release-zalgo "^1.0.0" + parent-module@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" @@ -1234,6 +1717,11 @@ path-exists@^3.0.0: resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" @@ -1244,6 +1732,11 @@ path-key@^2.0.1: resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + path-parse@^1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" @@ -1283,6 +1776,13 @@ pkg-dir@^2.0.0: dependencies: find-up "^2.1.0" +pkg-dir@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" @@ -1307,6 +1807,13 @@ prettier@^1.19.1: resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb" integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew== +process-on-spawn@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/process-on-spawn/-/process-on-spawn-1.0.0.tgz#95b05a23073d30a17acfdc92a440efd2baefdc93" + integrity sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg== + dependencies: + fromentries "^1.2.0" + progress@^2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" @@ -1354,6 +1861,13 @@ regexpp@^2.0.1: resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== +release-zalgo@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/release-zalgo/-/release-zalgo-1.0.0.tgz#09700b7e5074329739330e535c5a90fb67851730" + integrity sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA= + dependencies: + es6-error "^4.0.1" + request@^2.88.0: version "2.88.0" resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" @@ -1380,12 +1894,27 @@ request@^2.88.0: tunnel-agent "^0.6.0" uuid "^3.3.2" +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + +require-main-filename@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" + integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== + resolve-from@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== -resolve@^1.10.0, resolve@^1.12.0, resolve@^1.13.1: +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve@^1.10.0, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.3.2: version "1.15.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.15.0.tgz#1b7ca96073ebb52e741ffd799f6b39ea462c67f5" integrity sha512-+hTmAldEGE80U2wJJDC1lebb5jWqvTYAfm3YZ1ckk1gBr0MnCqUKlwK1e+anaFljIl+F5tR5IoZcm4ZDA1zMQw== @@ -1412,6 +1941,13 @@ rimraf@2.6.3: dependencies: glob "^7.1.3" +rimraf@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.1.tgz#48d3d4cb46c80d388ab26cd61b1b466ae9ae225a" + integrity sha512-IQ4ikL8SjBiEDZfk+DFVwqRK8md24RWMEJkdSlgNLkyyAImcjf8SWvU1qFMDOb4igBClbTQ/ugPqXcRwdFTxZw== + dependencies: + glob "^7.1.3" + run-async@^2.2.0: version "2.3.0" resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" @@ -1436,21 +1972,31 @@ safe-buffer@^5.0.1, safe-buffer@^5.1.2: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519" integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg== +safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + "safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -"semver@2 || 3 || 4 || 5", semver@^5.5.0: +"semver@2 || 3 || 4 || 5", semver@^5.4.1, semver@^5.5.0: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== -semver@^6.1.2: +semver@^6.0.0, semver@^6.1.2, semver@^6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== +set-blocking@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= + shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" @@ -1458,11 +2004,23 @@ shebang-command@^1.2.0: dependencies: shebang-regex "^1.0.0" +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + shebang-regex@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + signal-exit@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" @@ -1498,6 +2056,28 @@ sort-package-json@^1.39.0: globby "10.0.1" sort-object-keys "^1.1.3" +source-map@^0.5.0: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + +source-map@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +spawn-wrap@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/spawn-wrap/-/spawn-wrap-2.0.0.tgz#103685b8b8f9b79771318827aa78650a610d457e" + integrity sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg== + dependencies: + foreground-child "^2.0.0" + is-windows "^1.0.2" + make-dir "^3.0.0" + rimraf "^3.0.0" + signal-exit "^3.0.2" + which "^2.0.1" + spdx-correct@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4" @@ -1553,7 +2133,7 @@ string-width@^3.0.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^5.1.0" -string-width@^4.1.0: +string-width@^4.1.0, string-width@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.0.tgz#952182c46cc7b2c313d1596e623992bd163b72b5" integrity sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg== @@ -1597,6 +2177,11 @@ strip-bom@^3.0.0: resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= +strip-bom@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" + integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== + strip-json-comments@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.0.1.tgz#85713975a91fb87bf1b305cca77395e40d2a64a7" @@ -1609,6 +2194,13 @@ supports-color@^5.3.0: dependencies: has-flag "^3.0.0" +supports-color@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1" + integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g== + dependencies: + has-flag "^4.0.0" + table@^5.2.3: version "5.4.6" resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" @@ -1619,6 +2211,15 @@ table@^5.2.3: slice-ansi "^2.1.0" string-width "^3.0.0" +test-exclude@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" + integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== + dependencies: + "@istanbuljs/schema" "^0.1.2" + glob "^7.1.4" + minimatch "^3.0.4" + text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" @@ -1636,6 +2237,11 @@ tmp@^0.0.33: dependencies: os-tmpdir "~1.0.2" +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= + to-regex-range@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" @@ -1675,11 +2281,18 @@ type-check@~0.3.2: dependencies: prelude-ls "~1.1.2" -type-fest@^0.8.1: +type-fest@^0.8.0, type-fest@^0.8.1: version "0.8.1" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== +typedarray-to-buffer@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" + integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== + dependencies: + is-typedarray "^1.0.0" + uri-js@^4.2.2: version "4.2.2" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" @@ -1697,7 +2310,7 @@ utest@^0.0.8: resolved "https://registry.yarnpkg.com/utest/-/utest-0.0.8.tgz#fc09451fe697b9008d0c432fe0db439d6cf37914" integrity sha1-/AlFH+aXuQCNDEMv4NtDnWzzeRQ= -uuid@^3.3.2: +uuid@^3.3.2, uuid@^3.3.3: version "3.4.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== @@ -1724,6 +2337,11 @@ verror@1.10.0: core-util-is "1.0.2" extsprintf "^1.2.0" +which-module@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= + which@^1.2.9: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" @@ -1731,19 +2349,75 @@ which@^1.2.9: dependencies: isexe "^2.0.0" +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + word-wrap@~1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== +wrap-ansi@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" + integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= +write-file-atomic@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.1.tgz#558328352e673b5bb192cf86500d60b230667d4b" + integrity sha512-JPStrIyyVJ6oCSz/691fAjFtefZ6q+fP6tm+OS4Qw6o+TGQxNp1ziY2PgS+X/m0V8OWhZiO/m4xSj+Pr4RrZvw== + dependencies: + imurmurhash "^0.1.4" + is-typedarray "^1.0.0" + signal-exit "^3.0.2" + typedarray-to-buffer "^3.1.5" + write@1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== dependencies: mkdirp "^0.5.1" + +y18n@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" + integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== + +yargs-parser@^16.1.0: + version "16.1.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-16.1.0.tgz#73747d53ae187e7b8dbe333f95714c76ea00ecf1" + integrity sha512-H/V41UNZQPkUMIT5h5hiwg4QKIY1RPvoBV4XcjUbRM8Bk2oKqqyZ0DIEbTFZB0XjbtSPG8SAa/0DxCQmiRgzKg== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs@^15.0.2: + version "15.1.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.1.0.tgz#e111381f5830e863a89550bd4b136bb6a5f37219" + integrity sha512-T39FNN1b6hCW4SOIk1XyTOWxtXdcen0t+XYrysQmChzSipvhBO8Bj0nK1ozAasdk24dNWuMZvr4k24nz+8HHLg== + dependencies: + cliui "^6.0.0" + decamelize "^1.2.0" + find-up "^4.1.0" + get-caller-file "^2.0.1" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^4.2.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^16.1.0" From f9d8cd4cf3df4e0bd641a2ee9aaf8d6496bb4ee2 Mon Sep 17 00:00:00 2001 From: Charlike Mike Reagent Date: Wed, 29 Jan 2020 15:47:20 +0200 Subject: [PATCH 07/19] chore: move to GitHub Actions CI Signed-off-by: Charlike Mike Reagent --- .github/workflows/nodejs.yml | 46 ++++++++++++++++++++++++++++++++++++ package.json | 4 ++-- 2 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/nodejs.yml diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml new file mode 100644 index 00000000..9fb7fcd6 --- /dev/null +++ b/.github/workflows/nodejs.yml @@ -0,0 +1,46 @@ +name: nodejs + +on: + pull_request: + branches: + - master + push: + branches: + - master + +jobs: + test: + env: + CI: true + CODECOV_TOKEN: ${{secrets.CODECOV_TOKEN}} + strategy: + matrix: + os: [ubuntu-latest, macos-latest] + node: [10.x, 12.x] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v1 + - uses: actions/cache@v1 + id: nodejs-cache + name: Cache node modules + with: + path: node_modules + key: ${{ matrix.os }}-nodejs-${{ matrix.node }}-${{ hashFiles('yarn.lock') }} + restore-keys: | + ${{ matrix.os }}-nodejs-${{ matrix.node }}- + ${{ matrix.os }}-nodejs- + ${{ matrix.os }}- + # - name: "Use Node.js ${{ matrix.node }}" + # uses: actions/setup-node@v1 + # with: + # node: ${{ matrix.node }} + - name: Installing dependencies + if: steps.nodejs-cache.outputs.cache-hit != 'true' + run: yarn --frozen-lockfile + - name: Linting codebase with ESLint & Prettier + run: yarn lint && yarn fmt + - name: Testing all packages + run: yarn test:ci + - name: Sending test coverage to CodeCov + if: matrix.os == 'ubuntu-latest' && matrix.node == '12.x' + run: echo ${{ matrix.node }} && bash <(curl -s https://codecov.io/bash) diff --git a/package.json b/package.json index c95c0245..651ce8b2 100644 --- a/package.json +++ b/package.json @@ -20,8 +20,8 @@ "lint": "eslint . --cache --fix --quiet --format codeframe", "pretest": "yarn run cleanup && mkdir test/tmp", "test": "node test/run.js", - "pretest:cov": "yarn pretest", - "test:cov": "nyc node test/run.js" + "pretest:ci": "yarn pretest", + "test:ci": "nyc node test/run.js" }, "devDependencies": { "@tunnckocore/prettier-config": "^1.2.0", From a84a0f19302f98baaa8aebacd2e72546ab84f863 Mon Sep 17 00:00:00 2001 From: Charlike Mike Reagent Date: Wed, 29 Jan 2020 20:26:01 +0200 Subject: [PATCH 08/19] fix: respect form hash option on incoming octect/stream requests close #407 Co-authored-by: Claudio Poli Signed-off-by: Charlike Mike Reagent --- CHANGELOG.md | 1 + src/plugins/octetstream.js | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index da0ba03a..50b78695 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ * fix: reorganize exports + move parsers to `src/parsers/` * fix: update docs and examples [#544](https://github.com/node-formidable/node-formidable/pull/544) ([#248](https://github.com/node-formidable/node-formidable/issues/248), [#335](https://github.com/node-formidable/node-formidable/issues/335), [#371](https://github.com/node-formidable/node-formidable/issues/371), [#372](https://github.com/node-formidable/node-formidable/issues/372), [#387](https://github.com/node-formidable/node-formidable/issues/387), partly [#471](https://github.com/node-formidable/node-formidable/issues/471), [#535](https://github.com/node-formidable/node-formidable/issues/535)) * feat: introduce Plugins API, fix silent failing tests ([#545](https://github.com/node-formidable/node-formidable/pull/545)) + * respect form hash option on incoming octect/stream requests ([#407](https://github.com/node-formidable/node-formidable/pull/407)) ### v1.2.1 (2018-03-20) diff --git a/src/plugins/octetstream.js b/src/plugins/octetstream.js index 5209122a..a1b967dc 100644 --- a/src/plugins/octetstream.js +++ b/src/plugins/octetstream.js @@ -30,6 +30,7 @@ function init(_self, _opts) { path: this._uploadPath(filename), name: filename, type: mime, + hash: this.options.hash, }); this.emit('fileBegin', filename, file); From db1e1f04d927ad8945f9ad260ee54a2d0a5b2c3c Mon Sep 17 00:00:00 2001 From: Charlike Mike Reagent Date: Thu, 30 Jan 2020 03:00:15 +0200 Subject: [PATCH 09/19] fix: tests, use dezalgo and once for parse callback - it is recommended plugins to return the this/self/formidable instance - add 2 deps: `once` and `dezalgo` for ensurance of the `cb` param of .parse() + otherwise it COULD (and happened already few times) be called multiple times - update unit tests to use Jest Signed-off-by: Charlike Mike Reagent --- package.json | 6 + src/Formidable.js | 78 ++++--- src/plugins/multipart.js | 3 +- src/plugins/octetstream.js | 4 + src/plugins/querystring.js | 4 + test/unit/custom-plugins.test.js | 213 ++++++++++++++++++ test/unit/formidable.test.js | 24 +- test/unit/test-custom-plugins.js | 230 ------------------- yarn.lock | 374 ++++++++++++++++++++++++++++++- 9 files changed, 646 insertions(+), 290 deletions(-) create mode 100644 test/unit/custom-plugins.test.js delete mode 100644 test/unit/test-custom-plugins.js diff --git a/package.json b/package.json index 88af6772..2e730dc6 100644 --- a/package.json +++ b/package.json @@ -31,11 +31,17 @@ "eslint-plugin-import": "^2.20.0", "eslint-plugin-prettier": "^3.1.2", "jest": "^25.1.0", + "koa": "^2.11.0", "nyc": "^15.0.0", "prettier": "^1.19.1", "prettier-plugin-pkgjson": "^0.2.0", "request": "^2.88.0", + "supertest": "^4.0.2", "urun": "^0.0.8", "utest": "^0.0.8" + }, + "dependencies": { + "dezalgo": "^1.0.3", + "once": "^1.4.0" } } diff --git a/src/Formidable.js b/src/Formidable.js index ecd71f48..9d132943 100644 --- a/src/Formidable.js +++ b/src/Formidable.js @@ -7,6 +7,8 @@ const os = require('os'); const fs = require('fs'); const path = require('path'); const crypto = require('crypto'); +const once = require('once'); +const dezalgo = require('dezalgo'); const { EventEmitter } = require('events'); const { StringDecoder } = require('string_decoder'); @@ -108,6 +110,7 @@ class IncomingForm extends EventEmitter { // Setup callback first, so we don't miss anything from data events emitted immediately. if (cb) { + const callback = once(dezalgo(cb)); const fields = {}; const files = {}; @@ -152,10 +155,10 @@ class IncomingForm extends EventEmitter { // } }); this.on('error', (err) => { - cb(err, fields, files); + callback(err, fields, files); }); this.on('end', () => { - cb(null, fields, files); + callback(null, fields, files); }); } @@ -196,19 +199,14 @@ class IncomingForm extends EventEmitter { this._parseContentLength(); this._parseContentType(); - // in case plugin fails - if (this._parser) { - this._parser.once('error', (error) => { - this._error(error); - }); - } else { - // when there is no argument, - // it will get the `this.error` which is manually set - // only on one case - when a plugin throw/fail - // this.emit('error', this.error); - // this._error(); - // this._maybeEnd(); + if (!this._parser) { + this._error(new Error('not parser found')); + return; } + + this._parser.once('error', (error) => { + this._error(error); + }); } write(buffer) { @@ -341,48 +339,56 @@ class IncomingForm extends EventEmitter { } const results = []; + const _dummyParser = new DummyParser(this, this.options); // eslint-disable-next-line no-plusplus for (let idx = 0; idx < this._plugins.length; idx++) { - const plugin = this._plugins[idx].bind(this); + const plugin = this._plugins[idx]; - let res = null; + let pluginReturn = null; try { - res = plugin.call(this, this, this.options); + pluginReturn = plugin(this, this.options) || this; } catch (err) { - const msg = `plugin on index ${idx} failed with: ${err.message}`; - this.error = new Error(msg); - // break; + // directly throw from the `form.parse` method; + // there is no other better way, except a handle through options + const error = new Error( + `plugin on index ${idx} failed with: ${err.message}`, + ); + error.idx = idx; + throw error; } + Object.assign(this, pluginReturn); + // todo: use Set/Map and pass plugin name instead of the `idx` index - this.emit('pluginReturn', idx, res); - results.push(res); + this.emit('plugin', idx, pluginReturn); + results.push(pluginReturn); } - this.emit('pluginReturns', results); + this.emit('pluginsResults', results); - if (results.length === 0 && results.length !== this._plugins.length) { - this._error( - new Error( - `bad content-type header, unknown content-type: ${this.headers['content-type']}`, - ), - ); - } + // ? probably not needed, because we check options.enabledPlugins in the constructor + // if (results.length === 0 /* && results.length !== this._plugins.length */) { + // this._error( + // new Error( + // `bad content-type header, unknown content-type: ${this.headers['content-type']}`, + // ), + // ); + // } } - _error(err) { - if (!err && this.error) { - this.emit('error', this.error); - return; - } + _error(err, eventName = 'error') { + // if (!err && this.error) { + // this.emit('error', this.error); + // return; + // } if (this.error || this.ended) { return; } this.error = err; - this.emit('error', err); + this.emit(eventName, err); if (Array.isArray(this.openedFiles)) { this.openedFiles.forEach((file) => { diff --git a/src/plugins/multipart.js b/src/plugins/multipart.js index 4215a3b0..b7d37468 100644 --- a/src/plugins/multipart.js +++ b/src/plugins/multipart.js @@ -21,7 +21,8 @@ module.exports = function plugin(formidable, options) { const initMultipart = createInitMultipart(m[1] || m[2]); initMultipart.call(self, self, options); } else { - throw new Error('bad content-type header, no multipart boundary'); + const err = new Error('bad content-type header, no multipart boundary'); + self._error(err); } } }; diff --git a/src/plugins/octetstream.js b/src/plugins/octetstream.js index a1b967dc..da17ab88 100644 --- a/src/plugins/octetstream.js +++ b/src/plugins/octetstream.js @@ -16,6 +16,8 @@ module.exports = function plugin(formidable, options) { if (/octet-stream/i.test(self.headers['content-type'])) { init.call(self, self, options); } + + return self; }; // Note that it's a good practice (but it's up to you) to use the `this.options` instead @@ -74,4 +76,6 @@ function init(_self, _opts) { this._parser.once('doneWritingFile', done); } }); + + return this; } diff --git a/src/plugins/querystring.js b/src/plugins/querystring.js index 1147503c..c9dcf1ec 100644 --- a/src/plugins/querystring.js +++ b/src/plugins/querystring.js @@ -15,6 +15,8 @@ module.exports = function plugin(formidable, options) { if (/urlencoded/i.test(self.headers['content-type'])) { init.call(self, self, options); } + + return self; }; // Note that it's a good practice (but it's up to you) to use the `this.options` instead @@ -35,4 +37,6 @@ function init(_self, _opts) { }); this._parser = parser; + + return this; } diff --git a/test/unit/custom-plugins.test.js b/test/unit/custom-plugins.test.js new file mode 100644 index 00000000..4a456050 --- /dev/null +++ b/test/unit/custom-plugins.test.js @@ -0,0 +1,213 @@ +/* eslint-disable no-underscore-dangle */ + +'use strict'; + +const path = require('path'); + +const Koa = require('koa'); +const request = require('supertest'); + +const { formidable } = require('../../src/index'); + +function createServer(options, handler) { + const app = new Koa(); + + app.use(async (ctx, next) => { + const form = formidable(options); + await handler(ctx, form); + await next(); + }); + + return app; +} + +function fromFixtures(...args) { + return path.join(process.cwd(), 'test', 'fixture', ...args); +} + +// function makeRequest(server, options) { +// server.listen(0, () => { +// const choosenPort = server.address().port; +// const url = `http://localhost:${choosenPort}`; +// console.log('Server up and running at:', url); + +// const method = 'POST'; + +// const opts = { +// ...options, +// port: choosenPort, +// url, +// method, +// }; + +// return http.request(opts); +// }); +// } + +// function onDone({ server, form, req, res }) { +// form.parse(req, (err, fields) => { +// assert.strictEqual(fields.qux, 'zaz'); + +// setTimeout(() => { +// res.end(); +// server.close(); +// }, 200); +// }); +// } + +// ! tests + +test('should call 3 custom and 1 builtin plugins, when .parse() is called', async () => { + const server = createServer({ enabledPlugins: ['json'] }, (ctx, form) => { + form.on('plugin', () => { + ctx.__pluginsCount = ctx.__pluginsCount || 0; + ctx.__pluginsCount += 1; + }); + form.on('pluginsResults', (results) => { + expect(results.length).toBe(4); + ctx.__pluginsResults = true; + }); + form.on('end', () => { + ctx.__ends = 1; + expect(ctx.__customPlugin1).toBe(111); + expect(ctx.__customPlugin2).toBe(222); + expect(ctx.__customPlugin3).toBe(333); + ctx.__ends = 2; + + const len = form._plugins.length; + expect(len).toBe(4); + }); + + form.use(() => { + ctx.__customPlugin1 = 111; + }); + form.use(() => { + ctx.__customPlugin2 = 222; + }); + form.use(() => { + ctx.__customPlugin3 = 333; + }); + + form.parse(ctx.req, (err, fields) => { + expect(fields.qux).toBe('zaz'); + expect(fields.a).toBe('bbb'); + expect(ctx.__pluginsCount).toBe(4); + expect(ctx.__pluginsResults).toBe(true); + }); + }); + + await new Promise((resolve, reject) => { + request(server.callback()) + .post('/') + .type('application/json') + .send({ qux: 'zaz', a: 'bbb' }) + .end((err) => (err ? reject(err) : resolve())); + }); +}); + +test('.parse throw error when some plugin fail', async () => { + const server = createServer( + { enabledPlugins: ['octetstream', 'json'] }, + (ctx, form) => { + // const failedIsOkay = false; + // ! not emitted? + // form.on('file', () => { + // ctx.__onFileCalled = ctx.__onFileCalled || 0; + // ctx.__onFileCalled += 1; + // }); + + form.on('plugin', () => { + ctx.__pluginsCount = ctx.__pluginsCount || 0; + ctx.__pluginsCount += 1; + }); + form.on('pluginsResults', () => { + throw new Error('should not be called'); + }); + + form.once('error', () => { + throw new Error('error event should not be fired when plugin throw'); + }); + + form.use(() => { + throw new Error('custom plugin err'); + }); + + let res = null; + try { + form.parse(ctx.req); + } catch (err) { + expect(err.message).toMatch(/custom plugin err/); + expect(err.message).toMatch(/plugin on index 2 failed/); + + expect(form._plugins.length).toBe(3); + expect(ctx.__pluginsCount).toBe(2); + expect(ctx.__pluginsResults).toBe(undefined); + + res = err; + } + + if (!res) { + throw new Error( + '^ .parse should throw & be caught with the try/catch ^', + ); + } + }, + ); + + await new Promise((resolve, reject) => { + request(server.callback()) + .post('/') + .type('application/octet-stream') + .attach('bin', fromFixtures('file', 'binaryfile.tar.gz')) + .end((err) => (err ? reject(err) : resolve())); + }); +}); + +test('multipart plugin fire `error` event when malformed boundary', async () => { + const server = createServer( + { enabledPlugins: ['json', 'multipart'] }, + (ctx, form) => { + let failedIsOkay = false; + + form.once('error', (err) => { + expect(form._plugins.length).toBe(2); + expect(err).toBeTruthy(); + expect(err.message).toMatch(/bad content-type header/); + expect(err.message).toMatch(/no multipart boundary/); + failedIsOkay = true; + }); + + // Should never be called when `error` + form.on('end', () => { + throw new Error('should not fire `end` event when error'); + }); + + form.parse(ctx.req, (err) => { + expect(err).toBeTruthy(); + expect(failedIsOkay).toBe(true); + }); + }, + ); + + // 'Content-Length': 1111111, + // 'content-Disposition': 'form-data; bouZndary=', + // 'Content-Type': 'multipart/form-data; bouZndary=', + await new Promise((resolve, reject) => { + request(server.callback()) + .post('/') + .type('multipart/form-data') + .set('Content-Length', 11111111) + .set('Content-Disposition', 'form-data; bouZndary=') + .set('Content-Type', 'multipart/form-data; bouZndary=') + .end((err) => (err ? reject(err) : resolve())); + }); +}); + +test('formidable() throw if not at least 1 built-in plugin in options.enabledPlugins', () => { + try { + formidable({ enabledPlugins: [] }); + } catch (err) { + expect(err).toBeTruthy(); + expect(err.message).toMatch(/expect at least 1 enabled builtin/); + } +}); diff --git a/test/unit/formidable.test.js b/test/unit/formidable.test.js index 2c08cec8..823d4a36 100644 --- a/test/unit/formidable.test.js +++ b/test/unit/formidable.test.js @@ -17,47 +17,47 @@ function makeHeader(filename) { } ['IncomingForm', 'Formidable', 'formidable'].forEach((name) => { - test(`${name}#_fileName with regular characters`, () => { + test(`${name}#_getFileName with regular characters`, () => { const filename = 'foo.txt'; const form = getForm(name); - expect(form._fileName(makeHeader(filename))).toBe('foo.txt'); + expect(form._getFileName(makeHeader(filename))).toBe('foo.txt'); }); - test(`${name}#_fileName with unescaped quote`, () => { + test(`${name}#_getFileName with unescaped quote`, () => { const filename = 'my".txt'; const form = getForm(name); - expect(form._fileName(makeHeader(filename))).toBe('my".txt'); + expect(form._getFileName(makeHeader(filename))).toBe('my".txt'); }); - test(`${name}#_fileName with escaped quote`, () => { + test(`${name}#_getFileName with escaped quote`, () => { const filename = 'my%22.txt'; const form = getForm(name); - expect(form._fileName(makeHeader(filename))).toBe('my".txt'); + expect(form._getFileName(makeHeader(filename))).toBe('my".txt'); }); - test(`${name}#_fileName with bad quote and additional sub-header`, () => { + test(`${name}#_getFileName with bad quote and additional sub-header`, () => { const filename = 'my".txt'; const form = getForm(name); const header = `${makeHeader(filename)}; foo="bar"`; - expect(form._fileName(header)).toBe(filename); + expect(form._getFileName(header)).toBe(filename); }); - test(`${name}#_fileName with semicolon`, () => { + test(`${name}#_getFileName with semicolon`, () => { const filename = 'my;.txt'; const form = getForm(name); - expect(form._fileName(makeHeader(filename))).toBe('my;.txt'); + expect(form._getFileName(makeHeader(filename))).toBe('my;.txt'); }); - test(`${name}#_fileName with utf8 character`, () => { + test(`${name}#_getFileName with utf8 character`, () => { const filename = 'my☃.txt'; const form = getForm(name); - expect(form._fileName(makeHeader(filename))).toBe('my☃.txt'); + expect(form._getFileName(makeHeader(filename))).toBe('my☃.txt'); }); test(`${name}#_uploadPath strips harmful characters from extension when keepExtensions`, () => { diff --git a/test/unit/test-custom-plugins.js b/test/unit/test-custom-plugins.js deleted file mode 100644 index 5d0a2898..00000000 --- a/test/unit/test-custom-plugins.js +++ /dev/null @@ -1,230 +0,0 @@ -/* eslint-disable no-underscore-dangle */ - -'use strict'; - -// ! TODO: doesn't actually pass, should switch the test runner first, -// ! before finishing the plugins tests - -const fs = require('fs'); -const path = require('path'); -const http = require('http'); -const { ClientRequest } = require('http'); -const assert = require('assert'); - -// const request = require('request'); -const test = require('utest'); - -const { formidable } = require('../../src/index'); - -function fromFixtures(...args) { - return path.join(process.cwd(), 'test', 'fixture', ...args); -} - -// function makeRequest(server, options) { -// server.listen(0, () => { -// const choosenPort = server.address().port; -// const url = `http://localhost:${choosenPort}`; -// console.log('Server up and running at:', url); - -// const method = 'POST'; - -// const opts = { -// ...options, -// port: choosenPort, -// url, -// method, -// }; - -// return http.request(opts); -// }); -// } - -// function onDone({ server, form, req, res }) { -// form.parse(req, (err, fields) => { -// assert.strictEqual(fields.qux, 'zaz'); - -// setTimeout(() => { -// res.end(); -// server.close(); -// }, 200); -// }); -// } - -// ! tests - -test('custom plugins', { - 'should call 3 custom and 1 builtin plugins, when .parse() is called': () => { - const form = formidable({ enabledPlugins: ['json'] }); - - form.on('pluginReturns', (results) => { - assert.strictEqual( - results.length, - 4, - `4 plugins should be called, but: ${results.length}`, - ); - }); - form.on('end', () => { - assert.strictEqual(form.__customPlugin1, 111); - assert.strictEqual(form.__customPlugin2, 222); - assert.strictEqual(form.__customPlugin3, 333); - const len = form._plugins.length; - assert.strictEqual(len, 4, `3 custom + 1 builtin plugins, but: ${len}`); - }); - - form.use((inst) => { - const self = inst; - self.__customPlugin1 = 111; - }); - form.use((inst) => { - const self = inst; - self.__customPlugin2 = 222; - }); - form.use((inst) => { - const self = inst; - self.__customPlugin3 = 333; - }); - - const req = new ClientRequest(); - req.headers = { - 'content-type': 'json', - 'content-length': 6, - }; - form.parse(req, (err, fields) => { - assert.strictEqual(fields.qux, 'zaz'); - }); - form.emit('field', 'qux', 'zaz'); - form.emit('end'); - }, - - 'should emit `error` event when some plugin fail': () => { - const form = formidable({ enabledPlugins: ['octetstream'] }); - let cnt = 0; - let onFileCalled = 0; - let failedIsOkay = false; - - form.on('file', () => { - onFileCalled += 1; - }); - form.on('pluginReturn', () => { - cnt += 1; - }); - - form.once('error', (err) => { - assert(/custom pluginX err/i.test(err.message), 'should have error'); - - const len = form._plugins.length; - assert.strictEqual(len, 2, `should call only two plugins, but: ${len}`); - - assert.strictEqual( - cnt, - 1, - `should emit \`pluginReturn\` one time (because the second plugin errors), but: ${cnt}`, - ); - - assert.strictEqual(onFileCalled, 1, 'expect `file` event to be fired'); - - failedIsOkay = true; - assert.strictEqual(failedIsOkay, true, 'should `error` handler be ok'); - - console.log('should print here!'); - }); - - form.use(() => { - console.log('should be called'); - throw new Error('custom plugin err'); - }); - - const req = new ClientRequest(); - - const reqStream = fs - .createReadStream(fromFixtures('file', 'plain.txt')) - .pipe(req); - - reqStream.headers = { - 'content-type': 'application/octet-stream', - }; - form.parse(reqStream, () => { - assert.strictEqual(failedIsOkay, true, 'should `error` handler be ok'); - - // setTimeout(() => { - // res.end(); - // server.close(); - // }, 300); - }); - }, - - 'multipart plugin emit error when malformed boundary': () => { - const server = http.createServer((req, res) => { - const form = formidable({ enabledPlugins: ['multipart'] }); - let failedIsOkay = false; - let errCount = 0; - - form.on('error', (err) => { - errCount += 1; - - const plgLen = form._plugins.length; - assert.strictEqual( - plgLen, - 1, - 'should have only one (multipart) plugin', - ); - - assert(err, 'should throw error'); - assert( - /bad content-type header, no multipart boundary/i.test(err.message), - 'expect at least 1 enabled plugin', - ); - failedIsOkay = true; - - console.log('should be here'); - }); - - // Should never be called when `error` - form.on('end', () => { - assert.strictEqual(failedIsOkay, true, 'should `error` handler be ok'); - failedIsOkay = 123; - }); - - form.parse(req, (err) => { - assert(err, 'should have error in .parse() callback'); - assert.strictEqual(failedIsOkay, true, 'should `error` handler be ok'); - assert.strictEqual(errCount, 1, 'should fire `error` event once'); - - setTimeout(() => { - res.end(); - server.close(); - }, 300); - }); - }); - - server.listen(0, () => { - const choosenPort = server.address().port; - const url = `http://localhost:${choosenPort}`; - console.log('Server up and running at:', url); - - const req = http.request({ - method: 'POST', - port: choosenPort, - headers: { - 'Content-Length': 1111111, - 'content-Disposition': 'form-data; bouZndary=', - 'Content-Type': 'multipart/form-data; bouZndary=', - }, - }); - - req.end(); - }); - }, - - 'should throw if not at least 1 builtin plugin in options.enabledPlugins': () => { - try { - formidable({ enabledPlugins: [] }); - } catch (err) { - assert(err, 'should throw error'); - assert( - /expect at least 1 enabled builtin/i.test(err.message), - 'expect at least 1 plugin in options.enabledPlugins', - ); - } - }, -}); diff --git a/yarn.lock b/yarn.lock index 92dee020..071c51d5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -462,6 +462,14 @@ abab@^2.0.0: resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.3.tgz#623e2075e02eb2d3f2475e49f99c91846467907a" integrity sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg== +accepts@^1.3.5: + version "1.3.7" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" + integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== + dependencies: + mime-types "~2.1.24" + negotiator "0.6.2" + acorn-globals@^4.3.2: version "4.3.4" resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-4.3.4.tgz#9fa1926addc11c97308c4e66d7add0d40c3272e7" @@ -540,6 +548,11 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: "@types/color-name" "^1.1.1" color-convert "^2.0.1" +any-promise@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" + integrity sha1-q8av7tzqUugJzcA3au0845Y10X8= + anymatch@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" @@ -622,6 +635,11 @@ array.prototype.flat@^1.2.1: define-properties "^1.1.3" es-abstract "^1.17.0-next.1" +asap@^2.0.0: + version "2.0.6" + resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" + integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= + asn1@~0.2.3: version "0.2.4" resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" @@ -799,6 +817,14 @@ cache-base@^1.0.1: union-value "^1.0.0" unset-value "^1.0.0" +cache-content-type@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cache-content-type/-/cache-content-type-1.0.1.tgz#035cde2b08ee2129f4a8315ea8f00a00dba1453c" + integrity sha512-IKufZ1o4Ut42YUrZSo8+qnMTrFuKkvyoLXUywKz9GJ5BrhOFGhLdkx9sG4KAnVvbY6kEcSFjLQul+DVmBm2bgA== + dependencies: + mime-types "^2.1.18" + ylru "^1.2.0" + caching-transform@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/caching-transform/-/caching-transform-4.0.0.tgz#00d297a4206d71e2163c39eaffa8157ac0651f0f" @@ -948,7 +974,7 @@ commondir@^1.0.1: resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= -component-emitter@^1.2.1: +component-emitter@^1.2.0, component-emitter@^1.2.1: version "1.3.0" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== @@ -968,6 +994,18 @@ contains-path@^0.1.0: resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" integrity sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo= +content-disposition@~0.5.2: + version "0.5.3" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" + integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g== + dependencies: + safe-buffer "5.1.2" + +content-type@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== + convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" @@ -975,12 +1013,25 @@ convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: dependencies: safe-buffer "~5.1.1" +cookiejar@^2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.2.tgz#dd8a235530752f988f9a0844f3fc589e3111125c" + integrity sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA== + +cookies@~0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/cookies/-/cookies-0.8.0.tgz#1293ce4b391740a8406e3c9870e828c4b54f3f90" + integrity sha512-8aPsApQfebXnuI+537McwYsDtjVxGm8gTIzQI3FDW6t5t/DAhERxtnbEPN/8RX+uZthoz4eCOgloXaE5cYyNow== + dependencies: + depd "~2.0.0" + keygrip "~1.1.0" + copy-descriptor@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= -core-util-is@1.0.2: +core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= @@ -1045,6 +1096,13 @@ debug@^2.2.0, debug@^2.3.3, debug@^2.6.9: dependencies: ms "2.0.0" +debug@^3.1.0: + version "3.2.6" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" + integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== + dependencies: + ms "^2.1.1" + debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" @@ -1052,6 +1110,13 @@ debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: dependencies: ms "^2.1.1" +debug@~3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== + dependencies: + ms "2.0.0" + decamelize@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" @@ -1062,6 +1127,11 @@ decode-uri-component@^0.2.0: resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= +deep-equal@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" + integrity sha1-9dJgKStmDghO/0zbyfCK0yR0SLU= + deep-is@~0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" @@ -1108,6 +1178,26 @@ delayed-stream@~1.0.0: resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= + +depd@^1.1.2, depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= + +depd@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" + integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== + +destroy@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= + detect-indent@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-6.0.0.tgz#0abd0f549f69fc6659a254fe96786186b6f528fd" @@ -1118,6 +1208,14 @@ detect-newline@3.1.0, detect-newline@^3.0.0: resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== +dezalgo@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456" + integrity sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY= + dependencies: + asap "^2.0.0" + wrappy "1" + diff-sequences@^25.1.0: version "25.1.0" resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-25.1.0.tgz#fd29a46f1c913fd66c22645dc75bffbe43051f32" @@ -1160,6 +1258,11 @@ ecc-jsbn@~0.1.1: jsbn "~0.1.0" safer-buffer "^2.1.0" +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= + emoji-regex@^7.0.1: version "7.0.3" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" @@ -1170,6 +1273,11 @@ emoji-regex@^8.0.0: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== +encodeurl@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= + end-of-stream@^1.1.0: version "1.4.4" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" @@ -1184,6 +1292,11 @@ error-ex@^1.2.0: dependencies: is-arrayish "^0.2.1" +error-inject@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/error-inject/-/error-inject-1.0.0.tgz#e2b3d91b54aed672f309d950d154850fa11d4f37" + integrity sha1-4rPZG1Su1nLzCdlQ0VSFD6EdTzc= + es-abstract@^1.17.0, es-abstract@^1.17.0-next.1, es-abstract@^1.17.2: version "1.17.4" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.4.tgz#e3aedf19706b20e7c2594c35fc0d57605a79e184" @@ -1215,6 +1328,11 @@ es6-error@^4.0.1: resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d" integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg== +escape-html@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= + escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" @@ -1469,7 +1587,7 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2: assign-symbols "^1.0.0" is-extendable "^1.0.1" -extend@~3.0.2: +extend@^3.0.0, extend@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== @@ -1639,6 +1757,15 @@ forever-agent@~0.6.1: resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= +form-data@^2.3.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.5.1.tgz#f2cbec57b5e59e23716e128fe44d4e5dd23895f4" + integrity sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.6" + mime-types "^2.1.12" + form-data@~2.3.2: version "2.3.3" resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" @@ -1648,6 +1775,11 @@ form-data@~2.3.2: combined-stream "^1.0.6" mime-types "^2.1.12" +formidable@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/formidable/-/formidable-1.2.1.tgz#70fb7ca0290ee6ff961090415f4b3df3d2082659" + integrity sha512-Fs9VRguL0gqGHkXS5GQiMCr1VhZBxz0JnJs4JmMp/2jL18Fmbzvv7vOFRU+U8TBkHEE/CX1qDXzJplVULgsLeg== + fragment-cache@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" @@ -1655,6 +1787,11 @@ fragment-cache@^0.2.1: dependencies: map-cache "^0.2.2" +fresh@~0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= + fromentries@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/fromentries/-/fromentries-1.2.0.tgz#e6aa06f240d6267f913cea422075ef88b63e7897" @@ -1872,6 +2009,25 @@ html-escaper@^2.0.0: resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.0.tgz#71e87f931de3fe09e56661ab9a29aadec707b491" integrity sha512-a4u9BeERWGu/S8JiWEAQcdrg9v4QArtP9keViQjGMdff20fBdd8waotXaNmODqBe6uZ3Nafi7K/ho4gCQHV3Ig== +http-assert@^1.3.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/http-assert/-/http-assert-1.4.1.tgz#c5f725d677aa7e873ef736199b89686cceb37878" + integrity sha512-rdw7q6GTlibqVVbXr0CKelfV5iY8G2HqEUkhSk297BMbSpSL8crXC+9rjKoMcZZEsksX30le6f/4ul4E28gegw== + dependencies: + deep-equal "~1.0.1" + http-errors "~1.7.2" + +http-errors@^1.6.3, http-errors@~1.7.2: + version "1.7.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" + integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw== + dependencies: + depd "~1.1.2" + inherits "2.0.4" + setprototypeof "1.1.1" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.0" + http-signature@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" @@ -1937,7 +2093,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2: +inherits@2, inherits@2.0.4, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -2071,6 +2227,11 @@ is-generator-fn@^2.0.0: resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== +is-generator-function@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.7.tgz#d2132e529bb0000a7f80794d4bdf5cd5e5813522" + integrity sha512-YZc5EwyO4f2kWCax7oegfuSr9mFz1ZvieNYBEjmukLxgXfBUbxAWGVF7GZf0zidYtoBl3WvC07YK0wT76a+Rtw== + is-glob@^4.0.0, is-glob@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" @@ -2146,7 +2307,7 @@ is-wsl@^2.1.1: resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.1.1.tgz#4a1c152d429df3d441669498e2486d3596ebaf1d" integrity sha512-umZHcSrwlDHo2TGMXv0DZ8dIUGunZ2Iv68YZnrmCiBPkZ4aaOhtv7pXJKeki9k3qJ3RJr0cDyitcl5wEH3AYog== -isarray@1.0.0, isarray@^1.0.0: +isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= @@ -2677,6 +2838,13 @@ jsprim@^1.2.2: json-schema "0.2.3" verror "1.10.0" +keygrip@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/keygrip/-/keygrip-1.1.0.tgz#871b1681d5e159c62a445b0c74b615e0917e7226" + integrity sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ== + dependencies: + tsscmp "1.0.6" + kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" @@ -2706,6 +2874,56 @@ kleur@^3.0.3: resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== +koa-compose@^3.0.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/koa-compose/-/koa-compose-3.2.1.tgz#a85ccb40b7d986d8e5a345b3a1ace8eabcf54de7" + integrity sha1-qFzLQLfZhtjlo0Wzoazo6rz1Tec= + dependencies: + any-promise "^1.1.0" + +koa-compose@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/koa-compose/-/koa-compose-4.1.0.tgz#507306b9371901db41121c812e923d0d67d3e877" + integrity sha512-8ODW8TrDuMYvXRwra/Kh7/rJo9BtOfPc6qO8eAfC80CnCvSjSl0bkRM24X6/XBBEyj0v1nRUQ1LyOy3dbqOWXw== + +koa-convert@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/koa-convert/-/koa-convert-1.2.0.tgz#da40875df49de0539098d1700b50820cebcd21d0" + integrity sha1-2kCHXfSd4FOQmNFwC1CCDOvNIdA= + dependencies: + co "^4.6.0" + koa-compose "^3.0.0" + +koa@^2.11.0: + version "2.11.0" + resolved "https://registry.yarnpkg.com/koa/-/koa-2.11.0.tgz#fe5a51c46f566d27632dd5dc8fd5d7dd44f935a4" + integrity sha512-EpR9dElBTDlaDgyhDMiLkXrPwp6ZqgAIBvhhmxQ9XN4TFgW+gEz6tkcsNI6BnUbUftrKDjVFj4lW2/J2aNBMMA== + dependencies: + accepts "^1.3.5" + cache-content-type "^1.0.0" + content-disposition "~0.5.2" + content-type "^1.0.4" + cookies "~0.8.0" + debug "~3.1.0" + delegates "^1.0.0" + depd "^1.1.2" + destroy "^1.0.4" + encodeurl "^1.0.2" + error-inject "^1.0.0" + escape-html "^1.0.3" + fresh "~0.5.2" + http-assert "^1.3.0" + http-errors "^1.6.3" + is-generator-function "^1.0.7" + koa-compose "^4.1.0" + koa-convert "^1.2.0" + on-finished "^2.3.0" + only "~0.0.2" + parseurl "^1.3.2" + statuses "^1.5.0" + type-is "^1.6.16" + vary "^1.1.2" + leven@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" @@ -2792,6 +3010,11 @@ map-visit@^1.0.0: dependencies: object-visit "^1.0.0" +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= + merge-stream@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" @@ -2802,6 +3025,11 @@ merge2@^1.2.3, merge2@^1.3.0: resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.3.0.tgz#5b366ee83b2f1582c48f87e47cf1a9352103ca81" integrity sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw== +methods@^1.1.1, methods@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= + micromatch@^3.1.4: version "3.1.10" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" @@ -2834,13 +3062,18 @@ mime-db@1.43.0: resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.43.0.tgz#0a12e0502650e473d735535050e7c8f4eb4fae58" integrity sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ== -mime-types@^2.1.12, mime-types@~2.1.19: +mime-types@^2.1.12, mime-types@^2.1.18, mime-types@~2.1.19, mime-types@~2.1.24: version "2.1.26" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.26.tgz#9c921fc09b7e149a65dfdc0da4d20997200b0a06" integrity sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ== dependencies: mime-db "1.43.0" +mime@^1.4.1: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + mimic-fn@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" @@ -2915,6 +3148,11 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= +negotiator@0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" + integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== + nice-try@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" @@ -3099,6 +3337,13 @@ object.values@^1.1.0: function-bind "^1.1.1" has "^1.0.3" +on-finished@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= + dependencies: + ee-first "1.1.1" + once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -3113,6 +3358,11 @@ onetime@^5.1.0: dependencies: mimic-fn "^2.1.0" +only@~0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/only/-/only-0.0.2.tgz#2afde84d03e50b9a8edc444e30610a70295edfb4" + integrity sha1-Kv3oTQPlC5qO3EROMGEKcCle37Q= + optionator@^0.8.1, optionator@^0.8.3: version "0.8.3" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" @@ -3219,6 +3469,11 @@ parse5@5.1.0: resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.0.tgz#c59341c9723f414c452975564c7c00a68d58acd2" integrity sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ== +parseurl@^1.3.2: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + pascalcase@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" @@ -3346,6 +3601,11 @@ pretty-format@^25.1.0: ansi-styles "^4.0.0" react-is "^16.12.0" +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + process-on-spawn@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/process-on-spawn/-/process-on-spawn-1.0.0.tgz#95b05a23073d30a17acfdc92a440efd2baefdc93" @@ -3389,6 +3649,11 @@ punycode@^2.1.0, punycode@^2.1.1: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== +qs@^6.5.1: + version "6.9.1" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.1.tgz#20082c65cb78223635ab1a9eaca8875a29bf8ec9" + integrity sha512-Cxm7/SS/y/Z3MHWSxXb8lIFqgqBowP5JMlTUFyJN88y0SGQhVmZnqFK/PeuMX9LzUyWsqqhNxIyg0jlzq946yA== + qs@~6.5.2: version "6.5.2" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" @@ -3416,6 +3681,19 @@ read-pkg@^2.0.0: normalize-package-data "^2.3.2" path-type "^2.0.0" +readable-stream@^2.3.5: + version "2.3.7" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + realpath-native@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/realpath-native/-/realpath-native-1.1.0.tgz#2003294fea23fb0672f2476ebe22fcf498a2d65c" @@ -3600,16 +3878,16 @@ rxjs@^6.5.3: dependencies: tslib "^1.9.0" +safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + safe-buffer@^5.0.1, safe-buffer@^5.1.2: version "5.2.0" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519" integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg== -safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - safe-regex@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" @@ -3674,6 +3952,11 @@ set-value@^2.0.0, set-value@^2.0.1: is-plain-object "^2.0.3" split-string "^3.0.1" +setprototypeof@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" + integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== + shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" @@ -3890,6 +4173,11 @@ static-extend@^0.1.1: define-property "^0.2.5" object-copy "^0.1.0" +"statuses@>= 1.5.0 < 2", statuses@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= + stealthy-require@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" @@ -3937,6 +4225,13 @@ string.prototype.trimright@^2.1.1: define-properties "^1.1.3" function-bind "^1.1.1" +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + strip-ansi@^5.1.0, strip-ansi@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" @@ -3976,6 +4271,30 @@ strip-json-comments@^3.0.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.0.1.tgz#85713975a91fb87bf1b305cca77395e40d2a64a7" integrity sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw== +superagent@^3.8.3: + version "3.8.3" + resolved "https://registry.yarnpkg.com/superagent/-/superagent-3.8.3.tgz#460ea0dbdb7d5b11bc4f78deba565f86a178e128" + integrity sha512-GLQtLMCoEIK4eDv6OGtkOoSMt3D+oq0y3dsxMuYuDvaNUvuT8eFBuLmfR0iYYzHC1e8hpzC6ZsxbuP6DIalMFA== + dependencies: + component-emitter "^1.2.0" + cookiejar "^2.1.0" + debug "^3.1.0" + extend "^3.0.0" + form-data "^2.3.1" + formidable "^1.2.0" + methods "^1.1.1" + mime "^1.4.1" + qs "^6.5.1" + readable-stream "^2.3.5" + +supertest@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/supertest/-/supertest-4.0.2.tgz#c2234dbdd6dc79b6f15b99c8d6577b90e4ce3f36" + integrity sha512-1BAbvrOZsGA3YTCWqbmh14L0YEq0EGICX/nBnfkfVJn7SrxQV1I3pMYjSzG9y/7ZU2V9dWqyqk2POwxlb09duQ== + dependencies: + methods "^1.1.2" + superagent "^3.8.3" + supports-color@^5.3.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" @@ -4094,6 +4413,11 @@ to-regex@^3.0.1, to-regex@^3.0.2: regex-not "^1.0.2" safe-regex "^1.1.0" +toidentifier@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" + integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== + tough-cookie@^2.3.3: version "2.5.0" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" @@ -4131,6 +4455,11 @@ tslib@^1.9.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== +tsscmp@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/tsscmp/-/tsscmp-1.0.6.tgz#85b99583ac3589ec4bfef825b5000aa911d605eb" + integrity sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA== + tunnel-agent@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" @@ -4160,6 +4489,14 @@ type-fest@^0.8.0, type-fest@^0.8.1: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== +type-is@^1.6.16: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + typedarray-to-buffer@^3.1.5: version "3.1.5" resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" @@ -4212,6 +4549,11 @@ utest@^0.0.8: resolved "https://registry.yarnpkg.com/utest/-/utest-0.0.8.tgz#fc09451fe697b9008d0c432fe0db439d6cf37914" integrity sha1-/AlFH+aXuQCNDEMv4NtDnWzzeRQ= +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + util.promisify@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.1.tgz#6baf7774b80eeb0f7520d8b81d07982a59abbaee" @@ -4249,6 +4591,11 @@ validate-npm-package-license@^3.0.1: spdx-correct "^3.0.0" spdx-expression-parse "^3.0.0" +vary@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= + verror@1.10.0: version "1.10.0" resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" @@ -4406,3 +4753,8 @@ yargs@^15.0.0, yargs@^15.0.2: which-module "^2.0.0" y18n "^4.0.0" yargs-parser "^16.1.0" + +ylru@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ylru/-/ylru-1.2.1.tgz#f576b63341547989c1de7ba288760923b27fe84f" + integrity sha512-faQrqNMzcPCHGVC2aaOINk13K+aaBDUPjGWl0teOXywElLjyVAB6Oe2jj62jHYtwsU49jXhScYbvPENK+6zAvQ== From b44bcbd3f061a5bc025c1b0ed584b712851c5be5 Mon Sep 17 00:00:00 2001 From: Charlike Mike Reagent Date: Thu, 30 Jan 2020 03:15:50 +0200 Subject: [PATCH 10/19] chore: tweaks, publish `dev` dist-tag (with Plugins API) Signed-off-by: Charlike Mike Reagent --- README.md | 1 + package.json | 15 ++++++++------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 058af4c6..db7a6230 100644 --- a/README.md +++ b/README.md @@ -482,6 +482,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d + ## License diff --git a/package.json b/package.json index 2e730dc6..90c9c3ec 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "formidable", - "version": "2.0.0-canary.20200129.32", + "version": "2.0.0-dev.20200130.1", "license": "MIT", "description": "A node.js module for parsing form data, especially file uploads.", "homepage": "https://github.com/node-formidable/node-formidable", @@ -8,11 +8,12 @@ "repository": "node-formidable/node-formidable", "main": "./src/index.js", "files": [ - "src" + "src", + "test" ], "publishConfig": { "access": "public", - "tag": "canary" + "tag": "dev" }, "scripts": { "cleanup": "rm -rf test/tmp", @@ -23,6 +24,10 @@ "pretest:ci": "yarn pretest", "test:ci": "nyc node test/run.js" }, + "dependencies": { + "dezalgo": "^1.0.3", + "once": "^1.4.0" + }, "devDependencies": { "@tunnckocore/prettier-config": "^1.2.0", "eslint": "^6.8.0", @@ -39,9 +44,5 @@ "supertest": "^4.0.2", "urun": "^0.0.8", "utest": "^0.0.8" - }, - "dependencies": { - "dezalgo": "^1.0.3", - "once": "^1.4.0" } } From d6cd110db117999e1867229ec3cb7dffe9495386 Mon Sep 17 00:00:00 2001 From: Charlike Mike Reagent Date: Fri, 31 Jan 2020 10:53:17 +0200 Subject: [PATCH 11/19] chore: sync & tweak Signed-off-by: Charlike Mike Reagent --- src/Formidable.js | 5 ---- yarn.lock | 69 ++++++++++++++++++++++------------------------- 2 files changed, 32 insertions(+), 42 deletions(-) diff --git a/src/Formidable.js b/src/Formidable.js index 3d8246ce..15548caa 100644 --- a/src/Formidable.js +++ b/src/Formidable.js @@ -376,11 +376,6 @@ class IncomingForm extends EventEmitter { // ), // ); // } - this._error( - new Error( - `bad content-type header, unknown content-type: ${this.headers['content-type']}`, - ), - ); } _error(err, eventName = 'error') { diff --git a/yarn.lock b/yarn.lock index 3bb276c5..22c0f5f5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -589,9 +589,6 @@ integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== "@types/node@*": - version "13.5.1" - resolved "https://registry.yarnpkg.com/@types/node/-/node-13.5.1.tgz#6fae50892d1841f4b38b298e2f78fb68c5960cb9" - integrity sha512-Jj2W7VWQ2uM83f8Ls5ON9adxN98MvyJsMSASYFuSvrov8RMRY64Ayay7KV35ph1TSGIJ2gG9ZVDdEq3c3zaydA== version "13.5.3" resolved "https://registry.yarnpkg.com/@types/node/-/node-13.5.3.tgz#37f1f539b7535b9fb4ef77d59db1847a837b7f17" integrity sha512-ZPnWX9PW992w6DUsz3JIXHaSb5v7qmKCVzC3km6SxcDGxk7zmLfYaCJTbktIa5NeywJkkZDhGldKqDIvC5DRrA== @@ -737,15 +734,16 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: "@types/color-name" "^1.1.1" color-convert "^2.0.1" -any-promise@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" - integrity sha1-q8av7tzqUugJzcA3au0845Y10X8= any-observable@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/any-observable/-/any-observable-0.3.0.tgz#af933475e5806a67d0d7df090dd5e8bef65d119b" integrity sha512-/FQM1EDkTsf63Ub2C6O7GuYFDsSXUwsaZDurV0np41ocwq0jthUAYCmhBX9f+KwlaCgIuWyr/4WlUQUBfKfZog== +any-promise@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" + integrity sha1-q8av7tzqUugJzcA3au0845Y10X8= + anymatch@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" @@ -838,15 +836,16 @@ array.prototype.flat@^1.2.1: define-properties "^1.1.3" es-abstract "^1.17.0-next.1" -asap@^2.0.0: - version "2.0.6" - resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" - integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= arrify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= +asap@^2.0.0: + version "2.0.6" + resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" + integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= + asn1@~0.2.3: version "0.2.4" resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" @@ -1267,7 +1266,6 @@ commondir@^1.0.1: resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= -component-emitter@^1.2.0, component-emitter@^1.2.1: compare-func@^1.3.1: version "1.3.2" resolved "https://registry.yarnpkg.com/compare-func/-/compare-func-1.3.2.tgz#99dd0ba457e1f9bc722b12c08ec33eeab31fa648" @@ -1281,7 +1279,7 @@ compare-versions@^3.5.1: resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.5.1.tgz#26e1f5cf0d48a77eced5046b9f67b6b61075a393" integrity sha512-9fGPIB7C6AyM18CJJBHt5EnCZDG3oiTJYy0NjfIAGjKpzv0tkxWko7TNQHF5ymqm7IH03tqmeuBxtvD+Izh6mg== -component-emitter@^1.2.1: +component-emitter@^1.2.0, component-emitter@^1.2.1: version "1.3.0" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== @@ -1312,6 +1310,7 @@ content-type@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== + conventional-changelog-angular@^1.3.3: version "1.6.6" resolved "https://registry.yarnpkg.com/conventional-changelog-angular/-/conventional-changelog-angular-1.6.6.tgz#b27f2b315c16d0a1f23eb181309d0e6a4698ea0f" @@ -1498,7 +1497,6 @@ debug@~3.1.0: dependencies: ms "2.0.0" -decamelize@^1.2.0: decamelize-keys@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9" @@ -1517,15 +1515,16 @@ decode-uri-component@^0.2.0: resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= -deep-equal@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" - integrity sha1-9dJgKStmDghO/0zbyfCK0yR0SLU= dedent@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" integrity sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw= +deep-equal@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" + integrity sha1-9dJgKStmDghO/0zbyfCK0yR0SLU= + deep-is@~0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" @@ -1663,6 +1662,7 @@ ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= + elegant-spinner@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/elegant-spinner/-/elegant-spinner-1.0.1.tgz#db043521c95d7e303fd8f345bedc3349cfb0729e" @@ -1738,7 +1738,6 @@ escape-html@^1.0.3: resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= -escape-string-regexp@^1.0.5: escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" @@ -2585,8 +2584,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@~2.0.3: -inherits@2, inherits@^2.0.3, inherits@~2.0.3: +inherits@2, inherits@2.0.4, inherits@^2.0.3, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -3492,9 +3490,9 @@ lines-and-columns@^1.1.6: integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= lint-staged@^10.0.6: - version "10.0.6" - resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-10.0.6.tgz#62d3f49a09a12e4df876dd8667a09d9a2d39495c" - integrity sha512-pz3k0J2/+sy2a2pUsMMCpbsChcK8nIyDIf73xAHPqXQRPogBedb0r/nHDKgrtu9v9cZ96Fc60NieoNMQoQU65Q== + version "10.0.7" + resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-10.0.7.tgz#d205f92d9359419a23bc6aa3b6f8546b1998da64" + integrity sha512-Byj0F4l7GYUpYYHEqyFH69NiI6ICTg0CeCKbhRorL+ickbzILKUlZLiyCkljZV02wnoh7yH7PmFyYm9PRNwk9g== dependencies: chalk "^3.0.0" commander "^4.0.1" @@ -3702,6 +3700,7 @@ media-typer@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= + meow@5.0.0, meow@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/meow/-/meow-5.0.0.tgz#dfc73d63a9afc714a5e371760eb5c88b91078aa4" @@ -3775,6 +3774,7 @@ mime@^1.4.1: version "1.6.0" resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + mimic-fn@^1.0.0: version "1.2.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" @@ -4093,6 +4093,7 @@ only@~0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/only/-/only-0.0.2.tgz#2afde84d03e50b9a8edc444e30610a70295edfb4" integrity sha1-Kv3oTQPlC5qO3EROMGEKcCle37Q= + opencollective-postinstall@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/opencollective-postinstall/-/opencollective-postinstall-2.0.2.tgz#5657f1bede69b6e33a45939b061eb53d3c6c3a89" @@ -4426,15 +4427,16 @@ punycode@^2.1.0, punycode@^2.1.1: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== -qs@^6.5.1: - version "6.9.1" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.1.tgz#20082c65cb78223635ab1a9eaca8875a29bf8ec9" - integrity sha512-Cxm7/SS/y/Z3MHWSxXb8lIFqgqBowP5JMlTUFyJN88y0SGQhVmZnqFK/PeuMX9LzUyWsqqhNxIyg0jlzq946yA== q@^1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= +qs@^6.5.1: + version "6.9.1" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.1.tgz#20082c65cb78223635ab1a9eaca8875a29bf8ec9" + integrity sha512-Cxm7/SS/y/Z3MHWSxXb8lIFqgqBowP5JMlTUFyJN88y0SGQhVmZnqFK/PeuMX9LzUyWsqqhNxIyg0jlzq946yA== + qs@~6.5.2: version "6.5.2" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" @@ -4475,7 +4477,6 @@ read-pkg@^2.0.0: normalize-package-data "^2.3.2" path-type "^2.0.0" -readable-stream@^2.3.5: read-pkg@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" @@ -4494,7 +4495,7 @@ read-pkg@^3.0.0: string_decoder "^1.1.1" util-deprecate "^1.0.1" -readable-stream@~2.3.6: +readable-stream@^2.3.5, readable-stream@~2.3.6: version "2.3.7" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== @@ -4746,17 +4747,11 @@ safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-buffer@^5.0.1, safe-buffer@^5.1.2: safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519" integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg== -safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - safe-regex@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" @@ -5242,6 +5237,7 @@ supertest@^4.0.2: dependencies: methods "^1.1.2" superagent "^3.8.3" + supports-color@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" @@ -5536,7 +5532,6 @@ utest@^0.0.8: resolved "https://registry.yarnpkg.com/utest/-/utest-0.0.8.tgz#fc09451fe697b9008d0c432fe0db439d6cf37914" integrity sha1-/AlFH+aXuQCNDEMv4NtDnWzzeRQ= -util-deprecate@~1.0.1: util-deprecate@^1.0.1, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" From 2c35e723a00c2c7408c319f053078739449b1602 Mon Sep 17 00:00:00 2001 From: Charlike Mike Reagent Date: Fri, 31 Jan 2020 11:12:18 +0200 Subject: [PATCH 12/19] fix: check strictly for multipart/form-data in multipart parser Signed-off-by: Charlike Mike Reagent --- src/plugins/multipart.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/multipart.js b/src/plugins/multipart.js index b7d37468..66bd4cad 100644 --- a/src/plugins/multipart.js +++ b/src/plugins/multipart.js @@ -13,7 +13,7 @@ module.exports = function plugin(formidable, options) { /* istanbul ignore next */ const self = this || formidable; - if (/multipart|form-data/i.test(self.headers['content-type'])) { + if (/multipart\/form-data/i.test(self.headers['content-type'])) { const m = self.headers['content-type'].match( /boundary=(?:"([^"]+)"|([^;]+))/i, ); From 3ebbbd092b3e085f601936ebd5a4f64370d722da Mon Sep 17 00:00:00 2001 From: Charlike Mike Reagent Date: Fri, 31 Jan 2020 11:14:22 +0200 Subject: [PATCH 13/19] chore: publish dev.2 Signed-off-by: Charlike Mike Reagent --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c4076792..a91fd58a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "formidable", - "version": "2.0.0-dev.20200130.1", + "version": "2.0.0-dev.20200131.2", "license": "MIT", "description": "A node.js module for parsing form data, especially file uploads.", "homepage": "https://github.com/node-formidable/node-formidable", From 3e3a27a4012b63458fa8beebf220e0096dd4a782 Mon Sep 17 00:00:00 2001 From: Charlike Mike Reagent Date: Fri, 31 Jan 2020 11:42:49 +0200 Subject: [PATCH 14/19] fix: tests updates Signed-off-by: Charlike Mike Reagent --- test/standalone/test-issue-46.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/standalone/test-issue-46.js b/test/standalone/test-issue-46.js index 711a16ee..e95c13ce 100644 --- a/test/standalone/test-issue-46.js +++ b/test/standalone/test-issue-46.js @@ -48,8 +48,8 @@ server.listen(PORT, () => { request({ method: 'POST', url, multipart: parts }, (e, res, body) => { const obj = JSON.parse(body); - assert.strictEqual('foo' in obj.fields, true); - assert.strictEqual('barry', obj.fields.foo); + assert.ok(obj.fields.foo, 'should havce fields.foo === barry'); + assert.strictEqual(obj.fields.foo, 'barry'); server.close(); }); }); From bc3445956fa9f373865a517d55da706e6f6f0a58 Mon Sep 17 00:00:00 2001 From: Charlike Mike Reagent Date: Fri, 31 Jan 2020 20:46:12 +0200 Subject: [PATCH 15/19] fix: it seems we support multipart/related too Signed-off-by: Charlike Mike Reagent --- src/plugins/multipart.js | 5 ++++- test/standalone/test-issue-46.js | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/plugins/multipart.js b/src/plugins/multipart.js index 66bd4cad..b5c1c088 100644 --- a/src/plugins/multipart.js +++ b/src/plugins/multipart.js @@ -13,7 +13,10 @@ module.exports = function plugin(formidable, options) { /* istanbul ignore next */ const self = this || formidable; - if (/multipart\/form-data/i.test(self.headers['content-type'])) { + // NOTE: we (currently) support both multipart/form-data and multipart/related + const multipart = /multipart/i.test(self.headers['content-type']); + + if (multipart) { const m = self.headers['content-type'].match( /boundary=(?:"([^"]+)"|([^;]+))/i, ); diff --git a/test/standalone/test-issue-46.js b/test/standalone/test-issue-46.js index e95c13ce..a2189dcc 100644 --- a/test/standalone/test-issue-46.js +++ b/test/standalone/test-issue-46.js @@ -48,8 +48,9 @@ server.listen(PORT, () => { request({ method: 'POST', url, multipart: parts }, (e, res, body) => { const obj = JSON.parse(body); - assert.ok(obj.fields.foo, 'should havce fields.foo === barry'); + assert.ok(obj.fields.foo, 'should have fields.foo === barry'); assert.strictEqual(obj.fields.foo, 'barry'); + server.close(); }); }); From 282971dad36cf4b7d13c2e89b743eaf1068461d5 Mon Sep 17 00:00:00 2001 From: Charlike Mike Reagent Date: Wed, 5 Feb 2020 13:59:12 +0200 Subject: [PATCH 16/19] chore: download badges Signed-off-by: Charlike Mike Reagent --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 5cdd645e..73a84023 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,9 @@ [![Make A Pull Request][prs-welcome-img]][prs-welcome-url] [![Twitter][twitter-img]][twitter-url] +[![][npm-weekly-img]][npmv-url] [![][npm-monthly-img]][npmv-url] +[![][npm-yearly-img]][npmv-url] [![][npm-alltime-img]][npmv-url] + ## Status: Maintained [![npm version][npmv-canary-img]][npmv-url] [![npm version][npmv-dev-img]][npmv-url] This module was initially developed by @@ -564,4 +567,9 @@ Formidable is licensed under the [MIT License][license-url]. [twitter-url]: https://twitter.com/tunnckoCore [twitter-img]: https://badgen.net/twitter/follow/tunnckoCore?icon=twitter&color=1da1f2&cache=300 +[npm-weekly-img]: https://badgen.net/npm/dw/formidable?icon=npm&cache=300 +[npm-monthly-img]: https://badgen.net/npm/dm/formidable?icon=npm&cache=300 +[npm-yearly-img]: https://badgen.net/npm/dy/formidable?icon=npm&cache=300 +[npm-alltime-img]: https://badgen.net/npm/dt/formidable?icon=npm&cache=300 + From 81c79fdca3149a546d5bf82ea6f5ecc9f02636ab Mon Sep 17 00:00:00 2001 From: Charlike Mike Reagent Date: Wed, 12 Feb 2020 15:50:23 +0200 Subject: [PATCH 17/19] Update package.json --- package.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/package.json b/package.json index 148ec005..801b60a4 100644 --- a/package.json +++ b/package.json @@ -42,11 +42,13 @@ "eslint-plugin-prettier": "^3.1.2", "husky": "^4.2.2", "jest": "^25.1.0", + "koa": "^2.11.0", "lint-staged": "^10.0.7", "nyc": "^15.0.0", "prettier": "^1.19.1", "prettier-plugin-pkgjson": "^0.2.3", "request": "^2.88.2", + "supertest": "^4.0.2", "urun": "^0.0.8", "utest": "^0.0.8" }, From e5312139577094bd6d843ad95af5416f872b0ba3 Mon Sep 17 00:00:00 2001 From: Charlike Mike Reagent Date: Wed, 12 Feb 2020 15:53:23 +0200 Subject: [PATCH 18/19] chore: sync Signed-off-by: Charlike Mike Reagent --- yarn.lock | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/yarn.lock b/yarn.lock index 8b0256eb..2e7e2345 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5381,6 +5381,11 @@ to-regex@^3.0.1, to-regex@^3.0.2: regex-not "^1.0.2" safe-regex "^1.1.0" +toidentifier@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" + integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== + tough-cookie@^2.3.3, tough-cookie@~2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" From 5b813a51711d2a9c883adf2a778c6efef8122c39 Mon Sep 17 00:00:00 2001 From: Charlike Mike Reagent Date: Wed, 12 Feb 2020 16:00:30 +0200 Subject: [PATCH 19/19] chore: update npm funding link, tag to canary [skip ci] Signed-off-by: Charlike Mike Reagent --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 801b60a4..b5789a9a 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "license": "MIT", "description": "A node.js module for parsing form data, especially file uploads.", "homepage": "https://github.com/node-formidable/node-formidable", - "funding": "https://ko-fi.com/tunnckoCore/commissions", + "funding": "https://tidelift.com/funding/github/npm/formidable", "repository": "node-formidable/node-formidable", "main": "./src/index.js", "files": [ @@ -13,7 +13,7 @@ ], "publishConfig": { "access": "public", - "tag": "dev" + "tag": "canary" }, "scripts": { "bench": "node benchmark",