first commit

This commit is contained in:
Tim Considine 2022-01-29 12:10:50 +02:00
parent ec43a9e894
commit 4132e00c28
104 changed files with 13101 additions and 0 deletions

9
CloudronManifest.json Normal file
View File

@ -0,0 +1,9 @@
{
"version": "0.1.0",
"healthCheckPath": "/",
"httpPort": 3000,
"addons": {
"localstorage": {}
},
"manifestVersion": 2
}

159
awesomebox.sty Normal file
View File

@ -0,0 +1,159 @@
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{awesomebox}[2019/07/27 v0.6]
% Awesome Box has been written by Étienne Deparis and is released under
% the WTFPL (http://www.wtfpl.net/txt/copying/).
% A copy of this license is distributed in this package.
%
% Contributors:
% v0.2: Vincent Goulet https://github.com/vigou3
% v0.3: Gilbert Fuerer https://github.com/foreachthing
% * Remove xelatex/luatex requirement and add pdflatex compatibility
% v0.4: Marcel Krüger https://github.com/zauguin
% * Fontawesome5 compatibility
% Gilbert Fuerer
% * Custom vertical rule color
% v0.5: Georger Araújo https://github.com/georgerbr
% * Horizontal rules at top and bottom, title
% v0.6: Vincent Goulet https://github.com/vigou3
% * Improving table cell rendering
% https://ctan.org/pkg/fontawesome5
\RequirePackage{fontawesome5}
% Compatibility with old version of this package
\def\abIconCheck{\faCheck}
\def\abIconInfoCircle{\faInfoCircle}
\def\abIconFire{\faBomb}
\def\abIconExclamationCircle{\faExclamationCircle}
\def\abIconExclamationTriangle{\faExclamationTriangle}
\def\abIconCogs{\faCogs}
\def\abIconThumbsUp{\faThumbsUp}
\def\abIconThumbsDown{\faThumbsDown}
\def\abIconCertificate{\faCertificate}
\def\abIconLightBulb{\faLightbulb[regular]}
\def\abIconTwitter{\faTwitter}
\def\abIconGithub{\faGithub}
% https://ctan.org/pkg/xcolor
\RequirePackage{xcolor}
% Some basic colors
\definecolor{abnote}{RGB}{25,64,122}
\definecolor{abcaution}{RGB}{245,0,0}
\definecolor{abwarning}{RGB}{255,215,0}
\definecolor{abimportant}{RGB}{220,0,0}
\definecolor{abvrulecolor}{RGB}{221,221,216}
% Customizable length
\newlength{\aweboxleftmargin}
\newlength{\aweboxcontentwidth}
\newlength{\aweboxvskip}
\setlength{\aweboxvskip}{5mm}
\newlength{\aweboxsignraise}
\setlength{\aweboxsignraise}{-5mm}
\newlength{\aweboxrulewidth}
\setlength{\aweboxrulewidth}{2pt}
\AtBeginDocument{%
\setlength{\aweboxleftmargin}{0.12\linewidth}%
\setlength{\aweboxcontentwidth}{0.88\linewidth}}
\RequirePackage{array}
% To allow for more than one optional argument
\RequirePackage{xparse}
% Horizontal rule definitions used with second optional argument [hrule]
\def\abShortLine{\cline{2-2}}
\def\abLongLine{\hline}
% The following commands are used to adjust and restore awesome boxes
% content width in respect to the current environment (e.g. lists).
\RequirePackage{ifthen}
\newlength{\aweboxlinewidthvar}
\setlength{\aweboxlinewidthvar}{0pt}
\newlength{\aweboxlinewidthref}
\AtBeginDocument{\setlength{\aweboxlinewidthref}{\linewidth}}
\newcommand{\awesomeboxadjustcontentwidth}{%
\ifthenelse{\lengthtest{\linewidth=\aweboxlinewidthref}}{}{%
\setlength{\aweboxlinewidthvar}{\dimexpr\aweboxlinewidthref-\linewidth}%
\setlength{\aweboxcontentwidth}{\dimexpr\aweboxcontentwidth-\aweboxlinewidthvar}}}%
%\aweboxdebug}}
\newcommand{\awesomeboxrestorecontentwidth}{%
\ifthenelse{\lengthtest{\linewidth=\textwidth}}{}{%
\setlength{\aweboxcontentwidth}{\dimexpr\aweboxcontentwidth+\aweboxlinewidthvar}%
\setlength{\aweboxlinewidthvar}{0pt}}}
% Commands API
% \awesomebox[vrulecolor][hrule][title]{vrulewidth}{icon}{iconcolor}{content}
\NewDocumentCommand \awesomebox { O{abvrulecolor} O{} o m m m +m }{%
{\vskip \aweboxvskip}\noindent\awesomeboxadjustcontentwidth%
\begin{tabular}%
{@{}>{\centering\arraybackslash}%
p{\aweboxleftmargin}@{}!{\color{#1}\vrule width #4}%
p{\dimexpr\aweboxcontentwidth-#4-\tabcolsep}@{}}
\IfValueTF {#3}
{ & #3 \\ #2 \raisebox{\aweboxsignraise}{\textcolor{#6}{\Huge#5}} & #7 \\ #2}
{ #2 \raisebox{\aweboxsignraise}{\textcolor{#6}{\Huge#5}} & #7 \\ #2}
\end{tabular}{\vskip \aweboxvskip}\awesomeboxrestorecontentwidth}
\newcommand{\notebox}[1]{%
\awesomebox[abnote]{\aweboxrulewidth}{\abIconInfoCircle}{abnote}{#1}}
\newcommand{\tipbox}[1]{%
\awesomebox{\aweboxrulewidth}{\abIconLightBulb}{black}{#1}}
\newcommand{\warningbox}[1]{%
\awesomebox[abwarning]{\aweboxrulewidth}{\abIconExclamationTriangle}{abwarning}{#1}}
\newcommand{\cautionbox}[1]{%
\awesomebox[abcaution]{\aweboxrulewidth}{\abIconFire}{abcaution}{#1}}
\newcommand{\importantbox}[1]{%
\awesomebox[abimportant]{\aweboxrulewidth}{\abIconExclamationCircle}{abimportant}{#1}}
% Environments API
% \begin{awesomeblock}[vrulecolor][hrule][title]{vrulewidth}{icon}{iconcolor}
% content
% \end{awesomeblock}
\NewDocumentEnvironment{awesomeblock}{ O{abvrulecolor} O{} o m m m }
{{\vskip \aweboxvskip}\noindent\awesomeboxadjustcontentwidth%
\begin{tabular}%
{@{}>{\centering\arraybackslash}%
p{\aweboxleftmargin}@{}!{\color{#1}\vrule width #4}%
p{\dimexpr\aweboxcontentwidth-#4-\tabcolsep}@{}}
\IfValueTF {#3}
{ & #3 \\ #2 \raisebox{\aweboxsignraise}{\textcolor{#6}{\Huge#5}} &}
{ #2 \raisebox{\aweboxsignraise}{\textcolor{#6}{\Huge#5}} &}}
{\\ #2 \end{tabular}{\vskip \aweboxvskip}\awesomeboxrestorecontentwidth}
\newenvironment{noteblock}%
{\begin{awesomeblock}[abnote]{\aweboxrulewidth}{\abIconInfoCircle}{abnote}}
{\end{awesomeblock}}
\newenvironment{tipblock}%
{\begin{awesomeblock}{\aweboxrulewidth}{\abIconLightBulb}{black}}
{\end{awesomeblock}}
\newenvironment{warningblock}%
{\begin{awesomeblock}[abwarning]{\aweboxrulewidth}{\abIconExclamationTriangle}{abwarning}}
{\end{awesomeblock}}
\newenvironment{cautionblock}%
{\begin{awesomeblock}[abcaution]{\aweboxrulewidth}{\abIconFire}{abcaution}}
{\end{awesomeblock}}
\newenvironment{importantblock}%
{\begin{awesomeblock}[abimportant]{\aweboxrulewidth}{\abIconExclamationCircle}{abimportant}}
{\end{awesomeblock}}
\newcommand{\aweboxdebug}{%
\typeout{**************************}%
\typeout{Line width: \the\linewidth}%
\typeout{Reference line width: \the\aweboxlinewidthref\space(text width: \the\textwidth)}%
\typeout{Width difference: \the\aweboxlinewidthvar}%
\typeout{Margin width: \the\aweboxleftmargin}%
\typeout{Content width: \the\aweboxcontentwidth}%
\typeout{**************************}}
\endinput

1069
eisvogel.latex Normal file

File diff suppressed because it is too large Load Diff

29
index.html Normal file
View File

@ -0,0 +1,29 @@
<html>
<body>
<h1>Pandoc PDF Builder</h1>
<hr>
<p>Upload a source document in Markdown (.md) format plus any images to be included.</p>
<p>This app will process them using Pandoc (https://pandoc.com) with a tweaked <a href="https://github.com/Wandmalfarbe/pandoc-latex-template">eisvogel template</a> and <a href="https://www.ctan.org/tex-archive/graphics/awesomebox">awesomebox.sty</a> to create a beautiful PDF, without the hassle of manual formatting in Word etc.</p>
<p><strong>THIS IS IN ALPHA STATUS : STILL IN DEVELOPMENT.</strong></p>
<hr>
<p>Click here to upload (1) a .md Markdown file (2) any included images</p>
<form action="fileupload" method="post" enctype="multipart/form-data">
<input type="file" name="filetoupload"><br><br>
<input type="submit" value="Upload">
</form>
<br>
<hr>
<h3>Background</h3>
<p>This app is a custom (i.e. not officially developed or maintained) app packaged for Cloudron.</p>
<p>It packages an instance of the excellent document conversion utility <a href="https://pandoc.org">Pandoc</a>.</p>
<p>Pandoc only runs from the command line. By packaging it into a web app, a consistent publishing environment can be maintained in a single location (avoiding multiple local installs which might change over time) and be accessible from any device, even without Pandoc and its utilities installed.</p>
<p>It is based on Cloudron's tutorial-supervisor app and the "pandoc docker" app from <a href="https://github.com/vpetersson/docker-pandoc">Viktor Petersson</a>.</p>
<p>Once the source Markdown and related images files are uploaded, click the button to process them.</p>
<p>The app will create a PDF, which must be downloaded to the local computer, as it cannot be retrieved later.</p>
<p>The source Markdown file will be moved to /app/data/done (in future version, it will be deleted).</p>
<p>Image files will not be moved, in case they are required for subsequent PDF creations, e.g.on updating and re-uploading the source Markdown file.</p>
<p>NB : currently source image files might be overwritten by other users of the app uploading a file of the same name but different content. Your document will then be. reated with the wrong image. If so, re-upload them and retry. This issue will be addressed in a future version.</p>
</body>
</html>

128
node_modules/.package-lock.json generated vendored Normal file
View File

@ -0,0 +1,128 @@
{
"name": "pandoc-cloudron",
"version": "1.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"node_modules/asap": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
"integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY="
},
"node_modules/content-disposition": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
"integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
"dependencies": {
"safe-buffer": "5.2.1"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/destroy": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.1.0.tgz",
"integrity": "sha512-R5QZrOXxSs0JDUIU/VANvRJlQVMts9C0L76HToQdPdlftfZCE7W6dyH0G4GZ5UW9fRqUOhAoCE2aGekuu+3HjQ==",
"engines": {
"node": ">= 0.8",
"npm": "1.2.8000 || >= 1.4.16"
}
},
"node_modules/dezalgo": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz",
"integrity": "sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY=",
"dependencies": {
"asap": "^2.0.0",
"wrappy": "1"
}
},
"node_modules/ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
},
"node_modules/formidable": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/formidable/-/formidable-2.0.1.tgz",
"integrity": "sha512-rjTMNbp2BpfQShhFbR3Ruk3qk2y9jKpvMW78nJgx8QKtxjDVrwbZG+wvDOmVbifHyOUOQJXxqEy6r0faRrPzTQ==",
"dependencies": {
"dezalgo": "1.0.3",
"hexoid": "1.0.0",
"once": "1.4.0",
"qs": "6.9.3"
},
"funding": {
"url": "https://ko-fi.com/tunnckoCore/commissions"
}
},
"node_modules/fs": {
"version": "0.0.1-security",
"resolved": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz",
"integrity": "sha1-invTcYa23d84E/I4WLV+yq9eQdQ="
},
"node_modules/hexoid": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz",
"integrity": "sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==",
"engines": {
"node": ">=8"
}
},
"node_modules/on-finished": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
"integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
"dependencies": {
"ee-first": "1.1.1"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"dependencies": {
"wrappy": "1"
}
},
"node_modules/qs": {
"version": "6.9.3",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.9.3.tgz",
"integrity": "sha512-EbZYNarm6138UKKq46tdx08Yo/q9ZhFoAXAI1meAFd2GtbRDhbZY2WQSICskT0c5q99aFzLG1D4nvTk9tqfXIw==",
"engines": {
"node": ">=0.6"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
]
},
"node_modules/wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
}
}
}

70
node_modules/asap/CHANGES.md generated vendored Normal file
View File

@ -0,0 +1,70 @@
## 2.0.6
Version 2.0.4 adds support for React Native by clarifying in package.json that
the browser environment does not support Node.js domains.
Why this is necessary, we leave as an exercise for the user.
## 2.0.3
Version 2.0.3 fixes a bug when adjusting the capacity of the task queue.
## 2.0.1-2.02
Version 2.0.1 fixes a bug in the way redirects were expressed that affected the
function of Browserify, but which Mr would tolerate.
## 2.0.0
Version 2 of ASAP is a full rewrite with a few salient changes.
First, the ASAP source is CommonJS only and designed with [Browserify][] and
[Browserify-compatible][Mr] module loaders in mind.
[Browserify]: https://github.com/substack/node-browserify
[Mr]: https://github.com/montagejs/mr
The new version has been refactored in two dimensions.
Support for Node.js and browsers have been separated, using Browserify
redirects and ASAP has been divided into two modules.
The "raw" layer depends on the tasks to catch thrown exceptions and unravel
Node.js domains.
The full implementation of ASAP is loadable as `require("asap")` in both Node.js
and browsers.
The raw layer that lacks exception handling overhead is loadable as
`require("asap/raw")`.
The interface is the same for both layers.
Tasks are no longer required to be functions, but can rather be any object that
implements `task.call()`.
With this feature you can recycle task objects to avoid garbage collector churn
and avoid closures in general.
The implementation has been rigorously documented so that our successors can
understand the scope of the problem that this module solves and all of its
nuances, ensuring that the next generation of implementations know what details
are essential.
- [asap.js](https://github.com/kriskowal/asap/blob/master/asap.js)
- [raw.js](https://github.com/kriskowal/asap/blob/master/raw.js)
- [browser-asap.js](https://github.com/kriskowal/asap/blob/master/browser-asap.js)
- [browser-raw.js](https://github.com/kriskowal/asap/blob/master/browser-raw.js)
The new version has also been rigorously tested across a broad spectrum of
browsers, in both the window and worker context.
The following charts capture the browser test results for the most recent
release.
The first chart shows test results for ASAP running in the main window context.
The second chart shows test results for ASAP running in a web worker context.
Test results are inconclusive (grey) on browsers that do not support web
workers.
These data are captured automatically by [Continuous
Integration][].
![Browser Compatibility](http://kriskowal-asap.s3-website-us-west-2.amazonaws.com/train/integration-2/saucelabs-results-matrix.svg)
![Compatibility in Web Workers](http://kriskowal-asap.s3-website-us-west-2.amazonaws.com/train/integration-2/saucelabs-worker-results-matrix.svg)
[Continuous Integration]: https://github.com/kriskowal/asap/blob/master/CONTRIBUTING.md

21
node_modules/asap/LICENSE.md generated vendored Normal file
View File

@ -0,0 +1,21 @@
Copyright 20092014 Contributors. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.

237
node_modules/asap/README.md generated vendored Normal file
View File

@ -0,0 +1,237 @@
# ASAP
[![Build Status](https://travis-ci.org/kriskowal/asap.png?branch=master)](https://travis-ci.org/kriskowal/asap)
Promise and asynchronous observer libraries, as well as hand-rolled callback
programs and libraries, often need a mechanism to postpone the execution of a
callback until the next available event.
(See [Designing APIs for Asynchrony][Zalgo].)
The `asap` function executes a task **as soon as possible** but not before it
returns, waiting only for the completion of the current event and previously
scheduled tasks.
```javascript
asap(function () {
// ...
});
```
[Zalgo]: http://blog.izs.me/post/59142742143/designing-apis-for-asynchrony
This CommonJS package provides an `asap` module that exports a function that
executes a task function *as soon as possible*.
ASAP strives to schedule events to occur before yielding for IO, reflow,
or redrawing.
Each event receives an independent stack, with only platform code in parent
frames and the events run in the order they are scheduled.
ASAP provides a fast event queue that will execute tasks until it is
empty before yielding to the JavaScript engine's underlying event-loop.
When a task gets added to a previously empty event queue, ASAP schedules a flush
event, preferring for that event to occur before the JavaScript engine has an
opportunity to perform IO tasks or rendering, thus making the first task and
subsequent tasks semantically indistinguishable.
ASAP uses a variety of techniques to preserve this invariant on different
versions of browsers and Node.js.
By design, ASAP prevents input events from being handled until the task
queue is empty.
If the process is busy enough, this may cause incoming connection requests to be
dropped, and may cause existing connections to inform the sender to reduce the
transmission rate or stall.
ASAP allows this on the theory that, if there is enough work to do, there is no
sense in looking for trouble.
As a consequence, ASAP can interfere with smooth animation.
If your task should be tied to the rendering loop, consider using
`requestAnimationFrame` instead.
A long sequence of tasks can also effect the long running script dialog.
If this is a problem, you may be able to use ASAPs cousin `setImmediate` to
break long processes into shorter intervals and periodically allow the browser
to breathe.
`setImmediate` will yield for IO, reflow, and repaint events.
It also returns a handler and can be canceled.
For a `setImmediate` shim, consider [YuzuJS setImmediate][setImmediate].
[setImmediate]: https://github.com/YuzuJS/setImmediate
Take care.
ASAP can sustain infinite recursive calls without warning.
It will not halt from a stack overflow, and it will not consume unbounded
memory.
This is behaviorally equivalent to an infinite loop.
Just as with infinite loops, you can monitor a Node.js process for this behavior
with a heart-beat signal.
As with infinite loops, a very small amount of caution goes a long way to
avoiding problems.
```javascript
function loop() {
asap(loop);
}
loop();
```
In browsers, if a task throws an exception, it will not interrupt the flushing
of high-priority tasks.
The exception will be postponed to a later, low-priority event to avoid
slow-downs.
In Node.js, if a task throws an exception, ASAP will resume flushing only if—and
only after—the error is handled by `domain.on("error")` or
`process.on("uncaughtException")`.
## Raw ASAP
Checking for exceptions comes at a cost.
The package also provides an `asap/raw` module that exports the underlying
implementation which is faster but stalls if a task throws an exception.
This internal version of the ASAP function does not check for errors.
If a task does throw an error, it will stall the event queue unless you manually
call `rawAsap.requestFlush()` before throwing the error, or any time after.
In Node.js, `asap/raw` also runs all tasks outside any domain.
If you need a task to be bound to your domain, you will have to do it manually.
```js
if (process.domain) {
task = process.domain.bind(task);
}
rawAsap(task);
```
## Tasks
A task may be any object that implements `call()`.
A function will suffice, but closures tend not to be reusable and can cause
garbage collector churn.
Both `asap` and `rawAsap` accept task objects to give you the option of
recycling task objects or using higher callable object abstractions.
See the `asap` source for an illustration.
## Compatibility
ASAP is tested on Node.js v0.10 and in a broad spectrum of web browsers.
The following charts capture the browser test results for the most recent
release.
The first chart shows test results for ASAP running in the main window context.
The second chart shows test results for ASAP running in a web worker context.
Test results are inconclusive (grey) on browsers that do not support web
workers.
These data are captured automatically by [Continuous
Integration][].
[Continuous Integration]: https://github.com/kriskowal/asap/blob/master/CONTRIBUTING.md
![Browser Compatibility](http://kriskowal-asap.s3-website-us-west-2.amazonaws.com/train/integration-2/saucelabs-results-matrix.svg)
![Compatibility in Web Workers](http://kriskowal-asap.s3-website-us-west-2.amazonaws.com/train/integration-2/saucelabs-worker-results-matrix.svg)
## Caveats
When a task is added to an empty event queue, it is not always possible to
guarantee that the task queue will begin flushing immediately after the current
event.
However, once the task queue begins flushing, it will not yield until the queue
is empty, even if the queue grows while executing tasks.
The following browsers allow the use of [DOM mutation observers][] to access
the HTML [microtask queue][], and thus begin flushing ASAP's task queue
immediately at the end of the current event loop turn, before any rendering or
IO:
[microtask queue]: http://www.whatwg.org/specs/web-apps/current-work/multipage/webappapis.html#microtask-queue
[DOM mutation observers]: http://dom.spec.whatwg.org/#mutation-observers
- Android 44.3
- Chrome 2634
- Firefox 1429
- Internet Explorer 11
- iPad Safari 67.1
- iPhone Safari 77.1
- Safari 67
In the absense of mutation observers, there are a few browsers, and situations
like web workers in some of the above browsers, where [message channels][]
would be a useful way to avoid falling back to timers.
Message channels give direct access to the HTML [task queue][], so the ASAP
task queue would flush after any already queued rendering and IO tasks, but
without having the minimum delay imposed by timers.
However, among these browsers, Internet Explorer 10 and Safari do not reliably
dispatch messages, so they are not worth the trouble to implement.
[message channels]: http://www.whatwg.org/specs/web-apps/current-work/multipage/web-messaging.html#message-channels
[task queue]: http://www.whatwg.org/specs/web-apps/current-work/multipage/webappapis.html#concept-task
- Internet Explorer 10
- Safair 5.0-1
- Opera 11-12
In the absense of mutation observers, these browsers and the following browsers
all fall back to using `setTimeout` and `setInterval` to ensure that a `flush`
occurs.
The implementation uses both and cancels whatever handler loses the race, since
`setTimeout` tends to occasionally skip tasks in unisolated circumstances.
Timers generally delay the flushing of ASAP's task queue for four milliseconds.
- Firefox 313
- Internet Explorer 610
- iPad Safari 4.3
- Lynx 2.8.7
## Heritage
ASAP has been factored out of the [Q][] asynchronous promise library.
It originally had a naïve implementation in terms of `setTimeout`, but
[Malte Ubl][NonBlocking] provided an insight that `postMessage` might be
useful for creating a high-priority, no-delay event dispatch hack.
Since then, Internet Explorer proposed and implemented `setImmediate`.
Robert Katić began contributing to Q by measuring the performance of
the internal implementation of `asap`, paying particular attention to
error recovery.
Domenic, Robert, and Kris Kowal collectively settled on the current strategy of
unrolling the high-priority event queue internally regardless of what strategy
we used to dispatch the potentially lower-priority flush event.
Domenic went on to make ASAP cooperate with Node.js domains.
[Q]: https://github.com/kriskowal/q
[NonBlocking]: http://www.nonblocking.io/2011/06/windownexttick.html
For further reading, Nicholas Zakas provided a thorough article on [The
Case for setImmediate][NCZ].
[NCZ]: http://www.nczonline.net/blog/2013/07/09/the-case-for-setimmediate/
Embers RSVP promise implementation later [adopted][RSVP ASAP] the name ASAP but
further developed the implentation.
Particularly, The `MessagePort` implementation was abandoned due to interaction
[problems with Mobile Internet Explorer][IE Problems] in favor of an
implementation backed on the newer and more reliable DOM `MutationObserver`
interface.
These changes were back-ported into this library.
[IE Problems]: https://github.com/cujojs/when/issues/197
[RSVP ASAP]: https://github.com/tildeio/rsvp.js/blob/cddf7232546a9cf858524b75cde6f9edf72620a7/lib/rsvp/asap.js
In addition, ASAP factored into `asap` and `asap/raw`, such that `asap` remained
exception-safe, but `asap/raw` provided a tight kernel that could be used for
tasks that guaranteed that they would not throw exceptions.
This core is useful for promise implementations that capture thrown errors in
rejected promises and do not need a second safety net.
At the same time, the exception handling in `asap` was factored into separate
implementations for Node.js and browsers, using the the [Browserify][Browser
Config] `browser` property in `package.json` to instruct browser module loaders
and bundlers, including [Browserify][], [Mr][], and [Mop][], to use the
browser-only implementation.
[Browser Config]: https://gist.github.com/defunctzombie/4339901
[Browserify]: https://github.com/substack/node-browserify
[Mr]: https://github.com/montagejs/mr
[Mop]: https://github.com/montagejs/mop
## License
Copyright 2009-2014 by Contributors
MIT License (enclosed)

65
node_modules/asap/asap.js generated vendored Normal file
View File

@ -0,0 +1,65 @@
"use strict";
var rawAsap = require("./raw");
var freeTasks = [];
/**
* Calls a task as soon as possible after returning, in its own event, with
* priority over IO events. An exception thrown in a task can be handled by
* `process.on("uncaughtException") or `domain.on("error")`, but will otherwise
* crash the process. If the error is handled, all subsequent tasks will
* resume.
*
* @param {{call}} task A callable object, typically a function that takes no
* arguments.
*/
module.exports = asap;
function asap(task) {
var rawTask;
if (freeTasks.length) {
rawTask = freeTasks.pop();
} else {
rawTask = new RawTask();
}
rawTask.task = task;
rawTask.domain = process.domain;
rawAsap(rawTask);
}
function RawTask() {
this.task = null;
this.domain = null;
}
RawTask.prototype.call = function () {
if (this.domain) {
this.domain.enter();
}
var threw = true;
try {
this.task.call();
threw = false;
// If the task throws an exception (presumably) Node.js restores the
// domain stack for the next event.
if (this.domain) {
this.domain.exit();
}
} finally {
// We use try/finally and a threw flag to avoid messing up stack traces
// when we catch and release errors.
if (threw) {
// In Node.js, uncaught exceptions are considered fatal errors.
// Re-throw them to interrupt flushing!
// Ensure that flushing continues if an uncaught exception is
// suppressed listening process.on("uncaughtException") or
// domain.on("error").
rawAsap.requestFlush();
}
// If the task threw an error, we do not want to exit the domain here.
// Exiting the domain would prevent the domain from catching the error.
this.task = null;
this.domain = null;
freeTasks.push(this);
}
};

66
node_modules/asap/browser-asap.js generated vendored Normal file
View File

@ -0,0 +1,66 @@
"use strict";
// rawAsap provides everything we need except exception management.
var rawAsap = require("./raw");
// RawTasks are recycled to reduce GC churn.
var freeTasks = [];
// We queue errors to ensure they are thrown in right order (FIFO).
// Array-as-queue is good enough here, since we are just dealing with exceptions.
var pendingErrors = [];
var requestErrorThrow = rawAsap.makeRequestCallFromTimer(throwFirstError);
function throwFirstError() {
if (pendingErrors.length) {
throw pendingErrors.shift();
}
}
/**
* Calls a task as soon as possible after returning, in its own event, with priority
* over other events like animation, reflow, and repaint. An error thrown from an
* event will not interrupt, nor even substantially slow down the processing of
* other events, but will be rather postponed to a lower priority event.
* @param {{call}} task A callable object, typically a function that takes no
* arguments.
*/
module.exports = asap;
function asap(task) {
var rawTask;
if (freeTasks.length) {
rawTask = freeTasks.pop();
} else {
rawTask = new RawTask();
}
rawTask.task = task;
rawAsap(rawTask);
}
// We wrap tasks with recyclable task objects. A task object implements
// `call`, just like a function.
function RawTask() {
this.task = null;
}
// The sole purpose of wrapping the task is to catch the exception and recycle
// the task object after its single use.
RawTask.prototype.call = function () {
try {
this.task.call();
} catch (error) {
if (asap.onerror) {
// This hook exists purely for testing purposes.
// Its name will be periodically randomized to break any code that
// depends on its existence.
asap.onerror(error);
} else {
// In a web browser, exceptions are not fatal. However, to avoid
// slowing down the queue of pending tasks, we rethrow the error in a
// lower priority turn.
pendingErrors.push(error);
requestErrorThrow();
}
} finally {
this.task = null;
freeTasks[freeTasks.length] = this;
}
};

223
node_modules/asap/browser-raw.js generated vendored Normal file
View File

@ -0,0 +1,223 @@
"use strict";
// Use the fastest means possible to execute a task in its own turn, with
// priority over other events including IO, animation, reflow, and redraw
// events in browsers.
//
// An exception thrown by a task will permanently interrupt the processing of
// subsequent tasks. The higher level `asap` function ensures that if an
// exception is thrown by a task, that the task queue will continue flushing as
// soon as possible, but if you use `rawAsap` directly, you are responsible to
// either ensure that no exceptions are thrown from your task, or to manually
// call `rawAsap.requestFlush` if an exception is thrown.
module.exports = rawAsap;
function rawAsap(task) {
if (!queue.length) {
requestFlush();
flushing = true;
}
// Equivalent to push, but avoids a function call.
queue[queue.length] = task;
}
var queue = [];
// Once a flush has been requested, no further calls to `requestFlush` are
// necessary until the next `flush` completes.
var flushing = false;
// `requestFlush` is an implementation-specific method that attempts to kick
// off a `flush` event as quickly as possible. `flush` will attempt to exhaust
// the event queue before yielding to the browser's own event loop.
var requestFlush;
// The position of the next task to execute in the task queue. This is
// preserved between calls to `flush` so that it can be resumed if
// a task throws an exception.
var index = 0;
// If a task schedules additional tasks recursively, the task queue can grow
// unbounded. To prevent memory exhaustion, the task queue will periodically
// truncate already-completed tasks.
var capacity = 1024;
// The flush function processes all tasks that have been scheduled with
// `rawAsap` unless and until one of those tasks throws an exception.
// If a task throws an exception, `flush` ensures that its state will remain
// consistent and will resume where it left off when called again.
// However, `flush` does not make any arrangements to be called again if an
// exception is thrown.
function flush() {
while (index < queue.length) {
var currentIndex = index;
// Advance the index before calling the task. This ensures that we will
// begin flushing on the next task the task throws an error.
index = index + 1;
queue[currentIndex].call();
// Prevent leaking memory for long chains of recursive calls to `asap`.
// If we call `asap` within tasks scheduled by `asap`, the queue will
// grow, but to avoid an O(n) walk for every task we execute, we don't
// shift tasks off the queue after they have been executed.
// Instead, we periodically shift 1024 tasks off the queue.
if (index > capacity) {
// Manually shift all values starting at the index back to the
// beginning of the queue.
for (var scan = 0, newLength = queue.length - index; scan < newLength; scan++) {
queue[scan] = queue[scan + index];
}
queue.length -= index;
index = 0;
}
}
queue.length = 0;
index = 0;
flushing = false;
}
// `requestFlush` is implemented using a strategy based on data collected from
// every available SauceLabs Selenium web driver worker at time of writing.
// https://docs.google.com/spreadsheets/d/1mG-5UYGup5qxGdEMWkhP6BWCz053NUb2E1QoUTU16uA/edit#gid=783724593
// Safari 6 and 6.1 for desktop, iPad, and iPhone are the only browsers that
// have WebKitMutationObserver but not un-prefixed MutationObserver.
// Must use `global` or `self` instead of `window` to work in both frames and web
// workers. `global` is a provision of Browserify, Mr, Mrs, or Mop.
/* globals self */
var scope = typeof global !== "undefined" ? global : self;
var BrowserMutationObserver = scope.MutationObserver || scope.WebKitMutationObserver;
// MutationObservers are desirable because they have high priority and work
// reliably everywhere they are implemented.
// They are implemented in all modern browsers.
//
// - Android 4-4.3
// - Chrome 26-34
// - Firefox 14-29
// - Internet Explorer 11
// - iPad Safari 6-7.1
// - iPhone Safari 7-7.1
// - Safari 6-7
if (typeof BrowserMutationObserver === "function") {
requestFlush = makeRequestCallFromMutationObserver(flush);
// MessageChannels are desirable because they give direct access to the HTML
// task queue, are implemented in Internet Explorer 10, Safari 5.0-1, and Opera
// 11-12, and in web workers in many engines.
// Although message channels yield to any queued rendering and IO tasks, they
// would be better than imposing the 4ms delay of timers.
// However, they do not work reliably in Internet Explorer or Safari.
// Internet Explorer 10 is the only browser that has setImmediate but does
// not have MutationObservers.
// Although setImmediate yields to the browser's renderer, it would be
// preferrable to falling back to setTimeout since it does not have
// the minimum 4ms penalty.
// Unfortunately there appears to be a bug in Internet Explorer 10 Mobile (and
// Desktop to a lesser extent) that renders both setImmediate and
// MessageChannel useless for the purposes of ASAP.
// https://github.com/kriskowal/q/issues/396
// Timers are implemented universally.
// We fall back to timers in workers in most engines, and in foreground
// contexts in the following browsers.
// However, note that even this simple case requires nuances to operate in a
// broad spectrum of browsers.
//
// - Firefox 3-13
// - Internet Explorer 6-9
// - iPad Safari 4.3
// - Lynx 2.8.7
} else {
requestFlush = makeRequestCallFromTimer(flush);
}
// `requestFlush` requests that the high priority event queue be flushed as
// soon as possible.
// This is useful to prevent an error thrown in a task from stalling the event
// queue if the exception handled by Node.jss
// `process.on("uncaughtException")` or by a domain.
rawAsap.requestFlush = requestFlush;
// To request a high priority event, we induce a mutation observer by toggling
// the text of a text node between "1" and "-1".
function makeRequestCallFromMutationObserver(callback) {
var toggle = 1;
var observer = new BrowserMutationObserver(callback);
var node = document.createTextNode("");
observer.observe(node, {characterData: true});
return function requestCall() {
toggle = -toggle;
node.data = toggle;
};
}
// The message channel technique was discovered by Malte Ubl and was the
// original foundation for this library.
// http://www.nonblocking.io/2011/06/windownexttick.html
// Safari 6.0.5 (at least) intermittently fails to create message ports on a
// page's first load. Thankfully, this version of Safari supports
// MutationObservers, so we don't need to fall back in that case.
// function makeRequestCallFromMessageChannel(callback) {
// var channel = new MessageChannel();
// channel.port1.onmessage = callback;
// return function requestCall() {
// channel.port2.postMessage(0);
// };
// }
// For reasons explained above, we are also unable to use `setImmediate`
// under any circumstances.
// Even if we were, there is another bug in Internet Explorer 10.
// It is not sufficient to assign `setImmediate` to `requestFlush` because
// `setImmediate` must be called *by name* and therefore must be wrapped in a
// closure.
// Never forget.
// function makeRequestCallFromSetImmediate(callback) {
// return function requestCall() {
// setImmediate(callback);
// };
// }
// Safari 6.0 has a problem where timers will get lost while the user is
// scrolling. This problem does not impact ASAP because Safari 6.0 supports
// mutation observers, so that implementation is used instead.
// However, if we ever elect to use timers in Safari, the prevalent work-around
// is to add a scroll event listener that calls for a flush.
// `setTimeout` does not call the passed callback if the delay is less than
// approximately 7 in web workers in Firefox 8 through 18, and sometimes not
// even then.
function makeRequestCallFromTimer(callback) {
return function requestCall() {
// We dispatch a timeout with a specified delay of 0 for engines that
// can reliably accommodate that request. This will usually be snapped
// to a 4 milisecond delay, but once we're flushing, there's no delay
// between events.
var timeoutHandle = setTimeout(handleTimer, 0);
// However, since this timer gets frequently dropped in Firefox
// workers, we enlist an interval handle that will try to fire
// an event 20 times per second until it succeeds.
var intervalHandle = setInterval(handleTimer, 50);
function handleTimer() {
// Whichever timer succeeds will cancel both timers and
// execute the callback.
clearTimeout(timeoutHandle);
clearInterval(intervalHandle);
callback();
}
};
}
// This is for `asap.js` only.
// Its name will be periodically randomized to break any code that depends on
// its existence.
rawAsap.makeRequestCallFromTimer = makeRequestCallFromTimer;
// ASAP was originally a nextTick shim included in Q. This was factored out
// into this ASAP package. It was later adapted to RSVP which made further
// amendments. These decisions, particularly to marginalize MessageChannel and
// to capture the MutationObserver implementation in a closure, were integrated
// back into ASAP proper.
// https://github.com/tildeio/rsvp.js/blob/cddf7232546a9cf858524b75cde6f9edf72620a7/lib/rsvp/asap.js

58
node_modules/asap/package.json generated vendored Normal file
View File

@ -0,0 +1,58 @@
{
"name": "asap",
"version": "2.0.6",
"description": "High-priority task queue for Node.js and browsers",
"keywords": [
"event",
"task",
"queue"
],
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/kriskowal/asap.git"
},
"main": "./asap.js",
"browser": {
"./asap": "./browser-asap.js",
"./asap.js": "./browser-asap.js",
"./raw": "./browser-raw.js",
"./raw.js": "./browser-raw.js",
"./test/domain.js": "./test/browser-domain.js"
},
"react-native": {
"domain": false
},
"files": [
"raw.js",
"asap.js",
"browser-raw.js",
"browser-asap.js"
],
"scripts": {
"test": "npm run lint && npm run test-node",
"test-travis": "npm run lint && npm run test-node && npm run test-saucelabs && npm run test-saucelabs-worker",
"test-node": "node test/asap-test.js",
"test-publish": "node scripts/publish-bundle.js test/asap-test.js | pbcopy",
"test-browser": "node scripts/publish-bundle.js test/asap-test.js | xargs opener",
"test-saucelabs": "node scripts/saucelabs.js test/asap-test.js scripts/saucelabs-spot-configurations.json",
"test-saucelabs-all": "node scripts/saucelabs.js test/asap-test.js scripts/saucelabs-all-configurations.json",
"test-saucelabs-worker": "node scripts/saucelabs-worker-test.js scripts/saucelabs-spot-configurations.json",
"test-saucelabs-worker-all": "node scripts/saucelabs-worker-test.js scripts/saucelabs-all-configurations.json",
"lint": "jshint raw.js asap.js browser-raw.js browser-asap.js $(find scripts -name '*.js' | grep -v gauntlet)",
"benchmarks": "node benchmarks"
},
"devDependencies": {
"events": "^1.0.1",
"jshint": "^2.5.1",
"knox": "^0.8.10",
"mr": "^2.0.5",
"opener": "^1.3.0",
"q": "^2.0.3",
"q-io": "^2.0.3",
"saucelabs": "^0.1.1",
"wd": "^0.2.21",
"weak-map": "^1.0.5",
"benchmark": "^1.0.0"
}
}

101
node_modules/asap/raw.js generated vendored Normal file
View File

@ -0,0 +1,101 @@
"use strict";
var domain; // The domain module is executed on demand
var hasSetImmediate = typeof setImmediate === "function";
// Use the fastest means possible to execute a task in its own turn, with
// priority over other events including network IO events in Node.js.
//
// An exception thrown by a task will permanently interrupt the processing of
// subsequent tasks. The higher level `asap` function ensures that if an
// exception is thrown by a task, that the task queue will continue flushing as
// soon as possible, but if you use `rawAsap` directly, you are responsible to
// either ensure that no exceptions are thrown from your task, or to manually
// call `rawAsap.requestFlush` if an exception is thrown.
module.exports = rawAsap;
function rawAsap(task) {
if (!queue.length) {
requestFlush();
flushing = true;
}
// Avoids a function call
queue[queue.length] = task;
}
var queue = [];
// Once a flush has been requested, no further calls to `requestFlush` are
// necessary until the next `flush` completes.
var flushing = false;
// The position of the next task to execute in the task queue. This is
// preserved between calls to `flush` so that it can be resumed if
// a task throws an exception.
var index = 0;
// If a task schedules additional tasks recursively, the task queue can grow
// unbounded. To prevent memory excaustion, the task queue will periodically
// truncate already-completed tasks.
var capacity = 1024;
// The flush function processes all tasks that have been scheduled with
// `rawAsap` unless and until one of those tasks throws an exception.
// If a task throws an exception, `flush` ensures that its state will remain
// consistent and will resume where it left off when called again.
// However, `flush` does not make any arrangements to be called again if an
// exception is thrown.
function flush() {
while (index < queue.length) {
var currentIndex = index;
// Advance the index before calling the task. This ensures that we will
// begin flushing on the next task the task throws an error.
index = index + 1;
queue[currentIndex].call();
// Prevent leaking memory for long chains of recursive calls to `asap`.
// If we call `asap` within tasks scheduled by `asap`, the queue will
// grow, but to avoid an O(n) walk for every task we execute, we don't
// shift tasks off the queue after they have been executed.
// Instead, we periodically shift 1024 tasks off the queue.
if (index > capacity) {
// Manually shift all values starting at the index back to the
// beginning of the queue.
for (var scan = 0, newLength = queue.length - index; scan < newLength; scan++) {
queue[scan] = queue[scan + index];
}
queue.length -= index;
index = 0;
}
}
queue.length = 0;
index = 0;
flushing = false;
}
rawAsap.requestFlush = requestFlush;
function requestFlush() {
// Ensure flushing is not bound to any domain.
// It is not sufficient to exit the domain, because domains exist on a stack.
// To execute code outside of any domain, the following dance is necessary.
var parentDomain = process.domain;
if (parentDomain) {
if (!domain) {
// Lazy execute the domain module.
// Only employed if the user elects to use domains.
domain = require("domain");
}
domain.active = process.domain = null;
}
// `setImmediate` is slower that `process.nextTick`, but `process.nextTick`
// cannot handle recursion.
// `requestFlush` will only be called recursively from `asap.js`, to resume
// flushing after an error is thrown into a domain.
// Conveniently, `setImmediate` was introduced in the same version
// `process.nextTick` started throwing recursion errors.
if (flushing && hasSetImmediate) {
setImmediate(flush);
} else {
process.nextTick(flush);
}
if (parentDomain) {
domain.active = process.domain = parentDomain;
}
}

60
node_modules/content-disposition/HISTORY.md generated vendored Normal file
View File

@ -0,0 +1,60 @@
0.5.4 / 2021-12-10
==================
* deps: safe-buffer@5.2.1
0.5.3 / 2018-12-17
==================
* Use `safe-buffer` for improved Buffer API
0.5.2 / 2016-12-08
==================
* Fix `parse` to accept any linear whitespace character
0.5.1 / 2016-01-17
==================
* perf: enable strict mode
0.5.0 / 2014-10-11
==================
* Add `parse` function
0.4.0 / 2014-09-21
==================
* Expand non-Unicode `filename` to the full ISO-8859-1 charset
0.3.0 / 2014-09-20
==================
* Add `fallback` option
* Add `type` option
0.2.0 / 2014-09-19
==================
* Reduce ambiguity of file names with hex escape in buggy browsers
0.1.2 / 2014-09-19
==================
* Fix periodic invalid Unicode filename header
0.1.1 / 2014-09-19
==================
* Fix invalid characters appearing in `filename*` parameter
0.1.0 / 2014-09-18
==================
* Make the `filename` argument optional
0.0.0 / 2014-09-18
==================
* Initial release

22
node_modules/content-disposition/LICENSE generated vendored Normal file
View File

@ -0,0 +1,22 @@
(The MIT License)
Copyright (c) 2014-2017 Douglas Christopher Wilson
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

142
node_modules/content-disposition/README.md generated vendored Normal file
View File

@ -0,0 +1,142 @@
# content-disposition
[![NPM Version][npm-image]][npm-url]
[![NPM Downloads][downloads-image]][downloads-url]
[![Node.js Version][node-version-image]][node-version-url]
[![Build Status][github-actions-ci-image]][github-actions-ci-url]
[![Test Coverage][coveralls-image]][coveralls-url]
Create and parse HTTP `Content-Disposition` header
## Installation
```sh
$ npm install content-disposition
```
## API
```js
var contentDisposition = require('content-disposition')
```
### contentDisposition(filename, options)
Create an attachment `Content-Disposition` header value using the given file name,
if supplied. The `filename` is optional and if no file name is desired, but you
want to specify `options`, set `filename` to `undefined`.
```js
res.setHeader('Content-Disposition', contentDisposition('∫ maths.pdf'))
```
**note** HTTP headers are of the ISO-8859-1 character set. If you are writing this
header through a means different from `setHeader` in Node.js, you'll want to specify
the `'binary'` encoding in Node.js.
#### Options
`contentDisposition` accepts these properties in the options object.
##### fallback
If the `filename` option is outside ISO-8859-1, then the file name is actually
stored in a supplemental field for clients that support Unicode file names and
a ISO-8859-1 version of the file name is automatically generated.
This specifies the ISO-8859-1 file name to override the automatic generation or
disables the generation all together, defaults to `true`.
- A string will specify the ISO-8859-1 file name to use in place of automatic
generation.
- `false` will disable including a ISO-8859-1 file name and only include the
Unicode version (unless the file name is already ISO-8859-1).
- `true` will enable automatic generation if the file name is outside ISO-8859-1.
If the `filename` option is ISO-8859-1 and this option is specified and has a
different value, then the `filename` option is encoded in the extended field
and this set as the fallback field, even though they are both ISO-8859-1.
##### type
Specifies the disposition type, defaults to `"attachment"`. This can also be
`"inline"`, or any other value (all values except inline are treated like
`attachment`, but can convey additional information if both parties agree to
it). The type is normalized to lower-case.
### contentDisposition.parse(string)
```js
var disposition = contentDisposition.parse('attachment; filename="EURO rates.txt"; filename*=UTF-8\'\'%e2%82%ac%20rates.txt')
```
Parse a `Content-Disposition` header string. This automatically handles extended
("Unicode") parameters by decoding them and providing them under the standard
parameter name. This will return an object with the following properties (examples
are shown for the string `'attachment; filename="EURO rates.txt"; filename*=UTF-8\'\'%e2%82%ac%20rates.txt'`):
- `type`: The disposition type (always lower case). Example: `'attachment'`
- `parameters`: An object of the parameters in the disposition (name of parameter
always lower case and extended versions replace non-extended versions). Example:
`{filename: "€ rates.txt"}`
## Examples
### Send a file for download
```js
var contentDisposition = require('content-disposition')
var destroy = require('destroy')
var fs = require('fs')
var http = require('http')
var onFinished = require('on-finished')
var filePath = '/path/to/public/plans.pdf'
http.createServer(function onRequest (req, res) {
// set headers
res.setHeader('Content-Type', 'application/pdf')
res.setHeader('Content-Disposition', contentDisposition(filePath))
// send file
var stream = fs.createReadStream(filePath)
stream.pipe(res)
onFinished(res, function () {
destroy(stream)
})
})
```
## Testing
```sh
$ npm test
```
## References
- [RFC 2616: Hypertext Transfer Protocol -- HTTP/1.1][rfc-2616]
- [RFC 5987: Character Set and Language Encoding for Hypertext Transfer Protocol (HTTP) Header Field Parameters][rfc-5987]
- [RFC 6266: Use of the Content-Disposition Header Field in the Hypertext Transfer Protocol (HTTP)][rfc-6266]
- [Test Cases for HTTP Content-Disposition header field (RFC 6266) and the Encodings defined in RFCs 2047, 2231 and 5987][tc-2231]
[rfc-2616]: https://tools.ietf.org/html/rfc2616
[rfc-5987]: https://tools.ietf.org/html/rfc5987
[rfc-6266]: https://tools.ietf.org/html/rfc6266
[tc-2231]: http://greenbytes.de/tech/tc2231/
## License
[MIT](LICENSE)
[npm-image]: https://img.shields.io/npm/v/content-disposition.svg
[npm-url]: https://npmjs.org/package/content-disposition
[node-version-image]: https://img.shields.io/node/v/content-disposition.svg
[node-version-url]: https://nodejs.org/en/download
[coveralls-image]: https://img.shields.io/coveralls/jshttp/content-disposition.svg
[coveralls-url]: https://coveralls.io/r/jshttp/content-disposition?branch=master
[downloads-image]: https://img.shields.io/npm/dm/content-disposition.svg
[downloads-url]: https://npmjs.org/package/content-disposition
[github-actions-ci-image]: https://img.shields.io/github/workflow/status/jshttp/content-disposition/ci/master?label=ci
[github-actions-ci-url]: https://github.com/jshttp/content-disposition?query=workflow%3Aci

458
node_modules/content-disposition/index.js generated vendored Normal file
View File

@ -0,0 +1,458 @@
/*!
* content-disposition
* Copyright(c) 2014-2017 Douglas Christopher Wilson
* MIT Licensed
*/
'use strict'
/**
* Module exports.
* @public
*/
module.exports = contentDisposition
module.exports.parse = parse
/**
* Module dependencies.
* @private
*/
var basename = require('path').basename
var Buffer = require('safe-buffer').Buffer
/**
* RegExp to match non attr-char, *after* encodeURIComponent (i.e. not including "%")
* @private
*/
var ENCODE_URL_ATTR_CHAR_REGEXP = /[\x00-\x20"'()*,/:;<=>?@[\\\]{}\x7f]/g // eslint-disable-line no-control-regex
/**
* RegExp to match percent encoding escape.
* @private
*/
var HEX_ESCAPE_REGEXP = /%[0-9A-Fa-f]{2}/
var HEX_ESCAPE_REPLACE_REGEXP = /%([0-9A-Fa-f]{2})/g
/**
* RegExp to match non-latin1 characters.
* @private
*/
var NON_LATIN1_REGEXP = /[^\x20-\x7e\xa0-\xff]/g
/**
* RegExp to match quoted-pair in RFC 2616
*
* quoted-pair = "\" CHAR
* CHAR = <any US-ASCII character (octets 0 - 127)>
* @private
*/
var QESC_REGEXP = /\\([\u0000-\u007f])/g // eslint-disable-line no-control-regex
/**
* RegExp to match chars that must be quoted-pair in RFC 2616
* @private
*/
var QUOTE_REGEXP = /([\\"])/g
/**
* RegExp for various RFC 2616 grammar
*
* parameter = token "=" ( token | quoted-string )
* token = 1*<any CHAR except CTLs or separators>
* separators = "(" | ")" | "<" | ">" | "@"
* | "," | ";" | ":" | "\" | <">
* | "/" | "[" | "]" | "?" | "="
* | "{" | "}" | SP | HT
* quoted-string = ( <"> *(qdtext | quoted-pair ) <"> )
* qdtext = <any TEXT except <">>
* quoted-pair = "\" CHAR
* CHAR = <any US-ASCII character (octets 0 - 127)>
* TEXT = <any OCTET except CTLs, but including LWS>
* LWS = [CRLF] 1*( SP | HT )
* CRLF = CR LF
* CR = <US-ASCII CR, carriage return (13)>
* LF = <US-ASCII LF, linefeed (10)>
* SP = <US-ASCII SP, space (32)>
* HT = <US-ASCII HT, horizontal-tab (9)>
* CTL = <any US-ASCII control character (octets 0 - 31) and DEL (127)>
* OCTET = <any 8-bit sequence of data>
* @private
*/
var PARAM_REGEXP = /;[\x09\x20]*([!#$%&'*+.0-9A-Z^_`a-z|~-]+)[\x09\x20]*=[\x09\x20]*("(?:[\x20!\x23-\x5b\x5d-\x7e\x80-\xff]|\\[\x20-\x7e])*"|[!#$%&'*+.0-9A-Z^_`a-z|~-]+)[\x09\x20]*/g // eslint-disable-line no-control-regex
var TEXT_REGEXP = /^[\x20-\x7e\x80-\xff]+$/
var TOKEN_REGEXP = /^[!#$%&'*+.0-9A-Z^_`a-z|~-]+$/
/**
* RegExp for various RFC 5987 grammar
*
* ext-value = charset "'" [ language ] "'" value-chars
* charset = "UTF-8" / "ISO-8859-1" / mime-charset
* mime-charset = 1*mime-charsetc
* mime-charsetc = ALPHA / DIGIT
* / "!" / "#" / "$" / "%" / "&"
* / "+" / "-" / "^" / "_" / "`"
* / "{" / "}" / "~"
* language = ( 2*3ALPHA [ extlang ] )
* / 4ALPHA
* / 5*8ALPHA
* extlang = *3( "-" 3ALPHA )
* value-chars = *( pct-encoded / attr-char )
* pct-encoded = "%" HEXDIG HEXDIG
* attr-char = ALPHA / DIGIT
* / "!" / "#" / "$" / "&" / "+" / "-" / "."
* / "^" / "_" / "`" / "|" / "~"
* @private
*/
var EXT_VALUE_REGEXP = /^([A-Za-z0-9!#$%&+\-^_`{}~]+)'(?:[A-Za-z]{2,3}(?:-[A-Za-z]{3}){0,3}|[A-Za-z]{4,8}|)'((?:%[0-9A-Fa-f]{2}|[A-Za-z0-9!#$&+.^_`|~-])+)$/
/**
* RegExp for various RFC 6266 grammar
*
* disposition-type = "inline" | "attachment" | disp-ext-type
* disp-ext-type = token
* disposition-parm = filename-parm | disp-ext-parm
* filename-parm = "filename" "=" value
* | "filename*" "=" ext-value
* disp-ext-parm = token "=" value
* | ext-token "=" ext-value
* ext-token = <the characters in token, followed by "*">
* @private
*/
var DISPOSITION_TYPE_REGEXP = /^([!#$%&'*+.0-9A-Z^_`a-z|~-]+)[\x09\x20]*(?:$|;)/ // eslint-disable-line no-control-regex
/**
* Create an attachment Content-Disposition header.
*
* @param {string} [filename]
* @param {object} [options]
* @param {string} [options.type=attachment]
* @param {string|boolean} [options.fallback=true]
* @return {string}
* @public
*/
function contentDisposition (filename, options) {
var opts = options || {}
// get type
var type = opts.type || 'attachment'
// get parameters
var params = createparams(filename, opts.fallback)
// format into string
return format(new ContentDisposition(type, params))
}
/**
* Create parameters object from filename and fallback.
*
* @param {string} [filename]
* @param {string|boolean} [fallback=true]
* @return {object}
* @private
*/
function createparams (filename, fallback) {
if (filename === undefined) {
return
}
var params = {}
if (typeof filename !== 'string') {
throw new TypeError('filename must be a string')
}
// fallback defaults to true
if (fallback === undefined) {
fallback = true
}
if (typeof fallback !== 'string' && typeof fallback !== 'boolean') {
throw new TypeError('fallback must be a string or boolean')
}
if (typeof fallback === 'string' && NON_LATIN1_REGEXP.test(fallback)) {
throw new TypeError('fallback must be ISO-8859-1 string')
}
// restrict to file base name
var name = basename(filename)
// determine if name is suitable for quoted string
var isQuotedString = TEXT_REGEXP.test(name)
// generate fallback name
var fallbackName = typeof fallback !== 'string'
? fallback && getlatin1(name)
: basename(fallback)
var hasFallback = typeof fallbackName === 'string' && fallbackName !== name
// set extended filename parameter
if (hasFallback || !isQuotedString || HEX_ESCAPE_REGEXP.test(name)) {
params['filename*'] = name
}
// set filename parameter
if (isQuotedString || hasFallback) {
params.filename = hasFallback
? fallbackName
: name
}
return params
}
/**
* Format object to Content-Disposition header.
*
* @param {object} obj
* @param {string} obj.type
* @param {object} [obj.parameters]
* @return {string}
* @private
*/
function format (obj) {
var parameters = obj.parameters
var type = obj.type
if (!type || typeof type !== 'string' || !TOKEN_REGEXP.test(type)) {
throw new TypeError('invalid type')
}
// start with normalized type
var string = String(type).toLowerCase()
// append parameters
if (parameters && typeof parameters === 'object') {
var param
var params = Object.keys(parameters).sort()
for (var i = 0; i < params.length; i++) {
param = params[i]
var val = param.substr(-1) === '*'
? ustring(parameters[param])
: qstring(parameters[param])
string += '; ' + param + '=' + val
}
}
return string
}
/**
* Decode a RFC 5987 field value (gracefully).
*
* @param {string} str
* @return {string}
* @private
*/
function decodefield (str) {
var match = EXT_VALUE_REGEXP.exec(str)
if (!match) {
throw new TypeError('invalid extended field value')
}
var charset = match[1].toLowerCase()
var encoded = match[2]
var value
// to binary string
var binary = encoded.replace(HEX_ESCAPE_REPLACE_REGEXP, pdecode)
switch (charset) {
case 'iso-8859-1':
value = getlatin1(binary)
break
case 'utf-8':
value = Buffer.from(binary, 'binary').toString('utf8')
break
default:
throw new TypeError('unsupported charset in extended field')
}
return value
}
/**
* Get ISO-8859-1 version of string.
*
* @param {string} val
* @return {string}
* @private
*/
function getlatin1 (val) {
// simple Unicode -> ISO-8859-1 transformation
return String(val).replace(NON_LATIN1_REGEXP, '?')
}
/**
* Parse Content-Disposition header string.
*
* @param {string} string
* @return {object}
* @public
*/
function parse (string) {
if (!string || typeof string !== 'string') {
throw new TypeError('argument string is required')
}
var match = DISPOSITION_TYPE_REGEXP.exec(string)
if (!match) {
throw new TypeError('invalid type format')
}
// normalize type
var index = match[0].length
var type = match[1].toLowerCase()
var key
var names = []
var params = {}
var value
// calculate index to start at
index = PARAM_REGEXP.lastIndex = match[0].substr(-1) === ';'
? index - 1
: index
// match parameters
while ((match = PARAM_REGEXP.exec(string))) {
if (match.index !== index) {
throw new TypeError('invalid parameter format')
}
index += match[0].length
key = match[1].toLowerCase()
value = match[2]
if (names.indexOf(key) !== -1) {
throw new TypeError('invalid duplicate parameter')
}
names.push(key)
if (key.indexOf('*') + 1 === key.length) {
// decode extended value
key = key.slice(0, -1)
value = decodefield(value)
// overwrite existing value
params[key] = value
continue
}
if (typeof params[key] === 'string') {
continue
}
if (value[0] === '"') {
// remove quotes and escapes
value = value
.substr(1, value.length - 2)
.replace(QESC_REGEXP, '$1')
}
params[key] = value
}
if (index !== -1 && index !== string.length) {
throw new TypeError('invalid parameter format')
}
return new ContentDisposition(type, params)
}
/**
* Percent decode a single character.
*
* @param {string} str
* @param {string} hex
* @return {string}
* @private
*/
function pdecode (str, hex) {
return String.fromCharCode(parseInt(hex, 16))
}
/**
* Percent encode a single character.
*
* @param {string} char
* @return {string}
* @private
*/
function pencode (char) {
return '%' + String(char)
.charCodeAt(0)
.toString(16)
.toUpperCase()
}
/**
* Quote a string for HTTP.
*
* @param {string} val
* @return {string}
* @private
*/
function qstring (val) {
var str = String(val)
return '"' + str.replace(QUOTE_REGEXP, '\\$1') + '"'
}
/**
* Encode a Unicode string for HTTP (RFC 5987).
*
* @param {string} val
* @return {string}
* @private
*/
function ustring (val) {
var str = String(val)
// percent encode as UTF-8
var encoded = encodeURIComponent(str)
.replace(ENCODE_URL_ATTR_CHAR_REGEXP, pencode)
return 'UTF-8\'\'' + encoded
}
/**
* Class for parsed Content-Disposition header for v8 optimization
*
* @public
* @param {string} type
* @param {object} parameters
* @constructor
*/
function ContentDisposition (type, parameters) {
this.type = type
this.parameters = parameters
}

44
node_modules/content-disposition/package.json generated vendored Normal file
View File

@ -0,0 +1,44 @@
{
"name": "content-disposition",
"description": "Create and parse Content-Disposition header",
"version": "0.5.4",
"author": "Douglas Christopher Wilson <doug@somethingdoug.com>",
"license": "MIT",
"keywords": [
"content-disposition",
"http",
"rfc6266",
"res"
],
"repository": "jshttp/content-disposition",
"dependencies": {
"safe-buffer": "5.2.1"
},
"devDependencies": {
"deep-equal": "1.0.1",
"eslint": "7.32.0",
"eslint-config-standard": "13.0.1",
"eslint-plugin-import": "2.25.3",
"eslint-plugin-markdown": "2.2.1",
"eslint-plugin-node": "11.1.0",
"eslint-plugin-promise": "5.2.0",
"eslint-plugin-standard": "4.1.0",
"istanbul": "0.4.5",
"mocha": "9.1.3"
},
"files": [
"LICENSE",
"HISTORY.md",
"README.md",
"index.js"
],
"engines": {
"node": ">= 0.6"
},
"scripts": {
"lint": "eslint .",
"test": "mocha --reporter spec --bail --check-leaks test/",
"test-ci": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/",
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/"
}
}

22
node_modules/destroy/LICENSE generated vendored Normal file
View File

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2014 Jonathan Ong me@jongleberry.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

61
node_modules/destroy/README.md generated vendored Normal file
View File

@ -0,0 +1,61 @@
# Destroy
[![NPM version][npm-image]][npm-url]
[![Build Status][github-actions-ci-image]][github-actions-ci-url]
[![Test coverage][coveralls-image]][coveralls-url]
[![License][license-image]][license-url]
[![Downloads][downloads-image]][downloads-url]
Destroy a stream.
This module is meant to ensure a stream gets destroyed, handling different APIs
and Node.js bugs.
## API
```js
var destroy = require('destroy')
```
### destroy(stream)
Destroy the given stream. In most cases, this is identical to a simple
`stream.destroy()` call. The rules are as follows for a given stream:
1. If the `stream` is an instance of `ReadStream`, then call `stream.destroy()`
and add a listener to the `open` event to call `stream.close()` if it is
fired. This is for a Node.js bug that will leak a file descriptor if
`.destroy()` is called before `open`.
2. If the `stream` is an instance of a zlib stream, then call `stream.destroy()`
and close the underlying zlib handle if open, otherwise call `stream.close()`.
This is for consistency across Node.js versions and a Node.js bug that will
leak a native zlib handle.
3. If the `stream` is not an instance of `Stream`, then nothing happens.
4. If the `stream` has a `.destroy()` method, then call it.
The function returns the `stream` passed in as the argument.
## Example
```js
var destroy = require('destroy')
var fs = require('fs')
var stream = fs.createReadStream('package.json')
// ... and later
destroy(stream)
```
[npm-image]: https://img.shields.io/npm/v/destroy.svg?style=flat-square
[npm-url]: https://npmjs.org/package/destroy
[github-tag]: http://img.shields.io/github/tag/stream-utils/destroy.svg?style=flat-square
[github-url]: https://github.com/stream-utils/destroy/tags
[coveralls-image]: https://img.shields.io/coveralls/stream-utils/destroy.svg?style=flat-square
[coveralls-url]: https://coveralls.io/r/stream-utils/destroy?branch=master
[license-image]: http://img.shields.io/npm/l/destroy.svg?style=flat-square
[license-url]: LICENSE.md
[downloads-image]: http://img.shields.io/npm/dm/destroy.svg?style=flat-square
[downloads-url]: https://npmjs.org/package/destroy
[github-actions-ci-image]: https://img.shields.io/github/workflow/status/stream-utils/destroy/ci/master?label=ci&style=flat-square
[github-actions-ci-url]: https://github.com/stream-utils/destroy/actions/workflows/ci.yml

145
node_modules/destroy/index.js generated vendored Normal file
View File

@ -0,0 +1,145 @@
/*!
* destroy
* Copyright(c) 2014 Jonathan Ong
* MIT Licensed
*/
'use strict'
/**
* Module dependencies.
* @private
*/
var ReadStream = require('fs').ReadStream
var Stream = require('stream')
var Zlib = require('zlib')
/**
* Module exports.
* @public
*/
module.exports = destroy
/**
* Destroy a stream.
*
* @param {object} stream
* @public
*/
function destroy (stream) {
if (stream instanceof ReadStream) {
return destroyReadStream(stream)
}
if (stream instanceof Zlib.Gzip ||
stream instanceof Zlib.Gunzip ||
stream instanceof Zlib.Deflate ||
stream instanceof Zlib.DeflateRaw ||
stream instanceof Zlib.Inflate ||
stream instanceof Zlib.InflateRaw ||
stream instanceof Zlib.Unzip) {
return destroyZlibStream(stream)
}
if (!(stream instanceof Stream)) {
return stream
}
if (typeof stream.destroy === 'function') {
stream.destroy()
}
return stream
}
/**
* Destroy a ReadStream.
*
* @param {object} stream
* @private
*/
function destroyReadStream (stream) {
stream.destroy()
if (typeof stream.close === 'function') {
// node.js core bug work-around
stream.on('open', onOpenClose)
}
return stream
}
/**
* Destroy a Zlib stream.
*
* Zlib streams don't have a destroy function in Node.js 6. On top of that
* simply calling destroy on a zlib stream in Node.js 8+ will result in a
* memory leak. So until that is fixed, we need to call both close AND destroy.
*
* PR to fix memory leak: https://github.com/nodejs/node/pull/23734
*
* In Node.js 6+8, it's important that destroy is called before close as the
* stream would otherwise emit the error 'zlib binding closed'.
*
* @param {object} stream
* @private
*/
function destroyZlibStream (stream) {
if (typeof stream.destroy === 'function') {
// node.js core bug work-around
// istanbul ignore if: node.js 0.8
if (stream._binding) {
// node.js < 0.10.0
stream.destroy()
if (stream._processing) {
stream._needDrain = true
stream.once('drain', onDrainClearBinding)
} else {
stream._binding.clear()
}
} else if (stream._destroy && stream._destroy !== Stream.Transform.prototype._destroy) {
// node.js >= 12, ^11.1.0, ^10.15.1
stream.destroy()
} else if (stream._destroy && typeof stream.close === 'function') {
// node.js 7, 8
stream.destroyed = true
stream.close()
} else {
// fallback
// istanbul ignore next
stream.destroy()
}
} else if (typeof stream.close === 'function') {
// node.js < 8 fallback
stream.close()
}
return stream
}
/**
* On drain handler to clear binding.
* @private
*/
// istanbul ignore next: node.js 0.8
function onDrainClearBinding () {
this._binding.clear()
}
/**
* On open handler to close stream.
* @private
*/
function onOpenClose () {
if (typeof this.fd === 'number') {
// actually close down the fd
this.close()
}
}

48
node_modules/destroy/package.json generated vendored Normal file
View File

@ -0,0 +1,48 @@
{
"name": "destroy",
"description": "destroy a stream if possible",
"version": "1.1.0",
"author": {
"name": "Jonathan Ong",
"email": "me@jongleberry.com",
"url": "http://jongleberry.com",
"twitter": "https://twitter.com/jongleberry"
},
"contributors": [
"Douglas Christopher Wilson <doug@somethingdoug.com>"
],
"license": "MIT",
"repository": "stream-utils/destroy",
"devDependencies": {
"eslint": "7.32.0",
"eslint-config-standard": "14.1.1",
"eslint-plugin-import": "2.25.4",
"eslint-plugin-node": "11.1.0",
"eslint-plugin-promise": "5.2.0",
"eslint-plugin-standard": "4.1.0",
"mocha": "9.2.0",
"nyc": "15.1.0"
},
"engines": {
"node": ">= 0.8",
"npm": "1.2.8000 || >= 1.4.16"
},
"scripts": {
"lint": "eslint .",
"test": "mocha --reporter spec",
"test-ci": "nyc --reporter=lcovonly --reporter=text npm test",
"test-cov": "nyc --reporter=html --reporter=text npm test"
},
"files": [
"index.js",
"LICENSE"
],
"keywords": [
"stream",
"streams",
"destroy",
"cleanup",
"leak",
"fd"
]
}

7
node_modules/dezalgo/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,7 @@
language: node_js
before_script: npm install -g npm@latest
node_js:
- '0.8'
- '0.10'
- '0.12'
- 'iojs'

15
node_modules/dezalgo/LICENSE generated vendored Normal file
View File

@ -0,0 +1,15 @@
The ISC License
Copyright (c) Isaac Z. Schlueter and Contributors
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

29
node_modules/dezalgo/README.md generated vendored Normal file
View File

@ -0,0 +1,29 @@
# dezalgo
Contain async insanity so that the dark pony lord doesn't eat souls
See [this blog
post](http://blog.izs.me/post/59142742143/designing-apis-for-asynchrony).
## USAGE
Pass a callback to `dezalgo` and it will ensure that it is *always*
called in a future tick, and never in this tick.
```javascript
var dz = require('dezalgo')
var cache = {}
function maybeSync(arg, cb) {
cb = dz(cb)
// this will actually defer to nextTick
if (cache[arg]) cb(null, cache[arg])
fs.readFile(arg, function (er, data) {
// since this is *already* defered, it will call immediately
if (er) cb(er)
cb(null, cache[arg] = data)
})
}
```

22
node_modules/dezalgo/dezalgo.js generated vendored Normal file
View File

@ -0,0 +1,22 @@
var wrappy = require('wrappy')
module.exports = wrappy(dezalgo)
var asap = require('asap')
function dezalgo (cb) {
var sync = true
asap(function () {
sync = false
})
return function zalgoSafe() {
var args = arguments
var me = this
if (sync)
asap(function() {
cb.apply(me, args)
})
else
cb.apply(me, args)
}
}

42
node_modules/dezalgo/package.json generated vendored Normal file
View File

@ -0,0 +1,42 @@
{
"name": "dezalgo",
"version": "1.0.3",
"description": "Contain async insanity so that the dark pony lord doesn't eat souls",
"main": "dezalgo.js",
"directories": {
"test": "test"
},
"dependencies": {
"asap": "^2.0.0",
"wrappy": "1"
},
"devDependencies": {
"tap": "^1.2.0"
},
"scripts": {
"test": "tap test/*.js"
},
"repository": {
"type": "git",
"url": "https://github.com/npm/dezalgo"
},
"keywords": [
"async",
"zalgo",
"the dark pony",
"he comes",
"asynchrony of all holy and good",
"T̯̪ͅo̯͖̹ ̻̮̖̲͢i̥̖n̢͈͇̝͍v͏͉ok̭̬̝ͅe̞͍̩̫͍̩͝ ̩̮̖̟͇͉́t͔͔͎̗h͏̗̟e̘͉̰̦̠̞͓ ͕h͉̟͎̪̠̱͠ḭ̮̩v̺͉͇̩e̵͖-̺̪m͍i̜n̪̲̲̲̮d̷ ̢r̠̼̯̹̦̦͘ͅe͓̳͓̙p̺̗̫͙͘ͅr͔̰͜e̴͓̞s͉̩̩͟ͅe͏̣n͚͇̗̭̺͍tì͙̣n͏̖̥̗͎̰̪g̞͓̭̱̯̫̕ ̣̱͜ͅc̦̰̰̠̮͎͙̀hao̺̜̻͍͙ͅs͉͓̘.͎̼̺̼͕̹͘",
"̠̞̱̰I͖͇̝̻n̦̰͍̰̟v̤̺̫̳̭̼̗͘ò̹̟̩̩͚k̢̥̠͍͉̦̬i̖͓͔̮̱̻͘n̶̳͙̫͎g̖̯̣̲̪͉ ̞͎̗͕͚ͅt̲͕̘̺̯̗̦h̘̦̲̜̻e̳͎͉̬͙ ̴̞̪̲̥f̜̯͓͓̭̭͢e̱̘͔̮e̜̤l̺̱͖̯͓͙͈͢i̵̦̬͉͔̫͚͕n͉g̨͖̙̙̹̹̟̤ ͉̪o̞̠͍̪̰͙ͅf̬̲̺ ͔͕̲͕͕̲̕c̙͉h̝͔̩̙̕ͅa̲͖̻̗̹o̥̼̫s̝̖̜̝͚̫̟.̺͚ ̸̱̲W̶̥̣͖̦i͏̤̬̱̳̣ͅt͉h̗̪̪ ̷̱͚̹̪ǫ͕̗̣̳̦͎u̼̦͔̥̮̕ţ͖͎̻͔͉ ̴͎̩òr̹̰̖͉͈͝d̷̲̦̖͓e̲͓̠r",
"̧͚̜͓̰̭̭Ṯ̫̹̜̮̟̮͝h͚̘̩̘̖̰́e ̥̘͓͉͔͙̼N̟̜̣̘͔̪e̞̞̤͢z̰̖̘͇p̠͟e̺̱̣͍͙̝ṛ̘̬͔̙͇̠d͝ḭ̯̱̥̗̩a̛ͅn͏̦ ̷̥hi̥v̖̳̹͉̮̱͝e̹̪̘̖̰̟-̴͙͓͚̜̻mi̗̺̻͙̺ͅn̪̯͈d ͏̘͓̫̳ͅơ̹͔̳̖̣͓f͈̹̘ ͕ͅc̗̤̠̜̮̥̥h̡͍̩̭̫͚̱a̤͉̤͔͜os͕̤̼͍̲̀ͅ.̡̱ ̦Za̯̱̗̭͍̣͚l̗͉̰̤g͏̣̭̬̗̲͖ͅo̶̭̩̳̟͈.̪̦̰̳",
"H̴̱̦̗̬̣͓̺e̮ ͉̠̰̞͎̖͟ẁh̛̺̯ͅo̖̫͡ ̢Ẁa̡̗i̸t͖̣͉̀ş͔̯̩ ̤̦̮͇̞̦̲B͎̭͇̦̼e̢hin͏͙̟̪d̴̰͓̻̣̮͕ͅ T͖̮̕h͖e̘̺̰̙͘ ̥Ẁ̦͔̻͚a̞͖̪͉l̪̠̻̰̣̠l̲͎͞",
"Z̘͍̼͎̣͔͝Ą̲̜̱̱̹̤͇L̶̝̰̭͔G͍̖͍O̫͜ͅ!̼̤ͅ",
"H̝̪̜͓̀̌̂̒E̢̙̠̣ ̴̳͇̥̟̠͍̐C̹̓̑̐̆͝Ó̶̭͓̚M̬̼Ĕ̖̤͔͔̟̹̽̿̊ͥ̍ͫS̻̰̦̻̖̘̱̒ͪ͌̅͟"
],
"author": "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me/)",
"license": "ISC",
"bugs": {
"url": "https://github.com/npm/dezalgo/issues"
},
"homepage": "https://github.com/npm/dezalgo"
}

29
node_modules/dezalgo/test/basic.js generated vendored Normal file
View File

@ -0,0 +1,29 @@
var test = require('tap').test
var dz = require('../dezalgo.js')
test('the dark pony', function(t) {
var n = 0
function foo(i, cb) {
cb = dz(cb)
if (++n % 2) cb(true, i)
else process.nextTick(cb.bind(null, false, i))
}
var called = 0
var order = [0, 2, 4, 6, 8, 1, 3, 5, 7, 9]
var o = 0
for (var i = 0; i < 10; i++) {
foo(i, function(cached, i) {
t.equal(i, order[o++])
t.equal(i % 2, cached ? 0 : 1)
called++
})
t.equal(called, 0)
}
setTimeout(function() {
t.equal(called, 10)
t.end()
})
})

22
node_modules/ee-first/LICENSE generated vendored Normal file
View File

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2014 Jonathan Ong me@jongleberry.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

80
node_modules/ee-first/README.md generated vendored Normal file
View File

@ -0,0 +1,80 @@
# EE First
[![NPM version][npm-image]][npm-url]
[![Build status][travis-image]][travis-url]
[![Test coverage][coveralls-image]][coveralls-url]
[![License][license-image]][license-url]
[![Downloads][downloads-image]][downloads-url]
[![Gittip][gittip-image]][gittip-url]
Get the first event in a set of event emitters and event pairs,
then clean up after itself.
## Install
```sh
$ npm install ee-first
```
## API
```js
var first = require('ee-first')
```
### first(arr, listener)
Invoke `listener` on the first event from the list specified in `arr`. `arr` is
an array of arrays, with each array in the format `[ee, ...event]`. `listener`
will be called only once, the first time any of the given events are emitted. If
`error` is one of the listened events, then if that fires first, the `listener`
will be given the `err` argument.
The `listener` is invoked as `listener(err, ee, event, args)`, where `err` is the
first argument emitted from an `error` event, if applicable; `ee` is the event
emitter that fired; `event` is the string event name that fired; and `args` is an
array of the arguments that were emitted on the event.
```js
var ee1 = new EventEmitter()
var ee2 = new EventEmitter()
first([
[ee1, 'close', 'end', 'error'],
[ee2, 'error']
], function (err, ee, event, args) {
// listener invoked
})
```
#### .cancel()
The group of listeners can be cancelled before being invoked and have all the event
listeners removed from the underlying event emitters.
```js
var thunk = first([
[ee1, 'close', 'end', 'error'],
[ee2, 'error']
], function (err, ee, event, args) {
// listener invoked
})
// cancel and clean up
thunk.cancel()
```
[npm-image]: https://img.shields.io/npm/v/ee-first.svg?style=flat-square
[npm-url]: https://npmjs.org/package/ee-first
[github-tag]: http://img.shields.io/github/tag/jonathanong/ee-first.svg?style=flat-square
[github-url]: https://github.com/jonathanong/ee-first/tags
[travis-image]: https://img.shields.io/travis/jonathanong/ee-first.svg?style=flat-square
[travis-url]: https://travis-ci.org/jonathanong/ee-first
[coveralls-image]: https://img.shields.io/coveralls/jonathanong/ee-first.svg?style=flat-square
[coveralls-url]: https://coveralls.io/r/jonathanong/ee-first?branch=master
[license-image]: http://img.shields.io/npm/l/ee-first.svg?style=flat-square
[license-url]: LICENSE.md
[downloads-image]: http://img.shields.io/npm/dm/ee-first.svg?style=flat-square
[downloads-url]: https://npmjs.org/package/ee-first
[gittip-image]: https://img.shields.io/gittip/jonathanong.svg?style=flat-square
[gittip-url]: https://www.gittip.com/jonathanong/

95
node_modules/ee-first/index.js generated vendored Normal file
View File

@ -0,0 +1,95 @@
/*!
* ee-first
* Copyright(c) 2014 Jonathan Ong
* MIT Licensed
*/
'use strict'
/**
* Module exports.
* @public
*/
module.exports = first
/**
* Get the first event in a set of event emitters and event pairs.
*
* @param {array} stuff
* @param {function} done
* @public
*/
function first(stuff, done) {
if (!Array.isArray(stuff))
throw new TypeError('arg must be an array of [ee, events...] arrays')
var cleanups = []
for (var i = 0; i < stuff.length; i++) {
var arr = stuff[i]
if (!Array.isArray(arr) || arr.length < 2)
throw new TypeError('each array member must be [ee, events...]')
var ee = arr[0]
for (var j = 1; j < arr.length; j++) {
var event = arr[j]
var fn = listener(event, callback)
// listen to the event
ee.on(event, fn)
// push this listener to the list of cleanups
cleanups.push({
ee: ee,
event: event,
fn: fn,
})
}
}
function callback() {
cleanup()
done.apply(null, arguments)
}
function cleanup() {
var x
for (var i = 0; i < cleanups.length; i++) {
x = cleanups[i]
x.ee.removeListener(x.event, x.fn)
}
}
function thunk(fn) {
done = fn
}
thunk.cancel = cleanup
return thunk
}
/**
* Create the event listener.
* @private
*/
function listener(event, done) {
return function onevent(arg1) {
var args = new Array(arguments.length)
var ee = this
var err = event === 'error'
? arg1
: null
// copy args to prevent arguments escaping scope
for (var i = 0; i < args.length; i++) {
args[i] = arguments[i]
}
done(err, ee, event, args)
}
}

29
node_modules/ee-first/package.json generated vendored Normal file
View File

@ -0,0 +1,29 @@
{
"name": "ee-first",
"description": "return the first event in a set of ee/event pairs",
"version": "1.1.1",
"author": {
"name": "Jonathan Ong",
"email": "me@jongleberry.com",
"url": "http://jongleberry.com",
"twitter": "https://twitter.com/jongleberry"
},
"contributors": [
"Douglas Christopher Wilson <doug@somethingdoug.com>"
],
"license": "MIT",
"repository": "jonathanong/ee-first",
"devDependencies": {
"istanbul": "0.3.9",
"mocha": "2.2.5"
},
"files": [
"index.js",
"LICENSE"
],
"scripts": {
"test": "mocha --reporter spec --bail --check-leaks test/",
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/",
"test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/"
}
}

21
node_modules/formidable/LICENSE generated vendored Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2011-present Felix Geisendörfer, and contributors.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

826
node_modules/formidable/README.md generated vendored Normal file
View File

@ -0,0 +1,826 @@
<p align="center">
<img alt="npm formidable package logo" src="https://raw.githubusercontent.com/node-formidable/formidable/master/logo.png" />
</p>
# formidable [![npm version][npmv-img]][npmv-url] [![MIT license][license-img]][license-url] [![Libera Manifesto][libera-manifesto-img]][libera-manifesto-url] [![Twitter][twitter-img]][twitter-url]
> A Node.js module for parsing form data, especially file uploads.
[![Code style][codestyle-img]][codestyle-url]
[![codecoverage][codecov-img]][codecov-url]
[![linux build status][linux-build-img]][build-url]
[![windows build status][windows-build-img]][build-url]
[![macos build status][macos-build-img]][build-url]
If you have any _how-to_ kind of questions, please read the [Contributing
Guide][contributing-url] and [Code of Conduct][code_of_conduct-url]
documents.<br /> For bugs reports and feature requests, [please create an
issue][open-issue-url] or ping [@tunnckoCore / @3a1FcBx0](https://twitter.com/3a1FcBx0)
at Twitter.
[![Conventional Commits][ccommits-img]][ccommits-url]
[![Minimum Required Nodejs][nodejs-img]][npmv-url]
[![Tidelift Subcsription][tidelift-img]][tidelift-url]
[![Buy me a Kofi][kofi-img]][kofi-url]
[![Renovate App Status][renovateapp-img]][renovateapp-url]
[![Make A Pull Request][prs-welcome-img]][prs-welcome-url]
This project is [semantically versioned](https://semver.org) and available as
part of the [Tidelift Subscription][tidelift-url] for professional grade
assurances, enhanced support and security.
[Learn more.](https://tidelift.com/subscription/pkg/npm-formidable?utm_source=npm-formidable&utm_medium=referral&utm_campaign=enterprise)
_The maintainers of `formidable` and thousands of other packages are working
with Tidelift to deliver commercial support and maintenance for the Open Source
dependencies you use to build your applications. Save time, reduce risk, and
improve code health, while paying the maintainers of the exact dependencies you
use._
[![][npm-weekly-img]][npmv-url] [![][npm-monthly-img]][npmv-url]
[![][npm-yearly-img]][npmv-url] [![][npm-alltime-img]][npmv-url]
## Project Status: Maintained
_Check [VERSION NOTES](https://github.com/node-formidable/formidable/blob/master/VERSION_NOTES.md) for more information on v1, v2, and v3 plans, NPM dist-tags and branches._
This module was initially developed by
[**@felixge**](https://github.com/felixge) for
[Transloadit](http://transloadit.com/), a service focused on uploading and
encoding images and videos. It has been battle-tested against hundreds of GBs of
file uploads from a large variety of clients and is considered production-ready
and is used in production for years.
Currently, we are few maintainers trying to deal with it. :) More contributors
are always welcome! :heart: Jump on
[issue #412](https://github.com/felixge/node-formidable/issues/412) which is
closed, but if you are interested we can discuss it and add you after strict
rules, like enabling Two-Factor Auth in your npm and GitHub accounts.
## Highlights
- [Fast (~900-2500 mb/sec)](#benchmarks) & streaming multipart parser
- Automatically writing file uploads to disk (optional, see
[`options.fileWriteStreamHandler`](#options))
- [Plugins API](#useplugin-plugin) - allowing custom parsers and plugins
- Low memory footprint
- Graceful error handling
- Very high test coverage
## Install
This project requires `Node.js >= 10.13`. Install it using
[yarn](https://yarnpkg.com) or [npm](https://npmjs.com).<br /> _We highly
recommend to use Yarn when you think to contribute to this project._
This is a low-level package, and if you're using a high-level framework it _may_
already be included. Check the examples below and the [examples/](https://github.com/node-formidable/formidable/tree/master/examples) folder.
```sh
# v2
npm install formidable
npm install formidable@latest
npm install formidable@v2
# or v3
npm install formidable@v3
```
_**Note:** In near future v3 will be published on the `latest` NPM dist-tag. Future not ready releases will continue to be published on `canary` dist-tag._
## Examples
For more examples look at the `examples/` directory.
### with Node.js http module
Parse an incoming file upload, with the
[Node.js's built-in `http` module](https://nodejs.org/api/http.html).
```js
const http = require('http');
const formidable = require('formidable');
const server = http.createServer((req, res) => {
if (req.url === '/api/upload' && req.method.toLowerCase() === 'post') {
// parse a file upload
const form = formidable({ multiples: true });
form.parse(req, (err, fields, files) => {
if (err) {
res.writeHead(err.httpCode || 400, { 'Content-Type': 'text/plain' });
res.end(String(err));
return;
}
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ fields, files }, null, 2));
});
return;
}
// show a file upload form
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end(`
<h2>With Node.js <code>"http"</code> module</h2>
<form action="/api/upload" enctype="multipart/form-data" method="post">
<div>Text field title: <input type="text" name="title" /></div>
<div>File: <input type="file" name="multipleFiles" multiple="multiple" /></div>
<input type="submit" value="Upload" />
</form>
`);
});
server.listen(8080, () => {
console.log('Server listening on http://localhost:8080/ ...');
});
```
### with Express.js
There are multiple variants to do this, but Formidable just need Node.js Request
stream, so something like the following example should work just fine, without
any third-party [Express.js](https://ghub.now.sh/express) middleware.
Or try the
[examples/with-express.js](https://github.com/node-formidable/formidable/blob/master/examples/with-express.js)
```js
const express = require('express');
const formidable = require('formidable');
const app = express();
app.get('/', (req, res) => {
res.send(`
<h2>With <code>"express"</code> npm package</h2>
<form action="/api/upload" enctype="multipart/form-data" method="post">
<div>Text field title: <input type="text" name="title" /></div>
<div>File: <input type="file" name="someExpressFiles" multiple="multiple" /></div>
<input type="submit" value="Upload" />
</form>
`);
});
app.post('/api/upload', (req, res, next) => {
const form = formidable({ multiples: true });
form.parse(req, (err, fields, files) => {
if (err) {
next(err);
return;
}
res.json({ fields, files });
});
});
app.listen(3000, () => {
console.log('Server listening on http://localhost:3000 ...');
});
```
### with Koa and Formidable
Of course, with [Koa v1, v2 or future v3](https://ghub.now.sh/koa) the things
are very similar. You can use `formidable` manually as shown below or through
the [koa-better-body](https://ghub.now.sh/koa-better-body) package which is
using `formidable` under the hood and support more features and different
request bodies, check its documentation for more info.
_Note: this example is assuming Koa v2. Be aware that you should pass `ctx.req`
which is Node.js's Request, and **NOT** the `ctx.request` which is Koa's Request
object - there is a difference._
```js
const Koa = require('koa');
const formidable = require('formidable');
const app = new Koa();
app.on('error', (err) => {
console.error('server error', err);
});
app.use(async (ctx, next) => {
if (ctx.url === '/api/upload' && ctx.method.toLowerCase() === 'post') {
const form = formidable({ multiples: true });
// not very elegant, but that's for now if you don't want to use `koa-better-body`
// or other middlewares.
await new Promise((resolve, reject) => {
form.parse(ctx.req, (err, fields, files) => {
if (err) {
reject(err);
return;
}
ctx.set('Content-Type', 'application/json');
ctx.status = 200;
ctx.state = { fields, files };
ctx.body = JSON.stringify(ctx.state, null, 2);
resolve();
});
});
await next();
return;
}
// show a file upload form
ctx.set('Content-Type', 'text/html');
ctx.status = 200;
ctx.body = `
<h2>With <code>"koa"</code> npm package</h2>
<form action="/api/upload" enctype="multipart/form-data" method="post">
<div>Text field title: <input type="text" name="title" /></div>
<div>File: <input type="file" name="koaFiles" multiple="multiple" /></div>
<input type="submit" value="Upload" />
</form>
`;
});
app.use((ctx) => {
console.log('The next middleware is called');
console.log('Results:', ctx.state);
});
app.listen(3000, () => {
console.log('Server listening on http://localhost:3000 ...');
});
```
## Benchmarks
The benchmark is quite old, from the old codebase. But maybe quite true though.
Previously the numbers was around ~500 mb/sec. Currently with moving to the new
Node.js Streams API it's faster. You can clearly see the differences between the
Node versions.
_Note: a lot better benchmarking could and should be done in future._
Benchmarked on 8GB RAM, Xeon X3440 (2.53 GHz, 4 cores, 8 threads)
```
~/github/node-formidable master
nve --parallel 8 10 12 13 node benchmark/bench-multipart-parser.js
⬢ Node 8
1261.08 mb/sec
⬢ Node 10
1113.04 mb/sec
⬢ Node 12
2107.00 mb/sec
⬢ Node 13
2566.42 mb/sec
```
![benchmark January 29th, 2020](./benchmark/2020-01-29_xeon-x3440.png)
## API
### Formidable / IncomingForm
All shown are equivalent.
_Please pass [`options`](#options) to the function/constructor, not by assigning
them to the instance `form`_
```js
const formidable = require('formidable');
const form = formidable(options);
// or
const { formidable } = require('formidable');
const form = formidable(options);
// or
const { IncomingForm } = require('formidable');
const form = new IncomingForm(options);
// or
const { Formidable } = require('formidable');
const form = new Formidable(options);
```
### Options
See it's defaults in [src/Formidable.js DEFAULT_OPTIONS](./src/Formidable.js)
(the `DEFAULT_OPTIONS` constant).
- `options.encoding` **{string}** - default `'utf-8'`; sets encoding for
incoming form fields,
- `options.uploadDir` **{string}** - default `os.tmpdir()`; the directory for
placing file uploads in. You can move them later by using `fs.rename()`.
- `options.keepExtensions` **{boolean}** - default `false`; to include the
extensions of the original files or not
- `options.allowEmptyFiles` **{boolean}** - default `true`; allow upload empty
files
- `options.minFileSize` **{number}** - default `1` (1byte); the minium size of
uploaded file.
- `options.maxFileSize` **{number}** - default `200 * 1024 * 1024` (200mb);
limit the size of uploaded file.
- `options.maxFields` **{number}** - default `1000`; limit the number of fields, set 0 for unlimited
- `options.maxFieldsSize` **{number}** - default `20 * 1024 * 1024` (20mb);
limit the amount of memory all fields together (except files) can allocate in
bytes.
- `options.hashAlgorithm` **{string | false}** - 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.fileWriteStreamHandler` **{function}** - default `null`, which by
default writes to host machine file system every file parsed; The function
should return an instance of a
[Writable stream](https://nodejs.org/api/stream.html#stream_class_stream_writable)
that will receive the uploaded file data. With this option, you can have any
custom behavior regarding where the uploaded file data will be streamed for.
If you are looking to write the file uploaded in other types of cloud storages
(AWS S3, Azure blob storage, Google cloud storage) or private file storage,
this is the option you're looking for. When this option is defined the default
behavior of writing the file in the host machine file system is lost.
- `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.filename` **{function}** - default `undefined` Use it to control
newFilename. Must return a string. Will be joined with options.uploadDir.
- `options.filter` **{function}** - default function that always returns true.
Use it to filter files before they are uploaded. Must return a boolean.
#### `options.filename` **{function}** function (name, ext, part, form) -> string
_**Note:** If this size of combined fields, or size of some file is exceeded, an
`'error'` event is fired._
```js
// The amount of bytes received for this form so far.
form.bytesReceived;
```
```js
// The expected number of bytes in this form.
form.bytesExpected;
```
#### `options.filter` **{function}** function ({name, originalFilename, mimetype}) -> boolean
**Note:** use an outside variable to cancel all uploads upon the first error
```js
const options = {
filter: function ({name, originalFilename, mimetype}) {
// keep only images
return mimetype && mimetype.includes("image");
}
};
```
### .parse(request, callback)
Parses an incoming Node.js `request` containing form data. If `callback` is
provided, all fields and files are collected and passed to the callback.
```js
const formidable = require('formidable');
const form = formidable({ multiples: true, uploadDir: __dirname });
form.parse(req, (err, fields, files) => {
console.log('fields:', fields);
console.log('files:', files);
});
```
You may overwrite this method if you are interested in directly accessing the
multipart stream. Doing so will disable any `'field'` / `'file'` events
processing which would occur otherwise, making you fully responsible for
handling the processing.
About `uploadDir`, given the following directory structure
```
project-name
├── src
│ └── server.js
└── uploads
└── image.jpg
```
`__dirname` would be the same directory as the source file itself (src)
```js
`${__dirname}/../uploads`
```
to put files in uploads.
Omitting `__dirname` would make the path relative to the current working directory. This would be the same if server.js is launched from src but not project-name.
`null` will use default which is `os.tmpdir()`
Note: If the directory does not exist, the uploaded files are __silently discarded__. To make sure it exists:
```js
import {createNecessaryDirectoriesSync} from "filesac";
const uploadPath = `${__dirname}/../uploads`;
createNecessaryDirectoriesSync(`${uploadPath}/x`);
```
In the example below, we listen on couple of events and direct them to the
`data` listener, so you can do whatever you choose there, based on whether its
before the file been emitted, the header value, the header name, on field, on
file and etc.
Or the other way could be to just override the `form.onPart` as it's shown a bit
later.
```js
form.once('error', console.error);
form.on('fileBegin', (formname, file) => {
form.emit('data', { name: 'fileBegin', formname, value: file });
});
form.on('file', (formname, file) => {
form.emit('data', { name: 'file', formname, value: file });
});
form.on('field', (fieldName, fieldValue) => {
form.emit('data', { name: 'field', key: fieldName, value: fieldValue });
});
form.once('end', () => {
console.log('Done!');
});
// If you want to customize whatever you want...
form.on('data', ({ name, key, value, buffer, start, end, formname, ...more }) => {
if (name === 'partBegin') {
}
if (name === 'partData') {
}
if (name === 'headerField') {
}
if (name === 'headerValue') {
}
if (name === 'headerEnd') {
}
if (name === 'headersEnd') {
}
if (name === 'field') {
console.log('field name:', key);
console.log('field value:', value);
}
if (name === 'file') {
console.log('file:', formname, value);
}
if (name === 'fileBegin') {
console.log('fileBegin:', formname, value);
}
});
```
### .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({
hashAlgorithm: '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. Or see
[#387](https://github.com/node-formidable/node-formidable/issues/387) for
inspiration, you can for example validate the mime-type.
```js
const form = formidable();
form.onPart = (part) => {
part.on('data', (buffer) => {
// do whatever you want here
});
};
```
For example, force Formidable to be used only on non-file "parts" (i.e., html
fields)
```js
const form = formidable();
form.onPart = function (part) {
// let formidable handle only non-file parts
if (part.originalFilename === '' || !part.mimetype) {
// used internally, please do not override!
form._handlePart(part);
}
};
```
### File
```ts
export interface File {
// The size of the uploaded file in bytes.
// If the file is still being uploaded (see `'fileBegin'` event),
// this property says how many bytes of the file have been written to disk yet.
file.size: number;
// The path this file is being written to. You can modify this in the `'fileBegin'` event in
// case you are unhappy with the way formidable generates a temporary path for your files.
file.filepath: string;
// The name this file had according to the uploading client.
file.originalFilename: string | null;
// calculated based on options provided
file.newFilename: string | null;
// The mime type of this file, according to the uploading client.
file.mimetype: string | null;
// A Date object (or `null`) containing the time this file was last written to.
// Mostly here for compatibility with the [W3C File API Draft](http://dev.w3.org/2006/webapi/FileAPI/).
file.mtime: Date | null;
file.hashAlgorithm: false | |'sha1' | 'md5' | 'sha256'
// If `options.hashAlgorithm` calculation was set, you can read the hex digest out of this var (at the end it will be a string)
file.hash: string | object | null;
}
```
#### file.toJSON()
This method returns a JSON-representation of the file, allowing you to
`JSON.stringify()` the file which is useful for logging and responding to
requests.
### Events
#### `'progress'`
Emitted after each incoming chunk of data that has been parsed. Can be used to
roll your own progress bar.
```js
form.on('progress', (bytesReceived, bytesExpected) => {});
```
#### `'field'`
Emitted whenever a field / value pair has been received.
```js
form.on('field', (name, value) => {});
```
#### `'fileBegin'`
Emitted whenever a new file is detected in the upload stream. Use this event if
you want to stream the file to somewhere else while buffering the upload on the
file system.
```js
form.on('fileBegin', (formName, file) => {
// accessible here
// formName the name in the form (<input name="thisname" type="file">) or http filename for octetstream
// file.originalFilename http filename or null if there was a parsing error
// file.newFilename generated hexoid or what options.filename returned
// file.filepath default pathnme as per options.uploadDir and options.filename
// file.filepath = CUSTOM_PATH // to change the final path
});
```
#### `'file'`
Emitted whenever a field / file pair has been received. `file` is an instance of
`File`.
```js
form.on('file', (formname, file) => {
// same as fileBegin, except
// it is too late to change file.filepath
// file.hash is available if options.hash was used
});
```
#### `'error'`
Emitted when there is an error processing the incoming form. A request that
experiences an error is automatically paused, you will have to manually call
`request.resume()` if you want the request to continue firing `'data'` events.
May have `error.httpCode` and `error.code` attached.
```js
form.on('error', (err) => {});
```
#### `'aborted'`
Emitted when the request was aborted by the user. Right now this can be due to a
'timeout' or 'close' event on the socket. After this event is emitted, an
`error` event will follow. In the future there will be a separate 'timeout'
event (needs a change in the node core).
```js
form.on('aborted', () => {});
```
#### `'end'`
Emitted when the entire request has been received, and all contained files have
finished flushing to disk. This is a great place for you to send your response.
```js
form.on('end', () => {});
```
## Changelog
[./CHANGELOG.md](./CHANGELOG.md)
## Ports & Credits
- [multipart-parser](http://github.com/FooBarWidget/multipart-parser): a C++
parser based on formidable
- [Ryan Dahl](http://twitter.com/ryah) for his work on
[http-parser](http://github.com/ry/http-parser) which heavily inspired the
initial `multipart_parser.js`.
## Contributing
If the documentation is unclear or has a typo, please click on the page's `Edit`
button (pencil icon) and suggest a correction. If you would like to help us fix
a bug or add a new feature, please check our [Contributing
Guide][contributing-url]. Pull requests are welcome!
Thanks goes to these wonderful people
([emoji key](https://allcontributors.org/docs/en/emoji-key)):
<!-- ALL-CONTRIBUTORS-LIST:START -->
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<table>
<tr>
<td align="center"><a href="https://twitter.com/felixge"><img src="https://avatars3.githubusercontent.com/u/15000?s=460&v=4" width="100px;" alt=""/><br /><sub><b>Felix Geisendörfer</b></sub></a><br /><a href="https://github.com/node-formidable/node-formidable/commits?author=felixge" title="Code">💻</a> <a href="#design-felixge" title="Design">🎨</a> <a href="#ideas-felixge" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/node-formidable/node-formidable/commits?author=felixge" title="Documentation">📖</a></td>
<td align="center"><a href="https://tunnckoCore.com"><img src="https://avatars3.githubusercontent.com/u/5038030?v=4" width="100px;" alt=""/><br /><sub><b>Charlike Mike Reagent</b></sub></a><br /><a href="https://github.com/node-formidable/node-formidable/issues?q=author%3AtunnckoCore" title="Bug reports">🐛</a> <a href="#infra-tunnckoCore" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#design-tunnckoCore" title="Design">🎨</a> <a href="https://github.com/node-formidable/node-formidable/commits?author=tunnckoCore" title="Code">💻</a> <a href="https://github.com/node-formidable/node-formidable/commits?author=tunnckoCore" title="Documentation">📖</a> <a href="#example-tunnckoCore" title="Examples">💡</a> <a href="#ideas-tunnckoCore" title="Ideas, Planning, & Feedback">🤔</a> <a href="#maintenance-tunnckoCore" title="Maintenance">🚧</a> <a href="https://github.com/node-formidable/node-formidable/commits?author=tunnckoCore" title="Tests">⚠️</a></td>
<td align="center"><a href="https://github.com/kedarv"><img src="https://avatars1.githubusercontent.com/u/1365665?v=4" width="100px;" alt=""/><br /><sub><b>Kedar</b></sub></a><br /><a href="https://github.com/node-formidable/node-formidable/commits?author=kedarv" title="Code">💻</a> <a href="https://github.com/node-formidable/node-formidable/commits?author=kedarv" title="Tests">⚠️</a> <a href="#question-kedarv" title="Answering Questions">💬</a> <a href="https://github.com/node-formidable/node-formidable/issues?q=author%3Akedarv" title="Bug reports">🐛</a></td>
<td align="center"><a href="https://github.com/GrosSacASac"><img src="https://avatars0.githubusercontent.com/u/5721194?v=4" width="100px;" alt=""/><br /><sub><b>Walle Cyril</b></sub></a><br /><a href="#question-GrosSacASac" title="Answering Questions">💬</a> <a href="https://github.com/node-formidable/node-formidable/issues?q=author%3AGrosSacASac" title="Bug reports">🐛</a> <a href="https://github.com/node-formidable/node-formidable/commits?author=GrosSacASac" title="Code">💻</a> <a href="#financial-GrosSacASac" title="Financial">💵</a> <a href="#ideas-GrosSacASac" title="Ideas, Planning, & Feedback">🤔</a> <a href="#maintenance-GrosSacASac" title="Maintenance">🚧</a></td>
<td align="center"><a href="https://github.com/xarguments"><img src="https://avatars2.githubusercontent.com/u/40522463?v=4" width="100px;" alt=""/><br /><sub><b>Xargs</b></sub></a><br /><a href="#question-xarguments" title="Answering Questions">💬</a> <a href="https://github.com/node-formidable/node-formidable/issues?q=author%3Axarguments" title="Bug reports">🐛</a> <a href="https://github.com/node-formidable/node-formidable/commits?author=xarguments" title="Code">💻</a> <a href="#maintenance-xarguments" title="Maintenance">🚧</a></td>
<td align="center"><a href="https://github.com/Amit-A"><img src="https://avatars1.githubusercontent.com/u/7987238?v=4" width="100px;" alt=""/><br /><sub><b>Amit-A</b></sub></a><br /><a href="#question-Amit-A" title="Answering Questions">💬</a> <a href="https://github.com/node-formidable/node-formidable/issues?q=author%3AAmit-A" title="Bug reports">🐛</a> <a href="https://github.com/node-formidable/node-formidable/commits?author=Amit-A" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://charmander.me/"><img src="https://avatars1.githubusercontent.com/u/1889843?v=4" width="100px;" alt=""/><br /><sub><b>Charmander</b></sub></a><br /><a href="#question-charmander" title="Answering Questions">💬</a> <a href="https://github.com/node-formidable/node-formidable/issues?q=author%3Acharmander" title="Bug reports">🐛</a> <a href="https://github.com/node-formidable/node-formidable/commits?author=charmander" title="Code">💻</a> <a href="#ideas-charmander" title="Ideas, Planning, & Feedback">🤔</a> <a href="#maintenance-charmander" title="Maintenance">🚧</a></td>
<td align="center"><a href="https://twitter.com/dylan_piercey"><img src="https://avatars2.githubusercontent.com/u/4985201?v=4" width="100px;" alt=""/><br /><sub><b>Dylan Piercey</b></sub></a><br /><a href="#ideas-DylanPiercey" title="Ideas, Planning, & Feedback">🤔</a></td>
<td align="center"><a href="http://ochrona.jawne.info.pl"><img src="https://avatars1.githubusercontent.com/u/3618479?v=4" width="100px;" alt=""/><br /><sub><b>Adam Dobrawy</b></sub></a><br /><a href="https://github.com/node-formidable/node-formidable/issues?q=author%3Aad-m" title="Bug reports">🐛</a> <a href="https://github.com/node-formidable/node-formidable/commits?author=ad-m" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/amitrohatgi"><img src="https://avatars3.githubusercontent.com/u/12177021?v=4" width="100px;" alt=""/><br /><sub><b>amitrohatgi</b></sub></a><br /><a href="#ideas-amitrohatgi" title="Ideas, Planning, & Feedback">🤔</a></td>
<td align="center"><a href="https://github.com/fengxinming"><img src="https://avatars2.githubusercontent.com/u/6262382?v=4" width="100px;" alt=""/><br /><sub><b>Jesse Feng</b></sub></a><br /><a href="https://github.com/node-formidable/node-formidable/issues?q=author%3Afengxinming" title="Bug reports">🐛</a></td>
<td align="center"><a href="https://qtmsheep.com"><img src="https://avatars1.githubusercontent.com/u/7271496?v=4" width="100px;" alt=""/><br /><sub><b>Nathanael Demacon</b></sub></a><br /><a href="#question-quantumsheep" title="Answering Questions">💬</a> <a href="https://github.com/node-formidable/node-formidable/commits?author=quantumsheep" title="Code">💻</a> <a href="https://github.com/node-formidable/node-formidable/pulls?q=is%3Apr+reviewed-by%3Aquantumsheep" title="Reviewed Pull Requests">👀</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/MunMunMiao"><img src="https://avatars1.githubusercontent.com/u/18216142?v=4" width="100px;" alt=""/><br /><sub><b>MunMunMiao</b></sub></a><br /><a href="https://github.com/node-formidable/node-formidable/issues?q=author%3AMunMunMiao" title="Bug reports">🐛</a></td>
<td align="center"><a href="https://github.com/gabipetrovay"><img src="https://avatars0.githubusercontent.com/u/1170398?v=4" width="100px;" alt=""/><br /><sub><b>Gabriel Petrovay</b></sub></a><br /><a href="https://github.com/node-formidable/node-formidable/issues?q=author%3Agabipetrovay" title="Bug reports">🐛</a> <a href="https://github.com/node-formidable/node-formidable/commits?author=gabipetrovay" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/Elzair"><img src="https://avatars0.githubusercontent.com/u/2352818?v=4" width="100px;" alt=""/><br /><sub><b>Philip Woods</b></sub></a><br /><a href="https://github.com/node-formidable/node-formidable/commits?author=Elzair" title="Code">💻</a> <a href="#ideas-Elzair" title="Ideas, Planning, & Feedback">🤔</a></td>
<td align="center"><a href="https://github.com/dmolim"><img src="https://avatars2.githubusercontent.com/u/7090374?v=4" width="100px;" alt=""/><br /><sub><b>Dmitry Ivonin</b></sub></a><br /><a href="https://github.com/node-formidable/node-formidable/commits?author=dmolim" title="Documentation">📖</a></td>
<td align="center"><a href="https://audiobox.fm"><img src="https://avatars1.githubusercontent.com/u/12844?v=4" width="100px;" alt=""/><br /><sub><b>Claudio Poli</b></sub></a><br /><a href="https://github.com/node-formidable/node-formidable/commits?author=masterkain" title="Code">💻</a></td>
</tr>
</table>
<!-- markdownlint-enable -->
<!-- prettier-ignore-end -->
<!-- ALL-CONTRIBUTORS-LIST:END -->
From a [Felix blog post](https://felixge.de/2013/03/11/the-pull-request-hack/):
- [Sven Lito](https://github.com/svnlto) for fixing bugs and merging patches
- [egirshov](https://github.com/egirshov) for contributing many improvements to the node-formidable multipart parser
- [Andrew Kelley](https://github.com/superjoe30) for also helping with fixing bugs and making improvements
- [Mike Frey](https://github.com/mikefrey) for contributing JSON support
## License
Formidable is licensed under the [MIT License][license-url].
<!-- badges -->
<!-- prettier-ignore-start -->
[codestyle-url]: https://github.com/airbnb/javascript
[codestyle-img]: https://badgen.net/badge/code%20style/airbnb%20%2B%20prettier/ff5a5f?icon=airbnb&cache=300
[codecov-url]: https://codecov.io/gh/node-formidable/formidable
[codecov-img]: https://badgen.net/codecov/c/github/node-formidable/formidable/master?icon=codecov
[npmv-canary-img]: https://badgen.net/npm/v/formidable/canary?icon=npm
[npmv-dev-img]: https://badgen.net/npm/v/formidable/dev?icon=npm
[npmv-img]: https://badgen.net/npm/v/formidable?icon=npm
[npmv-url]: https://npmjs.com/package/formidable
[license-img]: https://badgen.net/npm/license/formidable
[license-url]: https://github.com/node-formidable/formidable/blob/master/LICENSE
[chat-img]: https://badgen.net/badge/chat/on%20gitter/46BC99?icon=gitter
[chat-url]: https://gitter.im/node-formidable/Lobby
[libera-manifesto-url]: https://liberamanifesto.com
[libera-manifesto-img]: https://badgen.net/badge/libera/manifesto/grey
[renovateapp-url]: https://renovatebot.com
[renovateapp-img]: https://badgen.net/badge/renovate/enabled/green?cache=300
[prs-welcome-img]: https://badgen.net/badge/PRs/welcome/green?cache=300
[prs-welcome-url]: http://makeapullrequest.com
[twitter-url]: https://twitter.com/3a1fcBx0
[twitter-img]: https://badgen.net/twitter/follow/3a1fcBx0?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&label=total%20downloads
[nodejs-img]: https://badgen.net/badge/node/>=%2010.13/green?cache=300
[ccommits-url]: https://conventionalcommits.org/
[ccommits-img]: https://badgen.net/badge/conventional%20commits/v1.0.0/green?cache=300
[contributing-url]: https://github.com/node-formidable/.github/blob/master/CONTRIBUTING.md
[code_of_conduct-url]: https://github.com/node-formidable/.github/blob/master/CODE_OF_CONDUCT.md
[open-issue-url]: https://github.com/node-formidable/formidable/issues/new
[tidelift-url]: https://tidelift.com/subscription/pkg/npm-formidable?utm_source=npm-formidable&utm_medium=referral&utm_campaign=enterprise
[tidelift-img]: https://badgen.net/badge/tidelift/subscription/4B5168?labelColor=F6914D
[kofi-url]: https://ko-fi.com/tunnckoCore/commissions
[kofi-img]: https://badgen.net/badge/ko-fi/support/29abe0c2?cache=300&icon=https://rawcdn.githack.com/tunnckoCore/badgen-icons/f8264c6414e0bec449dd86f2241d50a9b89a1203/icons/kofi.svg
[linux-build-img]: https://badgen.net/github/checks/node-formidable/formidable/master/ubuntu?cache=300&label=linux%20build&icon=github
[macos-build-img]: https://badgen.net/github/checks/node-formidable/formidable/master/macos?cache=300&label=macos%20build&icon=github
[windows-build-img]: https://badgen.net/github/checks/node-formidable/formidable/master/windows?cache=300&label=windows%20build&icon=github
[build-url]: https://github.com/node-formidable/formidable/actions?query=workflow%3Anodejs
<!-- prettier-ignore-end -->

98
node_modules/formidable/package.json generated vendored Normal file
View File

@ -0,0 +1,98 @@
{
"name": "formidable",
"version": "2.0.1",
"license": "MIT",
"description": "A node.js module for parsing form data, especially file uploads.",
"homepage": "https://github.com/node-formidable/formidable",
"funding": "https://ko-fi.com/tunnckoCore/commissions",
"repository": "node-formidable/formidable",
"main": "./src/index.js",
"files": [
"src"
],
"publishConfig": {
"access": "public",
"tag": "v2"
},
"scripts": {
"bench": "node benchmark",
"fmt": "yarn run fmt:prepare '**/*'",
"fmt:prepare": "prettier --write",
"lint": "yarn run lint:prepare .",
"lint:prepare": "eslint --cache --fix --quiet --format codeframe",
"reinstall": "del-cli ./node_modules ./yarn.lock",
"postreinstall": "yarn setup",
"setup": "yarn",
"pretest": "del-cli ./test/tmp && make-dir ./test/tmp",
"test": "jest --coverage",
"pretest:ci": "yarn run pretest",
"test:ci": "nyc jest --coverage",
"test:jest": "jest --coverage"
},
"dependencies": {
"dezalgo": "1.0.3",
"hexoid": "1.0.0",
"once": "1.4.0",
"qs": "6.9.3"
},
"devDependencies": {
"@commitlint/cli": "8.3.5",
"@commitlint/config-conventional": "8.3.4",
"@tunnckocore/prettier-config": "1.3.8",
"del-cli": "3.0.0",
"eslint": "6.8.0",
"eslint-config-airbnb-base": "14.1.0",
"eslint-config-prettier": "6.11.0",
"eslint-plugin-import": "2.20.2",
"eslint-plugin-prettier": "3.1.3",
"express": "4.17.1",
"husky": "4.2.5",
"jest": "25.4.0",
"koa": "2.11.0",
"lint-staged": "10.2.7",
"make-dir-cli": "2.0.0",
"nyc": "15.0.1",
"prettier": "2.0.5",
"prettier-plugin-pkgjson": "0.2.8",
"request": "2.88.2",
"supertest": "4.0.2"
},
"jest": {
"verbose": true
},
"husky": {
"hooks": {
"pre-commit": "git status --porcelain && yarn lint-staged",
"commit-msg": "yarn commitlint -E HUSKY_GIT_PARAMS"
}
},
"commitlint": {
"extends": [
"@commitlint/config-conventional"
]
},
"lint-staged": {
"!*.{js,jsx,ts,tsx}": [
"yarn run fmt:prepare"
],
"*.{js,jsx,ts,tsx}": [
"yarn run lint"
]
},
"renovate": {
"extends": [
"@tunnckocore",
":pinAllExceptPeerDependencies"
]
},
"keywords": [
"multipart",
"form",
"data",
"querystring",
"www",
"json",
"ulpoad",
"file"
]
}

617
node_modules/formidable/src/Formidable.js generated vendored Normal file
View File

@ -0,0 +1,617 @@
/* eslint-disable class-methods-use-this */
/* eslint-disable no-underscore-dangle */
'use strict';
const os = require('os');
const path = require('path');
const hexoid = require('hexoid');
const once = require('once');
const dezalgo = require('dezalgo');
const { EventEmitter } = require('events');
const { StringDecoder } = require('string_decoder');
const qs = require('qs');
const toHexoId = hexoid(25);
const DEFAULT_OPTIONS = {
maxFields: 1000,
maxFieldsSize: 20 * 1024 * 1024,
maxFileSize: 200 * 1024 * 1024,
minFileSize: 1,
allowEmptyFiles: true,
keepExtensions: false,
encoding: 'utf-8',
hashAlgorithm: false,
uploadDir: os.tmpdir(),
multiples: false,
enabledPlugins: ['octetstream', 'querystring', 'multipart', 'json'],
fileWriteStreamHandler: null,
defaultInvalidName: 'invalid-name',
filter: function () {
return true;
},
};
const PersistentFile = require('./PersistentFile');
const VolatileFile = require('./VolatileFile');
const DummyParser = require('./parsers/Dummy');
const MultipartParser = require('./parsers/Multipart');
const errors = require('./FormidableError.js');
const { FormidableError } = errors;
function hasOwnProp(obj, key) {
return Object.prototype.hasOwnProperty.call(obj, key);
}
class IncomingForm extends EventEmitter {
constructor(options = {}) {
super();
this.options = { ...DEFAULT_OPTIONS, ...options };
const dir = path.resolve(
this.options.uploadDir || this.options.uploaddir || os.tmpdir(),
);
this.uploaddir = dir;
this.uploadDir = dir;
// initialize with null
[
'error',
'headers',
'type',
'bytesExpected',
'bytesReceived',
'_parser',
].forEach((key) => {
this[key] = null;
});
this._setUpRename();
this._flushing = 0;
this._fieldsSize = 0;
this._fileSize = 0;
this._plugins = [];
this.openedFiles = [];
this.options.enabledPlugins = []
.concat(this.options.enabledPlugins)
.filter(Boolean);
if (this.options.enabledPlugins.length === 0) {
throw new FormidableError(
'expect at least 1 enabled builtin plugin, see options.enabledPlugins',
errors.missingPlugin,
);
}
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`)));
});
this._setUpMaxFields();
}
use(plugin) {
if (typeof plugin !== 'function') {
throw new FormidableError(
'.use: expect `plugin` to be a function',
errors.pluginFunction,
);
}
this._plugins.push(plugin.bind(this));
return this;
}
parse(req, cb) {
this.pause = () => {
try {
req.pause();
} catch (err) {
// the stream was destroyed
if (!this.ended) {
// before it was completed, crash & burn
this._error(err);
}
return false;
}
return true;
};
this.resume = () => {
try {
req.resume();
} catch (err) {
// the stream was destroyed
if (!this.ended) {
// before it was completed, crash & burn
this._error(err);
}
return false;
}
return true;
};
// Setup callback first, so we don't miss anything from data events emitted immediately.
if (cb) {
const callback = once(dezalgo(cb));
const fields = {};
let mockFields = '';
const files = {};
this.on('field', (name, value) => {
if (
this.options.multiples &&
(this.type === 'multipart' || this.type === 'urlencoded')
) {
const mObj = { [name]: value };
mockFields = mockFields
? `${mockFields}&${qs.stringify(mObj)}`
: `${qs.stringify(mObj)}`;
} else {
fields[name] = value;
}
});
this.on('file', (name, file) => {
// TODO: too much nesting
if (this.options.multiples) {
if (hasOwnProp(files, name)) {
if (!Array.isArray(files[name])) {
files[name] = [files[name]];
}
files[name].push(file);
} else {
files[name] = file;
}
} else {
files[name] = file;
}
});
this.on('error', (err) => {
callback(err, fields, files);
});
this.on('end', () => {
if (this.options.multiples) {
Object.assign(fields, qs.parse(mockFields));
}
callback(null, fields, files);
});
}
// Parse headers and setup the parser, ready to start listening for data.
this.writeHeaders(req.headers);
// Start listening for data.
req
.on('error', (err) => {
this._error(err);
})
.on('aborted', () => {
this.emit('aborted');
this._error(new FormidableError('Request aborted', errors.aborted));
})
.on('data', (buffer) => {
try {
this.write(buffer);
} catch (err) {
this._error(err);
}
})
.on('end', () => {
if (this.error) {
return;
}
if (this._parser) {
this._parser.end();
}
this._maybeEnd();
});
return this;
}
writeHeaders(headers) {
this.headers = headers;
this._parseContentLength();
this._parseContentType();
if (!this._parser) {
this._error(
new FormidableError(
'no parser found',
errors.noParser,
415, // Unsupported Media Type
),
);
return;
}
this._parser.once('error', (error) => {
this._error(error);
});
}
write(buffer) {
if (this.error) {
return null;
}
if (!this._parser) {
this._error(
new FormidableError('uninitialized parser', errors.uninitializedParser),
);
return null;
}
this.bytesReceived += buffer.length;
this.emit('progress', this.bytesReceived, this.bytesExpected);
this._parser.write(buffer);
return this.bytesReceived;
}
pause() {
// this does nothing, unless overwritten in IncomingForm.parse
return false;
}
resume() {
// this does nothing, unless overwritten in IncomingForm.parse
return false;
}
onPart(part) {
// this method can be overwritten by the user
this._handlePart(part);
}
_handlePart(part) {
if (part.originalFilename && typeof part.originalFilename !== 'string') {
this._error(
new FormidableError(
`the part.originalFilename should be string when it exists`,
errors.filenameNotString,
),
);
return;
}
// This MUST check exactly for undefined. You can not change it to !part.originalFilename.
// todo: uncomment when switch tests to Jest
// console.log(part);
// ? NOTE(@tunnckocore): no it can be any falsey value, it most probably depends on what's returned
// from somewhere else. Where recently I changed the return statements
// and such thing because code style
// ? NOTE(@tunnckocore): or even better, if there is no mimetype, then it's for sure a field
// ? NOTE(@tunnckocore): originalFilename is an empty string when a field?
if (!part.mimetype) {
let value = '';
const decoder = new StringDecoder(
part.transferEncoding || this.options.encoding,
);
part.on('data', (buffer) => {
this._fieldsSize += buffer.length;
if (this._fieldsSize > this.options.maxFieldsSize) {
this._error(
new FormidableError(
`options.maxFieldsSize (${this.options.maxFieldsSize} bytes) exceeded, received ${this._fieldsSize} bytes of field data`,
errors.maxFieldsSizeExceeded,
413, // Payload Too Large
),
);
return;
}
value += decoder.write(buffer);
});
part.on('end', () => {
this.emit('field', part.name, value);
});
return;
}
if (!this.options.filter(part)) {
return;
}
this._flushing += 1;
const newFilename = this._getNewName(part);
const filepath = this._joinDirectoryName(newFilename);
const file = this._newFile({
newFilename,
filepath,
originalFilename: part.originalFilename,
mimetype: part.mimetype,
});
file.on('error', (err) => {
this._error(err);
});
this.emit('fileBegin', part.name, file);
file.open();
this.openedFiles.push(file);
part.on('data', (buffer) => {
this._fileSize += buffer.length;
if (this._fileSize < this.options.minFileSize) {
this._error(
new FormidableError(
`options.minFileSize (${this.options.minFileSize} bytes) inferior, received ${this._fileSize} bytes of file data`,
errors.smallerThanMinFileSize,
400,
),
);
return;
}
if (this._fileSize > this.options.maxFileSize) {
this._error(
new FormidableError(
`options.maxFileSize (${this.options.maxFileSize} bytes) exceeded, received ${this._fileSize} bytes of file data`,
errors.biggerThanMaxFileSize,
413,
),
);
return;
}
if (buffer.length === 0) {
return;
}
this.pause();
file.write(buffer, () => {
this.resume();
});
});
part.on('end', () => {
if (!this.options.allowEmptyFiles && this._fileSize === 0) {
this._error(
new FormidableError(
`options.allowEmptyFiles is false, file size should be greather than 0`,
errors.noEmptyFiles,
400,
),
);
return;
}
file.end(() => {
this._flushing -= 1;
this.emit('file', part.name, file);
this._maybeEnd();
});
});
}
// eslint-disable-next-line max-statements
_parseContentType() {
if (this.bytesExpected === 0) {
this._parser = new DummyParser(this, this.options);
return;
}
if (!this.headers['content-type']) {
this._error(
new FormidableError(
'bad content-type header, no content-type',
errors.missingContentType,
400,
),
);
return;
}
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];
let pluginReturn = null;
try {
pluginReturn = plugin(this, this.options) || this;
} catch (err) {
// directly throw from the `form.parse` method;
// there is no other better way, except a handle through options
const error = new FormidableError(
`plugin on index ${idx} failed with: ${err.message}`,
errors.pluginFailed,
500,
);
error.idx = idx;
throw error;
}
Object.assign(this, pluginReturn);
// todo: use Set/Map and pass plugin name instead of the `idx` index
this.emit('plugin', idx, pluginReturn);
results.push(pluginReturn);
}
this.emit('pluginsResults', results);
// NOTE: 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, eventName = 'error') {
// if (!err && this.error) {
// this.emit('error', this.error);
// return;
// }
if (this.error || this.ended) {
return;
}
this.error = err;
this.emit(eventName, err);
if (Array.isArray(this.openedFiles)) {
this.openedFiles.forEach((file) => {
file.destroy();
});
}
}
_parseContentLength() {
this.bytesReceived = 0;
if (this.headers['content-length']) {
this.bytesExpected = parseInt(this.headers['content-length'], 10);
} else if (this.headers['transfer-encoding'] === undefined) {
this.bytesExpected = 0;
}
if (this.bytesExpected !== null) {
this.emit('progress', this.bytesReceived, this.bytesExpected);
}
}
_newParser() {
return new MultipartParser(this.options);
}
_newFile({ filepath, originalFilename, mimetype, newFilename }) {
return this.options.fileWriteStreamHandler
? new VolatileFile({
newFilename,
filepath,
originalFilename,
mimetype,
createFileWriteStream: this.options.fileWriteStreamHandler,
hashAlgorithm: this.options.hashAlgorithm,
})
: new PersistentFile({
newFilename,
filepath,
originalFilename,
mimetype,
hashAlgorithm: this.options.hashAlgorithm,
});
}
_getFileName(headerValue) {
// matches either a quoted-string or a token (RFC 2616 section 19.5.1)
const m = headerValue.match(
/\bfilename=("(.*?)"|([^()<>{}[\]@,;:"?=\s/\t]+))($|;\s)/i,
);
if (!m) return null;
const match = m[2] || m[3] || '';
let originalFilename = match.substr(match.lastIndexOf('\\') + 1);
originalFilename = originalFilename.replace(/%22/g, '"');
originalFilename = originalFilename.replace(/&#([\d]{4});/g, (_, code) =>
String.fromCharCode(code),
);
return originalFilename;
}
_getExtension(str) {
if (!str) {
return '';
}
const basename = path.basename(str);
const firstDot = basename.indexOf('.');
const lastDot = basename.lastIndexOf('.');
const extname = path.extname(basename).replace(/(\.[a-z0-9]+).*/i, '$1');
if (firstDot === lastDot) {
return extname;
}
return basename.slice(firstDot, lastDot) + extname;
}
_joinDirectoryName(name) {
const newPath = path.join(this.uploadDir, name);
// prevent directory traversal attacks
if (!newPath.startsWith(this.uploadDir)) {
return path.join(this.uploadDir, this.options.defaultInvalidName);
}
return newPath;
}
_setUpRename() {
const hasRename = typeof this.options.filename === 'function';
if (hasRename) {
this._getNewName = (part) => {
let ext = '';
let name = this.options.defaultInvalidName;
if (part.originalFilename) {
// can be null
({ ext, name } = path.parse(part.originalFilename));
if (this.options.keepExtensions !== true) {
ext = '';
}
}
return this.options.filename.call(this, name, ext, part, this);
};
} else {
this._getNewName = (part) => {
const name = toHexoId();
if (part && this.options.keepExtensions) {
const originalFilename = typeof part === 'string' ? part : part.originalFilename;
return `${name}${this._getExtension(originalFilename)}`;
}
return name;
}
}
}
_setUpMaxFields() {
if (this.options.maxFields !== 0) {
let fieldsCount = 0;
this.on('field', () => {
fieldsCount += 1;
if (fieldsCount > this.options.maxFields) {
this._error(
new FormidableError(
`options.maxFields (${this.options.maxFields}) exceeded`,
errors.maxFieldsExceeded,
413,
),
);
}
});
}
}
_maybeEnd() {
// console.log('ended', this.ended);
// console.log('_flushing', this._flushing);
// console.log('error', this.error);
if (!this.ended || this._flushing || this.error) {
return;
}
this.emit('end');
}
}
IncomingForm.DEFAULT_OPTIONS = DEFAULT_OPTIONS;
module.exports = IncomingForm;

45
node_modules/formidable/src/FormidableError.js generated vendored Normal file
View File

@ -0,0 +1,45 @@
/* eslint-disable no-plusplus */
const missingPlugin = 1000;
const pluginFunction = 1001;
const aborted = 1002;
const noParser = 1003;
const uninitializedParser = 1004;
const filenameNotString = 1005;
const maxFieldsSizeExceeded = 1006;
const maxFieldsExceeded = 1007;
const smallerThanMinFileSize = 1008;
const biggerThanMaxFileSize = 1009;
const noEmptyFiles = 1010;
const missingContentType = 1011;
const malformedMultipart = 1012;
const missingMultipartBoundary = 1013;
const unknownTransferEncoding = 1014;
const FormidableError = class extends Error {
constructor(message, internalCode, httpCode = 500) {
super(message);
this.code = internalCode;
this.httpCode = httpCode;
}
};
module.exports = {
missingPlugin,
pluginFunction,
aborted,
noParser,
uninitializedParser,
filenameNotString,
maxFieldsSizeExceeded,
maxFieldsExceeded,
smallerThanMinFileSize,
biggerThanMaxFileSize,
noEmptyFiles,
missingContentType,
malformedMultipart,
missingMultipartBoundary,
unknownTransferEncoding,
FormidableError,
};

87
node_modules/formidable/src/PersistentFile.js generated vendored Normal file
View File

@ -0,0 +1,87 @@
/* eslint-disable no-underscore-dangle */
'use strict';
const fs = require('fs');
const crypto = require('crypto');
const { EventEmitter } = require('events');
class PersistentFile extends EventEmitter {
constructor({ filepath, newFilename, originalFilename, mimetype, hashAlgorithm }) {
super();
this.lastModifiedDate = null;
Object.assign(this, { filepath, newFilename, originalFilename, mimetype, hashAlgorithm });
this.size = 0;
this._writeStream = null;
if (typeof this.hashAlgorithm === 'string') {
this.hash = crypto.createHash(this.hashAlgorithm);
} else {
this.hash = null;
}
}
open() {
this._writeStream = new fs.WriteStream(this.filepath);
this._writeStream.on('error', (err) => {
this.emit('error', err);
});
}
toJSON() {
const json = {
size: this.size,
filepath: this.filepath,
newFilename: this.newFilename,
mimetype: this.mimetype,
mtime: this.lastModifiedDate,
length: this.length,
originalFilename: this.originalFilename,
};
if (this.hash && this.hash !== '') {
json.hash = this.hash;
}
return json;
}
toString() {
return `PersistentFile: ${this._file.newFilename}, Original: ${this._file.originalFilename}, Path: ${this._file.filepath}`;
}
write(buffer, cb) {
if (this.hash) {
this.hash.update(buffer);
}
if (this._writeStream.closed) {
cb();
return;
}
this._writeStream.write(buffer, () => {
this.lastModifiedDate = new Date();
this.size += buffer.length;
this.emit('progress', this.size);
cb();
});
}
end(cb) {
if (this.hash) {
this.hash = this.hash.digest('hex');
}
this._writeStream.end(() => {
this.emit('end');
cb();
});
}
destroy() {
this._writeStream.destroy();
fs.unlink(this.filepath, () => {});
}
}
module.exports = PersistentFile;

82
node_modules/formidable/src/VolatileFile.js generated vendored Normal file
View File

@ -0,0 +1,82 @@
/* eslint-disable no-underscore-dangle */
'use strict';
const crypto = require('crypto');
const { EventEmitter } = require('events');
class VolatileFile extends EventEmitter {
constructor({ filepath, newFilename, originalFilename, mimetype, hashAlgorithm, createFileWriteStream }) {
super();
this.lastModifiedDate = null;
Object.assign(this, { filepath, newFilename, originalFilename, mimetype, hashAlgorithm, createFileWriteStream });
this.size = 0;
this._writeStream = null;
if (typeof this.hashAlgorithm === 'string') {
this.hash = crypto.createHash(this.hashAlgorithm);
} else {
this.hash = null;
}
}
open() {
this._writeStream = this.createFileWriteStream(this);
this._writeStream.on('error', (err) => {
this.emit('error', err);
});
}
destroy() {
this._writeStream.destroy();
}
toJSON() {
const json = {
size: this.size,
newFilename: this.newFilename,
length: this.length,
originalFilename: this.originalFilename,
mimetype: this.mimetype,
};
if (this.hash && this.hash !== '') {
json.hash = this.hash;
}
return json;
}
toString() {
return `VolatileFile: ${this.originalFilename}`;
}
write(buffer, cb) {
if (this.hash) {
this.hash.update(buffer);
}
if (this._writeStream.closed || this._writeStream.destroyed) {
cb();
return;
}
this._writeStream.write(buffer, () => {
this.size += buffer.length;
this.emit('progress', this.size);
cb();
});
}
end(cb) {
if (this.hash) {
this.hash = this.hash.digest('hex');
}
this._writeStream.end(() => {
this.emit('end');
cb();
});
}
}
module.exports = VolatileFile;

38
node_modules/formidable/src/index.js generated vendored Normal file
View File

@ -0,0 +1,38 @@
'use strict';
const PersistentFile = require('./PersistentFile');
const VolatileFile = require('./VolatileFile');
const Formidable = require('./Formidable');
const FormidableError = require('./FormidableError');
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
const formidable = (...args) => new Formidable(...args);
module.exports = Object.assign(formidable, {
errors: FormidableError,
File: PersistentFile,
PersistentFile,
VolatileFile,
Formidable,
formidable,
// alias
IncomingForm: Formidable,
// parsers
...parsers,
parsers,
// misc
defaultOptions: Formidable.DEFAULT_OPTIONS,
enabledPlugins: Formidable.DEFAULT_OPTIONS.enabledPlugins,
// plugins
plugins: {
...plugins,
},
});

21
node_modules/formidable/src/parsers/Dummy.js generated vendored Normal file
View File

@ -0,0 +1,21 @@
/* eslint-disable no-underscore-dangle */
'use strict';
const { Transform } = require('stream');
class DummyParser extends Transform {
constructor(incomingForm, options = {}) {
super();
this.globalOptions = { ...options };
this.incomingForm = incomingForm;
}
_flush(callback) {
this.incomingForm.ended = true;
this.incomingForm._maybeEnd();
callback();
}
}
module.exports = DummyParser;

35
node_modules/formidable/src/parsers/JSON.js generated vendored Normal file
View File

@ -0,0 +1,35 @@
/* eslint-disable no-underscore-dangle */
'use strict';
const { Transform } = require('stream');
class JSONParser extends Transform {
constructor(options = {}) {
super({ readableObjectMode: true });
this.chunks = [];
this.globalOptions = { ...options };
}
_transform(chunk, encoding, callback) {
this.chunks.push(String(chunk)); // todo consider using a string decoder
callback();
}
_flush(callback) {
try {
const fields = JSON.parse(this.chunks.join(''));
Object.keys(fields).forEach((key) => {
const value = fields[key];
this.push({ key, value });
});
} catch (e) {
callback(e);
return;
}
this.chunks = null;
callback();
}
}
module.exports = JSONParser;

347
node_modules/formidable/src/parsers/Multipart.js generated vendored Normal file
View File

@ -0,0 +1,347 @@
/* eslint-disable no-fallthrough */
/* eslint-disable no-bitwise */
/* eslint-disable no-plusplus */
/* eslint-disable no-underscore-dangle */
'use strict';
const { Transform } = require('stream');
const errors = require('../FormidableError.js');
const { FormidableError } = errors;
let s = 0;
const STATE = {
PARSER_UNINITIALIZED: s++,
START: s++,
START_BOUNDARY: s++,
HEADER_FIELD_START: s++,
HEADER_FIELD: s++,
HEADER_VALUE_START: s++,
HEADER_VALUE: s++,
HEADER_VALUE_ALMOST_DONE: s++,
HEADERS_ALMOST_DONE: s++,
PART_DATA_START: s++,
PART_DATA: s++,
PART_END: s++,
END: s++,
};
let f = 1;
const FBOUNDARY = { PART_BOUNDARY: f, LAST_BOUNDARY: (f *= 2) };
const LF = 10;
const CR = 13;
const SPACE = 32;
const HYPHEN = 45;
const COLON = 58;
const A = 97;
const Z = 122;
function lower(c) {
return c | 0x20;
}
exports.STATES = {};
Object.keys(STATE).forEach((stateName) => {
exports.STATES[stateName] = STATE[stateName];
});
class MultipartParser extends Transform {
constructor(options = {}) {
super({ readableObjectMode: true });
this.boundary = null;
this.boundaryChars = null;
this.lookbehind = null;
this.bufferLength = 0;
this.state = STATE.PARSER_UNINITIALIZED;
this.globalOptions = { ...options };
this.index = null;
this.flags = 0;
}
_flush(done) {
if (
(this.state === STATE.HEADER_FIELD_START && this.index === 0) ||
(this.state === STATE.PART_DATA && this.index === this.boundary.length)
) {
this._handleCallback('partEnd');
this._handleCallback('end');
done();
} else if (this.state !== STATE.END) {
done(
new FormidableError(
`MultipartParser.end(): stream ended unexpectedly: ${this.explain()}`,
errors.malformedMultipart,
400,
),
);
}
}
initWithBoundary(str) {
this.boundary = Buffer.from(`\r\n--${str}`);
this.lookbehind = Buffer.alloc(this.boundary.length + 8);
this.state = STATE.START;
this.boundaryChars = {};
for (let i = 0; i < this.boundary.length; i++) {
this.boundaryChars[this.boundary[i]] = true;
}
}
// eslint-disable-next-line max-params
_handleCallback(name, buf, start, end) {
if (start !== undefined && start === end) {
return;
}
this.push({ name, buffer: buf, start, end });
}
// eslint-disable-next-line max-statements
_transform(buffer, _, done) {
let i = 0;
let prevIndex = this.index;
let { index, state, flags } = this;
const { lookbehind, boundary, boundaryChars } = this;
const boundaryLength = boundary.length;
const boundaryEnd = boundaryLength - 1;
this.bufferLength = buffer.length;
let c = null;
let cl = null;
const setMark = (name, idx) => {
this[`${name}Mark`] = typeof idx === 'number' ? idx : i;
};
const clearMarkSymbol = (name) => {
delete this[`${name}Mark`];
};
const dataCallback = (name, shouldClear) => {
const markSymbol = `${name}Mark`;
if (!(markSymbol in this)) {
return;
}
if (!shouldClear) {
this._handleCallback(name, buffer, this[markSymbol], buffer.length);
setMark(name, 0);
} else {
this._handleCallback(name, buffer, this[markSymbol], i);
clearMarkSymbol(name);
}
};
for (i = 0; i < this.bufferLength; i++) {
c = buffer[i];
switch (state) {
case STATE.PARSER_UNINITIALIZED:
return i;
case STATE.START:
index = 0;
state = STATE.START_BOUNDARY;
case STATE.START_BOUNDARY:
if (index === boundary.length - 2) {
if (c === HYPHEN) {
flags |= FBOUNDARY.LAST_BOUNDARY;
} else if (c !== CR) {
return i;
}
index++;
break;
} else if (index - 1 === boundary.length - 2) {
if (flags & FBOUNDARY.LAST_BOUNDARY && c === HYPHEN) {
this._handleCallback('end');
state = STATE.END;
flags = 0;
} else if (!(flags & FBOUNDARY.LAST_BOUNDARY) && c === LF) {
index = 0;
this._handleCallback('partBegin');
state = STATE.HEADER_FIELD_START;
} else {
return i;
}
break;
}
if (c !== boundary[index + 2]) {
index = -2;
}
if (c === boundary[index + 2]) {
index++;
}
break;
case STATE.HEADER_FIELD_START:
state = STATE.HEADER_FIELD;
setMark('headerField');
index = 0;
case STATE.HEADER_FIELD:
if (c === CR) {
clearMarkSymbol('headerField');
state = STATE.HEADERS_ALMOST_DONE;
break;
}
index++;
if (c === HYPHEN) {
break;
}
if (c === COLON) {
if (index === 1) {
// empty header field
return i;
}
dataCallback('headerField', true);
state = STATE.HEADER_VALUE_START;
break;
}
cl = lower(c);
if (cl < A || cl > Z) {
return i;
}
break;
case STATE.HEADER_VALUE_START:
if (c === SPACE) {
break;
}
setMark('headerValue');
state = STATE.HEADER_VALUE;
case STATE.HEADER_VALUE:
if (c === CR) {
dataCallback('headerValue', true);
this._handleCallback('headerEnd');
state = STATE.HEADER_VALUE_ALMOST_DONE;
}
break;
case STATE.HEADER_VALUE_ALMOST_DONE:
if (c !== LF) {
return i;
}
state = STATE.HEADER_FIELD_START;
break;
case STATE.HEADERS_ALMOST_DONE:
if (c !== LF) {
return i;
}
this._handleCallback('headersEnd');
state = STATE.PART_DATA_START;
break;
case STATE.PART_DATA_START:
state = STATE.PART_DATA;
setMark('partData');
case STATE.PART_DATA:
prevIndex = index;
if (index === 0) {
// boyer-moore derrived algorithm to safely skip non-boundary data
i += boundaryEnd;
while (i < this.bufferLength && !(buffer[i] in boundaryChars)) {
i += boundaryLength;
}
i -= boundaryEnd;
c = buffer[i];
}
if (index < boundary.length) {
if (boundary[index] === c) {
if (index === 0) {
dataCallback('partData', true);
}
index++;
} else {
index = 0;
}
} else if (index === boundary.length) {
index++;
if (c === CR) {
// CR = part boundary
flags |= FBOUNDARY.PART_BOUNDARY;
} else if (c === HYPHEN) {
// HYPHEN = end boundary
flags |= FBOUNDARY.LAST_BOUNDARY;
} else {
index = 0;
}
} else if (index - 1 === boundary.length) {
if (flags & FBOUNDARY.PART_BOUNDARY) {
index = 0;
if (c === LF) {
// unset the PART_BOUNDARY flag
flags &= ~FBOUNDARY.PART_BOUNDARY;
this._handleCallback('partEnd');
this._handleCallback('partBegin');
state = STATE.HEADER_FIELD_START;
break;
}
} else if (flags & FBOUNDARY.LAST_BOUNDARY) {
if (c === HYPHEN) {
this._handleCallback('partEnd');
this._handleCallback('end');
state = STATE.END;
flags = 0;
} else {
index = 0;
}
} else {
index = 0;
}
}
if (index > 0) {
// when matching a possible boundary, keep a lookbehind reference
// in case it turns out to be a false lead
lookbehind[index - 1] = c;
} else if (prevIndex > 0) {
// if our boundary turned out to be rubbish, the captured lookbehind
// belongs to partData
this._handleCallback('partData', lookbehind, 0, prevIndex);
prevIndex = 0;
setMark('partData');
// reconsider the current character even so it interrupted the sequence
// it could be the beginning of a new sequence
i--;
}
break;
case STATE.END:
break;
default:
return i;
}
}
dataCallback('headerField');
dataCallback('headerValue');
dataCallback('partData');
this.index = index;
this.state = state;
this.flags = flags;
done();
return this.bufferLength;
}
explain() {
return `state = ${MultipartParser.stateToString(this.state)}`;
}
}
// eslint-disable-next-line consistent-return
MultipartParser.stateToString = (stateNumber) => {
// eslint-disable-next-line no-restricted-syntax, guard-for-in
for (const stateName in STATE) {
const number = STATE[stateName];
if (number === stateNumber) return stateName;
}
};
module.exports = Object.assign(MultipartParser, { STATES: exports.STATES });

12
node_modules/formidable/src/parsers/OctetStream.js generated vendored Normal file
View File

@ -0,0 +1,12 @@
'use strict';
const { PassThrough } = require('stream');
class OctetStreamParser extends PassThrough {
constructor(options = {}) {
super();
this.globalOptions = { ...options };
}
}
module.exports = OctetStreamParser;

38
node_modules/formidable/src/parsers/Querystring.js generated vendored Normal file
View File

@ -0,0 +1,38 @@
/* eslint-disable no-underscore-dangle */
'use strict';
const { Transform } = require('stream');
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(options = {}) {
super({ readableObjectMode: true });
this.globalOptions = { ...options };
this.buffer = '';
this.bufferLength = 0;
}
_transform(buffer, encoding, callback) {
this.buffer += buffer.toString('ascii');
this.bufferLength = this.buffer.length;
callback();
}
_flush(callback) {
const fields = querystring.parse(this.buffer, '&', '=');
// eslint-disable-next-line no-restricted-syntax, guard-for-in
for (const key in fields) {
this.push({
key,
value: fields[key],
});
}
this.buffer = '';
callback();
}
}
module.exports = QuerystringParser;

View File

@ -0,0 +1,121 @@
// not used
/* eslint-disable no-underscore-dangle */
'use strict';
const { Transform } = require('stream');
const errors = require('../FormidableError.js');
const { FormidableError } = errors;
const AMPERSAND = 38;
const EQUALS = 61;
class QuerystringParser extends Transform {
constructor(options = {}) {
super({ readableObjectMode: true });
const { maxFieldSize } = options;
this.maxFieldLength = maxFieldSize;
this.buffer = Buffer.from('');
this.fieldCount = 0;
this.sectionStart = 0;
this.key = '';
this.readingKey = true;
}
_transform(buffer, encoding, callback) {
let len = buffer.length;
if (this.buffer && this.buffer.length) {
// we have some data left over from the last write which we are in the middle of processing
len += this.buffer.length;
buffer = Buffer.concat([this.buffer, buffer], len);
}
for (let i = this.buffer.length || 0; i < len; i += 1) {
const c = buffer[i];
if (this.readingKey) {
// KEY, check for =
if (c === EQUALS) {
this.key = this.getSection(buffer, i);
this.readingKey = false;
this.sectionStart = i + 1;
} else if (c === AMPERSAND) {
// just key, no value. Prepare to read another key
this.emitField(this.getSection(buffer, i));
this.sectionStart = i + 1;
}
// VALUE, check for &
} else if (c === AMPERSAND) {
this.emitField(this.key, this.getSection(buffer, i));
this.sectionStart = i + 1;
}
if (
this.maxFieldLength &&
i - this.sectionStart === this.maxFieldLength
) {
callback(
new FormidableError(
`${
this.readingKey ? 'Key' : `Value for ${this.key}`
} longer than maxFieldLength`,
),
errors.maxFieldsSizeExceeded,
413,
);
}
}
// Prepare the remaining key or value (from sectionStart to the end) for the next write() or for end()
len -= this.sectionStart;
if (len) {
// i.e. Unless the last character was a & or =
this.buffer = Buffer.from(this.buffer, 0, this.sectionStart);
} else this.buffer = null;
this.sectionStart = 0;
callback();
}
_flush(callback) {
// Emit the last field
if (this.readingKey) {
// we only have a key if there's something in the buffer. We definitely have no value
if (this.buffer && this.buffer.length){
this.emitField(this.buffer.toString('ascii'));
}
} else {
// We have a key, we may or may not have a value
this.emitField(
this.key,
this.buffer && this.buffer.length && this.buffer.toString('ascii'),
);
}
this.buffer = '';
callback();
}
getSection(buffer, i) {
if (i === this.sectionStart) return '';
return buffer.toString('ascii', this.sectionStart, i);
}
emitField(key, val) {
this.key = '';
this.readingKey = true;
this.push({ key, value: val || '' });
}
}
module.exports = QuerystringParser;
// const q = new QuerystringParser({maxFieldSize: 100});
// (async function() {
// for await (const chunk of q) {
// console.log(chunk);
// }
// })();
// q.write("a=b&c=d")
// q.end()

17
node_modules/formidable/src/parsers/index.js generated vendored Normal file
View File

@ -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,
});

13
node_modules/formidable/src/plugins/index.js generated vendored Normal file
View File

@ -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,
});

38
node_modules/formidable/src/plugins/json.js generated vendored Normal file
View File

@ -0,0 +1,38 @@
/* 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
/* istanbul ignore next */
const self = this || formidable;
if (/json/i.test(self.headers['content-type'])) {
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 init(_self, _opts) {
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;
}

173
node_modules/formidable/src/plugins/multipart.js generated vendored Normal file
View File

@ -0,0 +1,173 @@
/* eslint-disable no-underscore-dangle */
'use strict';
const { Stream } = require('stream');
const MultipartParser = require('../parsers/Multipart');
const errors = require('../FormidableError.js');
const { FormidableError } = errors;
// 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
/* istanbul ignore next */
const self = this || formidable;
// 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,
);
if (m) {
const initMultipart = createInitMultipart(m[1] || m[2]);
initMultipart.call(self, self, options); // lgtm [js/superfluous-trailing-arguments]
} else {
const err = new FormidableError(
'bad content-type header, no multipart boundary',
errors.missingMultipartBoundary,
400,
);
self._error(err);
}
}
};
// 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.originalFilename = null;
part.mimetype = null;
part.transferEncoding = this.options.encoding;
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.originalFilename = this._getFileName(headerValue);
} else if (headerField === 'content-type') {
part.mimetype = 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':
case 'utf-8': {
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 FormidableError(
'unknown transfer-encoding',
errors.unknownTransferEncoding,
501,
),
);
}
this.onPart(part);
} else if (name === 'end') {
this.ended = true;
this._maybeEnd();
}
});
this._parser = parser;
};
}

86
node_modules/formidable/src/plugins/octetstream.js generated vendored Normal file
View File

@ -0,0 +1,86 @@
/* eslint-disable no-underscore-dangle */
'use strict';
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
/* istanbul ignore next */
const self = this || formidable;
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
// 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 init(_self, _opts) {
this.type = 'octet-stream';
const originalFilename = this.headers['x-file-name'];
const mimetype = this.headers['content-type'];
const thisPart = {
originalFilename,
mimetype,
};
const newFilename = this._getNewName(thisPart);
const filepath = this._joinDirectoryName(newFilename);
const file = this._newFile({
newFilename,
filepath,
originalFilename,
mimetype,
});
this.emit('fileBegin', originalFilename, 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);
}
});
return this;
}

42
node_modules/formidable/src/plugins/querystring.js generated vendored Normal file
View File

@ -0,0 +1,42 @@
/* 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
/* istanbul ignore next */
const self = this || formidable;
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
// 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 init(_self, _opts) {
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;
return this;
}

9
node_modules/fs/README.md generated vendored Normal file
View File

@ -0,0 +1,9 @@
# Security holding package
This package name is not currently in use, but was formerly occupied
by another package. To avoid malicious use, npm is hanging on to the
package name, but loosely, and we'll probably give it to you if you
want it.
You may adopt this package by contacting support@npmjs.com and
requesting the name.

20
node_modules/fs/package.json generated vendored Normal file
View File

@ -0,0 +1,20 @@
{
"name": "fs",
"version": "0.0.1-security",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/npm/security-holder.git"
},
"keywords": [],
"author": "",
"license": "ISC",
"bugs": {
"url": "https://github.com/npm/security-holder/issues"
},
"homepage": "https://github.com/npm/security-holder#readme"
}

15
node_modules/hexoid/dist/index.js generated vendored Normal file
View File

@ -0,0 +1,15 @@
var IDX=256, HEX=[];
while (IDX--) HEX[IDX] = (IDX + 256).toString(16).substring(1);
module.exports = function (len) {
len = len || 16;
var str='', num=0;
return function () {
if (!str || num === 256) {
str=''; num=(1+len)/2 | 0;
while (num--) str += HEX[256 * Math.random() | 0];
str = str.substring(num=0, len-2);
}
return str + HEX[num++];
};
}

1
node_modules/hexoid/dist/index.min.js generated vendored Normal file
View File

@ -0,0 +1 @@
!function(n,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):n.hexoid=e()}(this,(function(){for(var n=256,e=[];n--;)e[n]=(n+256).toString(16).substring(1);return function(n){n=n||16;var t="",o=0;return function(){if(!t||256===o){for(t="",o=(1+n)/2|0;o--;)t+=e[256*Math.random()|0];t=t.substring(o=0,n-2)}return t+e[o++]}}}));

15
node_modules/hexoid/dist/index.mjs generated vendored Normal file
View File

@ -0,0 +1,15 @@
var IDX=256, HEX=[];
while (IDX--) HEX[IDX] = (IDX + 256).toString(16).substring(1);
export default function (len) {
len = len || 16;
var str='', num=0;
return function () {
if (!str || num === 256) {
str=''; num=(1+len)/2 | 0;
while (num--) str += HEX[256 * Math.random() | 0];
str = str.substring(num=0, len-2);
}
return str + HEX[num++];
};
}

1
node_modules/hexoid/hexoid.d.ts generated vendored Normal file
View File

@ -0,0 +1 @@
export default function (len?: number): () => string;

9
node_modules/hexoid/license generated vendored Normal file
View File

@ -0,0 +1,9 @@
MIT License
Copyright (c) Luke Edwards <luke.edwards05@gmail.com> (lukeed.com)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

41
node_modules/hexoid/package.json generated vendored Normal file
View File

@ -0,0 +1,41 @@
{
"name": "hexoid",
"version": "1.0.0",
"repository": "lukeed/hexoid",
"description": "A tiny (190B) and extremely fast utility to generate random IDs of fixed length",
"unpkg": "dist/index.min.js",
"module": "dist/index.mjs",
"main": "dist/index.js",
"types": "hexoid.d.ts",
"license": "MIT",
"author": {
"name": "Luke Edwards",
"email": "luke.edwards05@gmail.com",
"url": "https://lukeed.com"
},
"engines": {
"node": ">=8"
},
"scripts": {
"build": "bundt",
"pretest": "npm run build",
"test": "tape -r esm test/*.js | tap-spec"
},
"files": [
"*.d.ts",
"dist"
],
"keywords": [
"id",
"uid",
"uuid",
"random",
"generate"
],
"devDependencies": {
"bundt": "1.0.0",
"esm": "3.2.25",
"tap-spec": "5.0.0",
"tape": "4.9.1"
}
}

119
node_modules/hexoid/readme.md generated vendored Normal file
View File

@ -0,0 +1,119 @@
# hexoid [![build status](https://badgen.net/github/status/lukeed/hexoid)](https://github.com/lukeed/hexoid/actions) [![codecov](https://badgen.now.sh/codecov/c/github/lukeed/hexoid)](https://codecov.io/gh/lukeed/hexoid)
> A tiny (190B) and [extremely fast](#benchmarks) utility to generate random IDs of fixed length
_**Hexadecimal object IDs.** Available for Node.js and the browser._<br>Generate randomized output strings of fixed length using lowercased hexadecimal pairs.
> **Notice:** Please note that this is not a cryptographically secure (CSPRNG) generator.
Additionally, this module is delivered as:
* **CommonJS**: [`dist/index.js`](https://unpkg.com/hexoid/dist/index.js)
* **ES Module**: [`dist/index.mjs`](https://unpkg.com/hexoid/dist/index.mjs)
* **UMD**: [`dist/index.min.js`](https://unpkg.com/hexoid/dist/index.min.js)
## Install
```
$ npm install --save hexoid
```
## Usage
```js
import hexoid from 'hexoid';
const toID = hexoid();
// length = 16 (default)
toID(); //=> '52032fedb951da00'
toID(); //=> '52032fedb951da01'
toID(); //=> '52032fedb951da02'
// customize length
hexoid(25)(); //=> '065359875047c63a037200e00'
hexoid(32)(); //=> 'ca8e4aec7f139d94fcab9cab2eb89f00'
hexoid(48)(); //=> 'c19a4deb5cdeca68534930e67bd0a2f4ed45988724d8d200'
```
## API
### hexoid(length?)
Returns: `() => string`
Creates the function that will generate strings.
#### length
Type: `Number`<br>
Default: `16`
Then length of the output string.
> **Important:** Your risk of collisions decreases with longer strings!<br>Please be aware of the [Birthday Problem](https://betterexplained.com/articles/understanding-the-birthday-paradox/)! You may need more combinations than you'd expect.
The **maximum combinations** are known given the following formula:
```js
const combos = 256 ** (len/2);
```
## Benchmarks
> Running on Node.js v10.13.0
```
Validation (length = 16):
✔ hashids/fixed (example: "LkQWjnegYbwZ1p0G")
✔ nanoid/non-secure (example: "sLlVL5X3M5k2fo58")
✔ uid (example: "3d0ckwcnjiuu91hj")
✔ hexoid (example: "de96b62e663ef300")
Benchmark (length = 16):
hashids/fixed x 349,462 ops/sec ±0.28% (93 runs sampled)
nanoid/non-secure x 3,337,573 ops/sec ±0.28% (96 runs sampled)
uid x 3,553,482 ops/sec ±0.51% (90 runs sampled)
hexoid x 81,081,364 ops/sec ±0.18% (96 runs sampled)
Validation (length = 25):
✔ cuid (example: "ck7lj5hbf00000v7c9gox6yfh")
✔ hashids/fixed (example: "r9JOyLkQWjnegYbwZ1p0GDXNm")
✔ nanoid/non-secure (example: "hI202PVPJQRNrP6o6z4pXz4m0")
✔ uid (example: "9904e9w130buxaw7n8358mn2f")
✔ hexoid (example: "01dfab2c14e37768eb7605a00")
Benchmark (length = 25):
cuid x 161,636 ops/sec ±1.36% (89 runs sampled)
hashids/fixed x 335,439 ops/sec ±2.40% (94 runs sampled)
nanoid/non-secure x 2,254,073 ops/sec ±0.23% (96 runs sampled)
uid x 2,483,275 ops/sec ±0.38% (95 runs sampled)
hexoid x 75,715,843 ops/sec ±0.27% (95 runs sampled)
Validation (length = 36):
✔ uuid/v1 (example: "c3dc1ed0-629a-11ea-8bfb-8ffc49585f54")
✔ uuid/v4 (example: "8c89f0ca-f01e-4c84-bd71-e645bab84552")
✔ hashids/fixed (example: "EVq3Pr9JOyLkQWjnegYbwZ1p0GDXNmRBlAxg")
@lukeed/uuid (example: "069ad676-48f9-4452-b11d-f20c3872dc1f")
✔ nanoid/non-secure (example: "jAZjrcDmHH6P1rT9EFdCdHUpF440SjAKwb2A")
✔ uid (example: "5mhi30lgy5d0glmuy81llelbzdko518ow1sx")
✔ hexoid (example: "615209331f0b4630acf69999ccfc95a23200")
Benchmark (length = 36):
uuid/v1 x 1,487,947 ops/sec ±0.18% (98 runs sampled)
uuid/v4 x 334,868 ops/sec ±1.08% (90 runs sampled)
@lukeed/uuid x 6,352,445 ops/sec ±0.27% (91 runs sampled)
hashids/fixed x 322,914 ops/sec ±0.27% (93 runs sampled)
nanoid/non-secure x 1,592,708 ops/sec ±0.25% (91 runs sampled)
uid x 1,789,492 ops/sec ±0.29% (92 runs sampled)
hexoid x 71,746,692 ops/sec ±0.29% (93 runs sampled)
```
## Related
- [uid](https://github.com/lukeed/uid) - A smaller (134B) but slower variant of this module with a different API
- [@lukeed/uuid](https://github.com/lukeed/uuid) - A tiny (230B), fast, and cryptographically secure UUID (V4) generator for Node and the browser
## License
MIT © [Luke Edwards](https://lukeed.com)

88
node_modules/on-finished/HISTORY.md generated vendored Normal file
View File

@ -0,0 +1,88 @@
2.3.0 / 2015-05-26
==================
* Add defined behavior for HTTP `CONNECT` requests
* Add defined behavior for HTTP `Upgrade` requests
* deps: ee-first@1.1.1
2.2.1 / 2015-04-22
==================
* Fix `isFinished(req)` when data buffered
2.2.0 / 2014-12-22
==================
* Add message object to callback arguments
2.1.1 / 2014-10-22
==================
* Fix handling of pipelined requests
2.1.0 / 2014-08-16
==================
* Check if `socket` is detached
* Return `undefined` for `isFinished` if state unknown
2.0.0 / 2014-08-16
==================
* Add `isFinished` function
* Move to `jshttp` organization
* Remove support for plain socket argument
* Rename to `on-finished`
* Support both `req` and `res` as arguments
* deps: ee-first@1.0.5
1.2.2 / 2014-06-10
==================
* Reduce listeners added to emitters
- avoids "event emitter leak" warnings when used multiple times on same request
1.2.1 / 2014-06-08
==================
* Fix returned value when already finished
1.2.0 / 2014-06-05
==================
* Call callback when called on already-finished socket
1.1.4 / 2014-05-27
==================
* Support node.js 0.8
1.1.3 / 2014-04-30
==================
* Make sure errors passed as instanceof `Error`
1.1.2 / 2014-04-18
==================
* Default the `socket` to passed-in object
1.1.1 / 2014-01-16
==================
* Rename module to `finished`
1.1.0 / 2013-12-25
==================
* Call callback when called on already-errored socket
1.0.1 / 2013-12-20
==================
* Actually pass the error to the callback
1.0.0 / 2013-12-20
==================
* Initial release

23
node_modules/on-finished/LICENSE generated vendored Normal file
View File

@ -0,0 +1,23 @@
(The MIT License)
Copyright (c) 2013 Jonathan Ong <me@jongleberry.com>
Copyright (c) 2014 Douglas Christopher Wilson <doug@somethingdoug.com>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

154
node_modules/on-finished/README.md generated vendored Normal file
View File

@ -0,0 +1,154 @@
# on-finished
[![NPM Version][npm-image]][npm-url]
[![NPM Downloads][downloads-image]][downloads-url]
[![Node.js Version][node-version-image]][node-version-url]
[![Build Status][travis-image]][travis-url]
[![Test Coverage][coveralls-image]][coveralls-url]
Execute a callback when a HTTP request closes, finishes, or errors.
## Install
```sh
$ npm install on-finished
```
## API
```js
var onFinished = require('on-finished')
```
### onFinished(res, listener)
Attach a listener to listen for the response to finish. The listener will
be invoked only once when the response finished. If the response finished
to an error, the first argument will contain the error. If the response
has already finished, the listener will be invoked.
Listening to the end of a response would be used to close things associated
with the response, like open files.
Listener is invoked as `listener(err, res)`.
```js
onFinished(res, function (err, res) {
// clean up open fds, etc.
// err contains the error is request error'd
})
```
### onFinished(req, listener)
Attach a listener to listen for the request to finish. The listener will
be invoked only once when the request finished. If the request finished
to an error, the first argument will contain the error. If the request
has already finished, the listener will be invoked.
Listening to the end of a request would be used to know when to continue
after reading the data.
Listener is invoked as `listener(err, req)`.
```js
var data = ''
req.setEncoding('utf8')
res.on('data', function (str) {
data += str
})
onFinished(req, function (err, req) {
// data is read unless there is err
})
```
### onFinished.isFinished(res)
Determine if `res` is already finished. This would be useful to check and
not even start certain operations if the response has already finished.
### onFinished.isFinished(req)
Determine if `req` is already finished. This would be useful to check and
not even start certain operations if the request has already finished.
## Special Node.js requests
### HTTP CONNECT method
The meaning of the `CONNECT` method from RFC 7231, section 4.3.6:
> The CONNECT method requests that the recipient establish a tunnel to
> the destination origin server identified by the request-target and,
> if successful, thereafter restrict its behavior to blind forwarding
> of packets, in both directions, until the tunnel is closed. Tunnels
> are commonly used to create an end-to-end virtual connection, through
> one or more proxies, which can then be secured using TLS (Transport
> Layer Security, [RFC5246]).
In Node.js, these request objects come from the `'connect'` event on
the HTTP server.
When this module is used on a HTTP `CONNECT` request, the request is
considered "finished" immediately, **due to limitations in the Node.js
interface**. This means if the `CONNECT` request contains a request entity,
the request will be considered "finished" even before it has been read.
There is no such thing as a response object to a `CONNECT` request in
Node.js, so there is no support for for one.
### HTTP Upgrade request
The meaning of the `Upgrade` header from RFC 7230, section 6.1:
> The "Upgrade" header field is intended to provide a simple mechanism
> for transitioning from HTTP/1.1 to some other protocol on the same
> connection.
In Node.js, these request objects come from the `'upgrade'` event on
the HTTP server.
When this module is used on a HTTP request with an `Upgrade` header, the
request is considered "finished" immediately, **due to limitations in the
Node.js interface**. This means if the `Upgrade` request contains a request
entity, the request will be considered "finished" even before it has been
read.
There is no such thing as a response object to a `Upgrade` request in
Node.js, so there is no support for for one.
## Example
The following code ensures that file descriptors are always closed
once the response finishes.
```js
var destroy = require('destroy')
var http = require('http')
var onFinished = require('on-finished')
http.createServer(function onRequest(req, res) {
var stream = fs.createReadStream('package.json')
stream.pipe(res)
onFinished(res, function (err) {
destroy(stream)
})
})
```
## License
[MIT](LICENSE)
[npm-image]: https://img.shields.io/npm/v/on-finished.svg
[npm-url]: https://npmjs.org/package/on-finished
[node-version-image]: https://img.shields.io/node/v/on-finished.svg
[node-version-url]: http://nodejs.org/download/
[travis-image]: https://img.shields.io/travis/jshttp/on-finished/master.svg
[travis-url]: https://travis-ci.org/jshttp/on-finished
[coveralls-image]: https://img.shields.io/coveralls/jshttp/on-finished/master.svg
[coveralls-url]: https://coveralls.io/r/jshttp/on-finished?branch=master
[downloads-image]: https://img.shields.io/npm/dm/on-finished.svg
[downloads-url]: https://npmjs.org/package/on-finished

196
node_modules/on-finished/index.js generated vendored Normal file
View File

@ -0,0 +1,196 @@
/*!
* on-finished
* Copyright(c) 2013 Jonathan Ong
* Copyright(c) 2014 Douglas Christopher Wilson
* MIT Licensed
*/
'use strict'
/**
* Module exports.
* @public
*/
module.exports = onFinished
module.exports.isFinished = isFinished
/**
* Module dependencies.
* @private
*/
var first = require('ee-first')
/**
* Variables.
* @private
*/
/* istanbul ignore next */
var defer = typeof setImmediate === 'function'
? setImmediate
: function(fn){ process.nextTick(fn.bind.apply(fn, arguments)) }
/**
* Invoke callback when the response has finished, useful for
* cleaning up resources afterwards.
*
* @param {object} msg
* @param {function} listener
* @return {object}
* @public
*/
function onFinished(msg, listener) {
if (isFinished(msg) !== false) {
defer(listener, null, msg)
return msg
}
// attach the listener to the message
attachListener(msg, listener)
return msg
}
/**
* Determine if message is already finished.
*
* @param {object} msg
* @return {boolean}
* @public
*/
function isFinished(msg) {
var socket = msg.socket
if (typeof msg.finished === 'boolean') {
// OutgoingMessage
return Boolean(msg.finished || (socket && !socket.writable))
}
if (typeof msg.complete === 'boolean') {
// IncomingMessage
return Boolean(msg.upgrade || !socket || !socket.readable || (msg.complete && !msg.readable))
}
// don't know
return undefined
}
/**
* Attach a finished listener to the message.
*
* @param {object} msg
* @param {function} callback
* @private
*/
function attachFinishedListener(msg, callback) {
var eeMsg
var eeSocket
var finished = false
function onFinish(error) {
eeMsg.cancel()
eeSocket.cancel()
finished = true
callback(error)
}
// finished on first message event
eeMsg = eeSocket = first([[msg, 'end', 'finish']], onFinish)
function onSocket(socket) {
// remove listener
msg.removeListener('socket', onSocket)
if (finished) return
if (eeMsg !== eeSocket) return
// finished on first socket event
eeSocket = first([[socket, 'error', 'close']], onFinish)
}
if (msg.socket) {
// socket already assigned
onSocket(msg.socket)
return
}
// wait for socket to be assigned
msg.on('socket', onSocket)
if (msg.socket === undefined) {
// node.js 0.8 patch
patchAssignSocket(msg, onSocket)
}
}
/**
* Attach the listener to the message.
*
* @param {object} msg
* @return {function}
* @private
*/
function attachListener(msg, listener) {
var attached = msg.__onFinished
// create a private single listener with queue
if (!attached || !attached.queue) {
attached = msg.__onFinished = createListener(msg)
attachFinishedListener(msg, attached)
}
attached.queue.push(listener)
}
/**
* Create listener on message.
*
* @param {object} msg
* @return {function}
* @private
*/
function createListener(msg) {
function listener(err) {
if (msg.__onFinished === listener) msg.__onFinished = null
if (!listener.queue) return
var queue = listener.queue
listener.queue = null
for (var i = 0; i < queue.length; i++) {
queue[i](err, msg)
}
}
listener.queue = []
return listener
}
/**
* Patch ServerResponse.prototype.assignSocket for node.js 0.8.
*
* @param {ServerResponse} res
* @param {function} callback
* @private
*/
function patchAssignSocket(res, callback) {
var assignSocket = res.assignSocket
if (typeof assignSocket !== 'function') return
// res.on('socket', callback) is broken in 0.8
res.assignSocket = function _assignSocket(socket) {
assignSocket.call(this, socket)
callback(socket)
}
}

31
node_modules/on-finished/package.json generated vendored Normal file
View File

@ -0,0 +1,31 @@
{
"name": "on-finished",
"description": "Execute a callback when a request closes, finishes, or errors",
"version": "2.3.0",
"contributors": [
"Douglas Christopher Wilson <doug@somethingdoug.com>",
"Jonathan Ong <me@jongleberry.com> (http://jongleberry.com)"
],
"license": "MIT",
"repository": "jshttp/on-finished",
"dependencies": {
"ee-first": "1.1.1"
},
"devDependencies": {
"istanbul": "0.3.9",
"mocha": "2.2.5"
},
"engines": {
"node": ">= 0.8"
},
"files": [
"HISTORY.md",
"LICENSE",
"index.js"
],
"scripts": {
"test": "mocha --reporter spec --bail --check-leaks test/",
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/",
"test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/"
}
}

15
node_modules/once/LICENSE generated vendored Normal file
View File

@ -0,0 +1,15 @@
The ISC License
Copyright (c) Isaac Z. Schlueter and Contributors
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

79
node_modules/once/README.md generated vendored Normal file
View File

@ -0,0 +1,79 @@
# once
Only call a function once.
## usage
```javascript
var once = require('once')
function load (file, cb) {
cb = once(cb)
loader.load('file')
loader.once('load', cb)
loader.once('error', cb)
}
```
Or add to the Function.prototype in a responsible way:
```javascript
// only has to be done once
require('once').proto()
function load (file, cb) {
cb = cb.once()
loader.load('file')
loader.once('load', cb)
loader.once('error', cb)
}
```
Ironically, the prototype feature makes this module twice as
complicated as necessary.
To check whether you function has been called, use `fn.called`. Once the
function is called for the first time the return value of the original
function is saved in `fn.value` and subsequent calls will continue to
return this value.
```javascript
var once = require('once')
function load (cb) {
cb = once(cb)
var stream = createStream()
stream.once('data', cb)
stream.once('end', function () {
if (!cb.called) cb(new Error('not found'))
})
}
```
## `once.strict(func)`
Throw an error if the function is called twice.
Some functions are expected to be called only once. Using `once` for them would
potentially hide logical errors.
In the example below, the `greet` function has to call the callback only once:
```javascript
function greet (name, cb) {
// return is missing from the if statement
// when no name is passed, the callback is called twice
if (!name) cb('Hello anonymous')
cb('Hello ' + name)
}
function log (msg) {
console.log(msg)
}
// this will print 'Hello anonymous' but the logical error will be missed
greet(null, once(msg))
// once.strict will print 'Hello anonymous' and throw an error when the callback will be called the second time
greet(null, once.strict(msg))
```

42
node_modules/once/once.js generated vendored Normal file
View File

@ -0,0 +1,42 @@
var wrappy = require('wrappy')
module.exports = wrappy(once)
module.exports.strict = wrappy(onceStrict)
once.proto = once(function () {
Object.defineProperty(Function.prototype, 'once', {
value: function () {
return once(this)
},
configurable: true
})
Object.defineProperty(Function.prototype, 'onceStrict', {
value: function () {
return onceStrict(this)
},
configurable: true
})
})
function once (fn) {
var f = function () {
if (f.called) return f.value
f.called = true
return f.value = fn.apply(this, arguments)
}
f.called = false
return f
}
function onceStrict (fn) {
var f = function () {
if (f.called)
throw new Error(f.onceError)
f.called = true
return f.value = fn.apply(this, arguments)
}
var name = fn.name || 'Function wrapped with `once`'
f.onceError = name + " shouldn't be called more than once"
f.called = false
return f
}

33
node_modules/once/package.json generated vendored Normal file
View File

@ -0,0 +1,33 @@
{
"name": "once",
"version": "1.4.0",
"description": "Run a function exactly one time",
"main": "once.js",
"directories": {
"test": "test"
},
"dependencies": {
"wrappy": "1"
},
"devDependencies": {
"tap": "^7.0.1"
},
"scripts": {
"test": "tap test/*.js"
},
"files": [
"once.js"
],
"repository": {
"type": "git",
"url": "git://github.com/isaacs/once"
},
"keywords": [
"once",
"function",
"one",
"single"
],
"author": "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me/)",
"license": "ISC"
}

33
node_modules/qs/.editorconfig generated vendored Normal file
View File

@ -0,0 +1,33 @@
root = true
[*]
indent_style = space
indent_size = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
max_line_length = 160
[test/*]
max_line_length = off
[LICENSE.md]
indent_size = off
[*.md]
max_line_length = off
[*.json]
max_line_length = off
[Makefile]
max_line_length = off
[CHANGELOG.md]
indent_style = space
indent_size = 2
[LICENSE]
indent_size = 2
max_line_length = off

1
node_modules/qs/.eslintignore generated vendored Normal file
View File

@ -0,0 +1 @@
dist

21
node_modules/qs/.eslintrc generated vendored Normal file
View File

@ -0,0 +1,21 @@
{
"root": true,
"extends": "@ljharb",
"rules": {
"complexity": 0,
"consistent-return": 1,
"func-name-matching": 0,
"id-length": [2, { "min": 1, "max": 25, "properties": "never" }],
"indent": [2, 4],
"max-lines-per-function": [2, { "max": 150 }],
"max-params": [2, 14],
"max-statements": [2, 52],
"multiline-comment-style": 0,
"no-continue": 1,
"no-magic-numbers": 0,
"no-restricted-syntax": [2, "BreakStatement", "DebuggerStatement", "ForInStatement", "LabeledStatement", "WithStatement"],
"operator-linebreak": [2, "before"],
}
}

12
node_modules/qs/.github/FUNDING.yml generated vendored Normal file
View File

@ -0,0 +1,12 @@
# These are supported funding model platforms
github: [ljharb]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: npm/qs
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: # Replace with a single custom sponsorship URL

15
node_modules/qs/.github/workflows/rebase.yml generated vendored Normal file
View File

@ -0,0 +1,15 @@
name: Automatic Rebase
on: [pull_request]
jobs:
_:
name: "Automatic Rebase"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: ljharb/rebase@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

339
node_modules/qs/CHANGELOG.md generated vendored Normal file
View File

@ -0,0 +1,339 @@
## **6.9.3**
- [Fix] proper comma parsing of URL-encoded commas (#361)
- [Fix] parses comma delimited array while having percent-encoded comma treated as normal text (#336)
## **6.9.2**
- [Fix] `parse`: Fix parsing array from object with `comma` true (#359)
- [Fix] `parse`: throw a TypeError instead of an Error for bad charset (#349)
- [meta] ignore eclint transitive audit warning
- [meta] fix indentation in package.json
- [meta] add tidelift marketing copy
- [Dev Deps] update `eslint`, `@ljharb/eslint-config`, `object-inspect`, `has-symbols`, `tape`, `mkdirp`, `iconv-lite`
- [actions] add automatic rebasing / merge commit blocking
## **6.9.1**
- [Fix] `parse`: with comma true, handle field that holds an array of arrays (#335)
- [Fix] `parse`: with comma true, do not split non-string values (#334)
- [meta] add `funding` field
- [Dev Deps] update `eslint`, `@ljharb/eslint-config`
- [Tests] use shared travis-ci config
## **6.9.0**
- [New] `parse`/`stringify`: Pass extra key/value argument to `decoder` (#333)
- [Dev Deps] update `eslint`, `@ljharb/eslint-config`, `evalmd`
- [Tests] `parse`: add passing `arrayFormat` tests
- [Tests] add `posttest` using `npx aud` to run `npm audit` without a lockfile
- [Tests] up to `node` `v12.10`, `v11.15`, `v10.16`, `v8.16`
- [Tests] `Buffer.from` in node v5.0-v5.9 and v4.0-v4.4 requires a TypedArray
## **6.8.2**
- [Fix] proper comma parsing of URL-encoded commas (#361)
- [Fix] parses comma delimited array while having percent-encoded comma treated as normal text (#336)
## **6.8.1**
- [Fix] `parse`: Fix parsing array from object with `comma` true (#359)
- [Fix] `parse`: throw a TypeError instead of an Error for bad charset (#349)
- [Fix] `parse`: with comma true, handle field that holds an array of arrays (#335)
- [fix] `parse`: with comma true, do not split non-string values (#334)
- [meta] add tidelift marketing copy
- [meta] add `funding` field
- [Dev Deps] update `eslint`, `@ljharb/eslint-config`, `tape`, `safe-publish-latest`, `evalmd`, `has-symbols`, `iconv-lite`, `mkdirp`, `object-inspect`
- [Tests] `parse`: add passing `arrayFormat` tests
- [Tests] use shared travis-ci configs
- [Tests] `Buffer.from` in node v5.0-v5.9 and v4.0-v4.4 requires a TypedArray
- [actions] add automatic rebasing / merge commit blocking
## **6.8.0**
- [New] add `depth=false` to preserve the original key; [Fix] `depth=0` should preserve the original key (#326)
- [New] [Fix] stringify symbols and bigints
- [Fix] ensure node 0.12 can stringify Symbols
- [Fix] fix for an impossible situation: when the formatter is called with a non-string value
- [Refactor] `formats`: tiny bit of cleanup.
- [Dev Deps] update `eslint`, `@ljharb/eslint-config`, `browserify`, `safe-publish-latest`, `iconv-lite`, `tape`
- [Tests] add tests for `depth=0` and `depth=false` behavior, both current and intuitive/intended (#326)
- [Tests] use `eclint` instead of `editorconfig-tools`
- [docs] readme: add security note
- [meta] add github sponsorship
- [meta] add FUNDING.yml
- [meta] Clean up license text so its properly detected as BSD-3-Clause
## **6.7.2**
- [Fix] proper comma parsing of URL-encoded commas (#361)
- [Fix] parses comma delimited array while having percent-encoded comma treated as normal text (#336)
## **6.7.1**
- [Fix] `parse`: Fix parsing array from object with `comma` true (#359)
- [Fix] `parse`: with comma true, handle field that holds an array of arrays (#335)
- [fix] `parse`: with comma true, do not split non-string values (#334)
- [Fix] `parse`: throw a TypeError instead of an Error for bad charset (#349)
- [Fix] fix for an impossible situation: when the formatter is called with a non-string value
- [Refactor] `formats`: tiny bit of cleanup.
- readme: add security note
- [meta] add tidelift marketing copy
- [meta] add `funding` field
- [meta] add FUNDING.yml
- [meta] Clean up license text so its properly detected as BSD-3-Clause
- [Dev Deps] update `eslint`, `@ljharb/eslint-config`, `tape`, `safe-publish-latest`, `evalmd`, `iconv-lite`, `mkdirp`, `object-inspect`, `browserify`
- [Tests] `parse`: add passing `arrayFormat` tests
- [Tests] use shared travis-ci configs
- [Tests] `Buffer.from` in node v5.0-v5.9 and v4.0-v4.4 requires a TypedArray
- [Tests] add tests for `depth=0` and `depth=false` behavior, both current and intuitive/intended
- [Tests] use `eclint` instead of `editorconfig-tools`
- [actions] add automatic rebasing / merge commit blocking
## **6.7.0**
- [New] `stringify`/`parse`: add `comma` as an `arrayFormat` option (#276, #219)
- [Fix] correctly parse nested arrays (#212)
- [Fix] `utils.merge`: avoid a crash with a null target and a truthy non-array source, also with an array source
- [Robustness] `stringify`: cache `Object.prototype.hasOwnProperty`
- [Refactor] `utils`: `isBuffer`: small tweak; add tests
- [Refactor] use cached `Array.isArray`
- [Refactor] `parse`/`stringify`: make a function to normalize the options
- [Refactor] `utils`: reduce observable [[Get]]s
- [Refactor] `stringify`/`utils`: cache `Array.isArray`
- [Tests] always use `String(x)` over `x.toString()`
- [Tests] fix Buffer tests to work in node < 4.5 and node < 5.10
- [Tests] temporarily allow coverage to fail
## **6.6.0**
- [New] Add support for iso-8859-1, utf8 "sentinel" and numeric entities (#268)
- [New] move two-value combine to a `utils` function (#189)
- [Fix] `stringify`: fix a crash with `strictNullHandling` and a custom `filter`/`serializeDate` (#279)
- [Fix] when `parseArrays` is false, properly handle keys ending in `[]` (#260)
- [Fix] `stringify`: do not crash in an obscure combo of `interpretNumericEntities`, a bad custom `decoder`, & `iso-8859-1`
- [Fix] `utils`: `merge`: fix crash when `source` is a truthy primitive & no options are provided
- [refactor] `stringify`: Avoid arr = arr.concat(...), push to the existing instance (#269)
- [Refactor] `parse`: only need to reassign the var once
- [Refactor] `parse`/`stringify`: clean up `charset` options checking; fix defaults
- [Refactor] add missing defaults
- [Refactor] `parse`: one less `concat` call
- [Refactor] `utils`: `compactQueue`: make it explicitly side-effecting
- [Dev Deps] update `browserify`, `eslint`, `@ljharb/eslint-config`, `iconv-lite`, `safe-publish-latest`, `tape`
- [Tests] up to `node` `v10.10`, `v9.11`, `v8.12`, `v6.14`, `v4.9`; pin included builds to LTS
## **6.5.2**
- [Fix] use `safer-buffer` instead of `Buffer` constructor
- [Refactor] utils: `module.exports` one thing, instead of mutating `exports` (#230)
- [Dev Deps] update `browserify`, `eslint`, `iconv-lite`, `safer-buffer`, `tape`, `browserify`
## **6.5.1**
- [Fix] Fix parsing & compacting very deep objects (#224)
- [Refactor] name utils functions
- [Dev Deps] update `eslint`, `@ljharb/eslint-config`, `tape`
- [Tests] up to `node` `v8.4`; use `nvm install-latest-npm` so newer npm doesnt break older node
- [Tests] Use precise dist for Node.js 0.6 runtime (#225)
- [Tests] make 0.6 required, now that its passing
- [Tests] on `node` `v8.2`; fix npm on node 0.6
## **6.5.0**
- [New] add `utils.assign`
- [New] pass default encoder/decoder to custom encoder/decoder functions (#206)
- [New] `parse`/`stringify`: add `ignoreQueryPrefix`/`addQueryPrefix` options, respectively (#213)
- [Fix] Handle stringifying empty objects with addQueryPrefix (#217)
- [Fix] do not mutate `options` argument (#207)
- [Refactor] `parse`: cache index to reuse in else statement (#182)
- [Docs] add various badges to readme (#208)
- [Dev Deps] update `eslint`, `browserify`, `iconv-lite`, `tape`
- [Tests] up to `node` `v8.1`, `v7.10`, `v6.11`; npm v4.6 breaks on node < v1; npm v5+ breaks on node < v4
- [Tests] add `editorconfig-tools`
## **6.4.0**
- [New] `qs.stringify`: add `encodeValuesOnly` option
- [Fix] follow `allowPrototypes` option during merge (#201, #201)
- [Fix] support keys starting with brackets (#202, #200)
- [Fix] chmod a-x
- [Dev Deps] update `eslint`
- [Tests] up to `node` `v7.7`, `v6.10`,` v4.8`; disable osx builds since they block linux builds
- [eslint] reduce warnings
## **6.3.2**
- [Fix] follow `allowPrototypes` option during merge (#201, #200)
- [Dev Deps] update `eslint`
- [Fix] chmod a-x
- [Fix] support keys starting with brackets (#202, #200)
- [Tests] up to `node` `v7.7`, `v6.10`,` v4.8`; disable osx builds since they block linux builds
## **6.3.1**
- [Fix] ensure that `allowPrototypes: false` does not ever shadow Object.prototype properties (thanks, @snyk!)
- [Dev Deps] update `eslint`, `@ljharb/eslint-config`, `browserify`, `iconv-lite`, `qs-iconv`, `tape`
- [Tests] on all node minors; improve test matrix
- [Docs] document stringify option `allowDots` (#195)
- [Docs] add empty object and array values example (#195)
- [Docs] Fix minor inconsistency/typo (#192)
- [Docs] document stringify option `sort` (#191)
- [Refactor] `stringify`: throw faster with an invalid encoder
- [Refactor] remove unnecessary escapes (#184)
- Remove contributing.md, since `qs` is no longer part of `hapi` (#183)
## **6.3.0**
- [New] Add support for RFC 1738 (#174, #173)
- [New] `stringify`: Add `serializeDate` option to customize Date serialization (#159)
- [Fix] ensure `utils.merge` handles merging two arrays
- [Refactor] only constructors should be capitalized
- [Refactor] capitalized var names are for constructors only
- [Refactor] avoid using a sparse array
- [Robustness] `formats`: cache `String#replace`
- [Dev Deps] update `browserify`, `eslint`, `@ljharb/eslint-config`; add `safe-publish-latest`
- [Tests] up to `node` `v6.8`, `v4.6`; improve test matrix
- [Tests] flesh out arrayLimit/arrayFormat tests (#107)
- [Tests] skip Object.create tests when null objects are not available
- [Tests] Turn on eslint for test files (#175)
## **6.2.3**
- [Fix] follow `allowPrototypes` option during merge (#201, #200)
- [Fix] chmod a-x
- [Fix] support keys starting with brackets (#202, #200)
- [Tests] up to `node` `v7.7`, `v6.10`,` v4.8`; disable osx builds since they block linux builds
## **6.2.2**
- [Fix] ensure that `allowPrototypes: false` does not ever shadow Object.prototype properties
## **6.2.1**
- [Fix] ensure `key[]=x&key[]&key[]=y` results in 3, not 2, values
- [Refactor] Be explicit and use `Object.prototype.hasOwnProperty.call`
- [Tests] remove `parallelshell` since it does not reliably report failures
- [Tests] up to `node` `v6.3`, `v5.12`
- [Dev Deps] update `tape`, `eslint`, `@ljharb/eslint-config`, `qs-iconv`
## [**6.2.0**](https://github.com/ljharb/qs/issues?milestone=36&state=closed)
- [New] pass Buffers to the encoder/decoder directly (#161)
- [New] add "encoder" and "decoder" options, for custom param encoding/decoding (#160)
- [Fix] fix compacting of nested sparse arrays (#150)
## **6.1.2
- [Fix] follow `allowPrototypes` option during merge (#201, #200)
- [Fix] chmod a-x
- [Fix] support keys starting with brackets (#202, #200)
- [Tests] up to `node` `v7.7`, `v6.10`,` v4.8`; disable osx builds since they block linux builds
## **6.1.1**
- [Fix] ensure that `allowPrototypes: false` does not ever shadow Object.prototype properties
## [**6.1.0**](https://github.com/ljharb/qs/issues?milestone=35&state=closed)
- [New] allowDots option for `stringify` (#151)
- [Fix] "sort" option should work at a depth of 3 or more (#151)
- [Fix] Restore `dist` directory; will be removed in v7 (#148)
## **6.0.4**
- [Fix] follow `allowPrototypes` option during merge (#201, #200)
- [Fix] chmod a-x
- [Fix] support keys starting with brackets (#202, #200)
- [Tests] up to `node` `v7.7`, `v6.10`,` v4.8`; disable osx builds since they block linux builds
## **6.0.3**
- [Fix] ensure that `allowPrototypes: false` does not ever shadow Object.prototype properties
- [Fix] Restore `dist` directory; will be removed in v7 (#148)
## [**6.0.2**](https://github.com/ljharb/qs/issues?milestone=33&state=closed)
- Revert ES6 requirement and restore support for node down to v0.8.
## [**6.0.1**](https://github.com/ljharb/qs/issues?milestone=32&state=closed)
- [**#127**](https://github.com/ljharb/qs/pull/127) Fix engines definition in package.json
## [**6.0.0**](https://github.com/ljharb/qs/issues?milestone=31&state=closed)
- [**#124**](https://github.com/ljharb/qs/issues/124) Use ES6 and drop support for node < v4
## **5.2.1**
- [Fix] ensure `key[]=x&key[]&key[]=y` results in 3, not 2, values
## [**5.2.0**](https://github.com/ljharb/qs/issues?milestone=30&state=closed)
- [**#64**](https://github.com/ljharb/qs/issues/64) Add option to sort object keys in the query string
## [**5.1.0**](https://github.com/ljharb/qs/issues?milestone=29&state=closed)
- [**#117**](https://github.com/ljharb/qs/issues/117) make URI encoding stringified results optional
- [**#106**](https://github.com/ljharb/qs/issues/106) Add flag `skipNulls` to optionally skip null values in stringify
## [**5.0.0**](https://github.com/ljharb/qs/issues?milestone=28&state=closed)
- [**#114**](https://github.com/ljharb/qs/issues/114) default allowDots to false
- [**#100**](https://github.com/ljharb/qs/issues/100) include dist to npm
## [**4.0.0**](https://github.com/ljharb/qs/issues?milestone=26&state=closed)
- [**#98**](https://github.com/ljharb/qs/issues/98) make returning plain objects and allowing prototype overwriting properties optional
## [**3.1.0**](https://github.com/ljharb/qs/issues?milestone=24&state=closed)
- [**#89**](https://github.com/ljharb/qs/issues/89) Add option to disable "Transform dot notation to bracket notation"
## [**3.0.0**](https://github.com/ljharb/qs/issues?milestone=23&state=closed)
- [**#80**](https://github.com/ljharb/qs/issues/80) qs.parse silently drops properties
- [**#77**](https://github.com/ljharb/qs/issues/77) Perf boost
- [**#60**](https://github.com/ljharb/qs/issues/60) Add explicit option to disable array parsing
- [**#74**](https://github.com/ljharb/qs/issues/74) Bad parse when turning array into object
- [**#81**](https://github.com/ljharb/qs/issues/81) Add a `filter` option
- [**#68**](https://github.com/ljharb/qs/issues/68) Fixed issue with recursion and passing strings into objects.
- [**#66**](https://github.com/ljharb/qs/issues/66) Add mixed array and object dot notation support Closes: #47
- [**#76**](https://github.com/ljharb/qs/issues/76) RFC 3986
- [**#85**](https://github.com/ljharb/qs/issues/85) No equal sign
- [**#84**](https://github.com/ljharb/qs/issues/84) update license attribute
## [**2.4.1**](https://github.com/ljharb/qs/issues?milestone=20&state=closed)
- [**#73**](https://github.com/ljharb/qs/issues/73) Property 'hasOwnProperty' of object #<Object> is not a function
## [**2.4.0**](https://github.com/ljharb/qs/issues?milestone=19&state=closed)
- [**#70**](https://github.com/ljharb/qs/issues/70) Add arrayFormat option
## [**2.3.3**](https://github.com/ljharb/qs/issues?milestone=18&state=closed)
- [**#59**](https://github.com/ljharb/qs/issues/59) make sure array indexes are >= 0, closes #57
- [**#58**](https://github.com/ljharb/qs/issues/58) make qs usable for browser loader
## [**2.3.2**](https://github.com/ljharb/qs/issues?milestone=17&state=closed)
- [**#55**](https://github.com/ljharb/qs/issues/55) allow merging a string into an object
## [**2.3.1**](https://github.com/ljharb/qs/issues?milestone=16&state=closed)
- [**#52**](https://github.com/ljharb/qs/issues/52) Return "undefined" and "false" instead of throwing "TypeError".
## [**2.3.0**](https://github.com/ljharb/qs/issues?milestone=15&state=closed)
- [**#50**](https://github.com/ljharb/qs/issues/50) add option to omit array indices, closes #46
## [**2.2.5**](https://github.com/ljharb/qs/issues?milestone=14&state=closed)
- [**#39**](https://github.com/ljharb/qs/issues/39) Is there an alternative to Buffer.isBuffer?
- [**#49**](https://github.com/ljharb/qs/issues/49) refactor utils.merge, fixes #45
- [**#41**](https://github.com/ljharb/qs/issues/41) avoid browserifying Buffer, for #39
## [**2.2.4**](https://github.com/ljharb/qs/issues?milestone=13&state=closed)
- [**#38**](https://github.com/ljharb/qs/issues/38) how to handle object keys beginning with a number
## [**2.2.3**](https://github.com/ljharb/qs/issues?milestone=12&state=closed)
- [**#37**](https://github.com/ljharb/qs/issues/37) parser discards first empty value in array
- [**#36**](https://github.com/ljharb/qs/issues/36) Update to lab 4.x
## [**2.2.2**](https://github.com/ljharb/qs/issues?milestone=11&state=closed)
- [**#33**](https://github.com/ljharb/qs/issues/33) Error when plain object in a value
- [**#34**](https://github.com/ljharb/qs/issues/34) use Object.prototype.hasOwnProperty.call instead of obj.hasOwnProperty
- [**#24**](https://github.com/ljharb/qs/issues/24) Changelog? Semver?
## [**2.2.1**](https://github.com/ljharb/qs/issues?milestone=10&state=closed)
- [**#32**](https://github.com/ljharb/qs/issues/32) account for circular references properly, closes #31
- [**#31**](https://github.com/ljharb/qs/issues/31) qs.parse stackoverflow on circular objects
## [**2.2.0**](https://github.com/ljharb/qs/issues?milestone=9&state=closed)
- [**#26**](https://github.com/ljharb/qs/issues/26) Don't use Buffer global if it's not present
- [**#30**](https://github.com/ljharb/qs/issues/30) Bug when merging non-object values into arrays
- [**#29**](https://github.com/ljharb/qs/issues/29) Don't call Utils.clone at the top of Utils.merge
- [**#23**](https://github.com/ljharb/qs/issues/23) Ability to not limit parameters?
## [**2.1.0**](https://github.com/ljharb/qs/issues?milestone=8&state=closed)
- [**#22**](https://github.com/ljharb/qs/issues/22) Enable using a RegExp as delimiter
## [**2.0.0**](https://github.com/ljharb/qs/issues?milestone=7&state=closed)
- [**#18**](https://github.com/ljharb/qs/issues/18) Why is there arrayLimit?
- [**#20**](https://github.com/ljharb/qs/issues/20) Configurable parametersLimit
- [**#21**](https://github.com/ljharb/qs/issues/21) make all limits optional, for #18, for #20
## [**1.2.2**](https://github.com/ljharb/qs/issues?milestone=6&state=closed)
- [**#19**](https://github.com/ljharb/qs/issues/19) Don't overwrite null values
## [**1.2.1**](https://github.com/ljharb/qs/issues?milestone=5&state=closed)
- [**#16**](https://github.com/ljharb/qs/issues/16) ignore non-string delimiters
- [**#15**](https://github.com/ljharb/qs/issues/15) Close code block
## [**1.2.0**](https://github.com/ljharb/qs/issues?milestone=4&state=closed)
- [**#12**](https://github.com/ljharb/qs/issues/12) Add optional delim argument
- [**#13**](https://github.com/ljharb/qs/issues/13) fix #11: flattened keys in array are now correctly parsed
## [**1.1.0**](https://github.com/ljharb/qs/issues?milestone=3&state=closed)
- [**#7**](https://github.com/ljharb/qs/issues/7) Empty values of a POST array disappear after being submitted
- [**#9**](https://github.com/ljharb/qs/issues/9) Should not omit equals signs (=) when value is null
- [**#6**](https://github.com/ljharb/qs/issues/6) Minor grammar fix in README
## [**1.0.2**](https://github.com/ljharb/qs/issues?milestone=2&state=closed)
- [**#5**](https://github.com/ljharb/qs/issues/5) array holes incorrectly copied into object on large index

29
node_modules/qs/LICENSE.md generated vendored Normal file
View File

@ -0,0 +1,29 @@
BSD 3-Clause License
Copyright (c) 2014, Nathan LaFreniere and other [contributors](https://github.com/ljharb/qs/graphs/contributors)
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

604
node_modules/qs/README.md generated vendored Normal file
View File

@ -0,0 +1,604 @@
# qs <sup>[![Version Badge][2]][1]</sup>
[![Build Status][3]][4]
[![dependency status][5]][6]
[![dev dependency status][7]][8]
[![License][license-image]][license-url]
[![Downloads][downloads-image]][downloads-url]
[![npm badge][11]][1]
A querystring parsing and stringifying library with some added security.
Lead Maintainer: [Jordan Harband](https://github.com/ljharb)
The **qs** module was originally created and maintained by [TJ Holowaychuk](https://github.com/visionmedia/node-querystring).
## Usage
```javascript
var qs = require('qs');
var assert = require('assert');
var obj = qs.parse('a=c');
assert.deepEqual(obj, { a: 'c' });
var str = qs.stringify(obj);
assert.equal(str, 'a=c');
```
### Parsing Objects
[](#preventEval)
```javascript
qs.parse(string, [options]);
```
**qs** allows you to create nested objects within your query strings, by surrounding the name of sub-keys with square brackets `[]`.
For example, the string `'foo[bar]=baz'` converts to:
```javascript
assert.deepEqual(qs.parse('foo[bar]=baz'), {
foo: {
bar: 'baz'
}
});
```
When using the `plainObjects` option the parsed value is returned as a null object, created via `Object.create(null)` and as such you should be aware that prototype methods will not exist on it and a user may set those names to whatever value they like:
```javascript
var nullObject = qs.parse('a[hasOwnProperty]=b', { plainObjects: true });
assert.deepEqual(nullObject, { a: { hasOwnProperty: 'b' } });
```
By default parameters that would overwrite properties on the object prototype are ignored, if you wish to keep the data from those fields either use `plainObjects` as mentioned above, or set `allowPrototypes` to `true` which will allow user input to overwrite those properties. *WARNING* It is generally a bad idea to enable this option as it can cause problems when attempting to use the properties that have been overwritten. Always be careful with this option.
```javascript
var protoObject = qs.parse('a[hasOwnProperty]=b', { allowPrototypes: true });
assert.deepEqual(protoObject, { a: { hasOwnProperty: 'b' } });
```
URI encoded strings work too:
```javascript
assert.deepEqual(qs.parse('a%5Bb%5D=c'), {
a: { b: 'c' }
});
```
You can also nest your objects, like `'foo[bar][baz]=foobarbaz'`:
```javascript
assert.deepEqual(qs.parse('foo[bar][baz]=foobarbaz'), {
foo: {
bar: {
baz: 'foobarbaz'
}
}
});
```
By default, when nesting objects **qs** will only parse up to 5 children deep. This means if you attempt to parse a string like
`'a[b][c][d][e][f][g][h][i]=j'` your resulting object will be:
```javascript
var expected = {
a: {
b: {
c: {
d: {
e: {
f: {
'[g][h][i]': 'j'
}
}
}
}
}
}
};
var string = 'a[b][c][d][e][f][g][h][i]=j';
assert.deepEqual(qs.parse(string), expected);
```
This depth can be overridden by passing a `depth` option to `qs.parse(string, [options])`:
```javascript
var deep = qs.parse('a[b][c][d][e][f][g][h][i]=j', { depth: 1 });
assert.deepEqual(deep, { a: { b: { '[c][d][e][f][g][h][i]': 'j' } } });
```
The depth limit helps mitigate abuse when **qs** is used to parse user input, and it is recommended to keep it a reasonably small number.
For similar reasons, by default **qs** will only parse up to 1000 parameters. This can be overridden by passing a `parameterLimit` option:
```javascript
var limited = qs.parse('a=b&c=d', { parameterLimit: 1 });
assert.deepEqual(limited, { a: 'b' });
```
To bypass the leading question mark, use `ignoreQueryPrefix`:
```javascript
var prefixed = qs.parse('?a=b&c=d', { ignoreQueryPrefix: true });
assert.deepEqual(prefixed, { a: 'b', c: 'd' });
```
An optional delimiter can also be passed:
```javascript
var delimited = qs.parse('a=b;c=d', { delimiter: ';' });
assert.deepEqual(delimited, { a: 'b', c: 'd' });
```
Delimiters can be a regular expression too:
```javascript
var regexed = qs.parse('a=b;c=d,e=f', { delimiter: /[;,]/ });
assert.deepEqual(regexed, { a: 'b', c: 'd', e: 'f' });
```
Option `allowDots` can be used to enable dot notation:
```javascript
var withDots = qs.parse('a.b=c', { allowDots: true });
assert.deepEqual(withDots, { a: { b: 'c' } });
```
If you have to deal with legacy browsers or services, there's
also support for decoding percent-encoded octets as iso-8859-1:
```javascript
var oldCharset = qs.parse('a=%A7', { charset: 'iso-8859-1' });
assert.deepEqual(oldCharset, { a: '§' });
```
Some services add an initial `utf8=✓` value to forms so that old
Internet Explorer versions are more likely to submit the form as
utf-8. Additionally, the server can check the value against wrong
encodings of the checkmark character and detect that a query string
or `application/x-www-form-urlencoded` body was *not* sent as
utf-8, eg. if the form had an `accept-charset` parameter or the
containing page had a different character set.
**qs** supports this mechanism via the `charsetSentinel` option.
If specified, the `utf8` parameter will be omitted from the
returned object. It will be used to switch to `iso-8859-1`/`utf-8`
mode depending on how the checkmark is encoded.
**Important**: When you specify both the `charset` option and the
`charsetSentinel` option, the `charset` will be overridden when
the request contains a `utf8` parameter from which the actual
charset can be deduced. In that sense the `charset` will behave
as the default charset rather than the authoritative charset.
```javascript
var detectedAsUtf8 = qs.parse('utf8=%E2%9C%93&a=%C3%B8', {
charset: 'iso-8859-1',
charsetSentinel: true
});
assert.deepEqual(detectedAsUtf8, { a: 'ø' });
// Browsers encode the checkmark as &#10003; when submitting as iso-8859-1:
var detectedAsIso8859_1 = qs.parse('utf8=%26%2310003%3B&a=%F8', {
charset: 'utf-8',
charsetSentinel: true
});
assert.deepEqual(detectedAsIso8859_1, { a: 'ø' });
```
If you want to decode the `&#...;` syntax to the actual character,
you can specify the `interpretNumericEntities` option as well:
```javascript
var detectedAsIso8859_1 = qs.parse('a=%26%239786%3B', {
charset: 'iso-8859-1',
interpretNumericEntities: true
});
assert.deepEqual(detectedAsIso8859_1, { a: '☺' });
```
It also works when the charset has been detected in `charsetSentinel`
mode.
### Parsing Arrays
**qs** can also parse arrays using a similar `[]` notation:
```javascript
var withArray = qs.parse('a[]=b&a[]=c');
assert.deepEqual(withArray, { a: ['b', 'c'] });
```
You may specify an index as well:
```javascript
var withIndexes = qs.parse('a[1]=c&a[0]=b');
assert.deepEqual(withIndexes, { a: ['b', 'c'] });
```
Note that the only difference between an index in an array and a key in an object is that the value between the brackets must be a number
to create an array. When creating arrays with specific indices, **qs** will compact a sparse array to only the existing values preserving
their order:
```javascript
var noSparse = qs.parse('a[1]=b&a[15]=c');
assert.deepEqual(noSparse, { a: ['b', 'c'] });
```
Note that an empty string is also a value, and will be preserved:
```javascript
var withEmptyString = qs.parse('a[]=&a[]=b');
assert.deepEqual(withEmptyString, { a: ['', 'b'] });
var withIndexedEmptyString = qs.parse('a[0]=b&a[1]=&a[2]=c');
assert.deepEqual(withIndexedEmptyString, { a: ['b', '', 'c'] });
```
**qs** will also limit specifying indices in an array to a maximum index of `20`. Any array members with an index of greater than `20` will
instead be converted to an object with the index as the key. This is needed to handle cases when someone sent, for example, `a[999999999]` and it will take significant time to iterate over this huge array.
```javascript
var withMaxIndex = qs.parse('a[100]=b');
assert.deepEqual(withMaxIndex, { a: { '100': 'b' } });
```
This limit can be overridden by passing an `arrayLimit` option:
```javascript
var withArrayLimit = qs.parse('a[1]=b', { arrayLimit: 0 });
assert.deepEqual(withArrayLimit, { a: { '1': 'b' } });
```
To disable array parsing entirely, set `parseArrays` to `false`.
```javascript
var noParsingArrays = qs.parse('a[]=b', { parseArrays: false });
assert.deepEqual(noParsingArrays, { a: { '0': 'b' } });
```
If you mix notations, **qs** will merge the two items into an object:
```javascript
var mixedNotation = qs.parse('a[0]=b&a[b]=c');
assert.deepEqual(mixedNotation, { a: { '0': 'b', b: 'c' } });
```
You can also create arrays of objects:
```javascript
var arraysOfObjects = qs.parse('a[][b]=c');
assert.deepEqual(arraysOfObjects, { a: [{ b: 'c' }] });
```
Some people use comma to join array, **qs** can parse it:
```javascript
var arraysOfObjects = qs.parse('a=b,c', { comma: true })
assert.deepEqual(arraysOfObjects, { a: ['b', 'c'] })
```
(_this cannot convert nested objects, such as `a={b:1},{c:d}`_)
### Stringifying
[](#preventEval)
```javascript
qs.stringify(object, [options]);
```
When stringifying, **qs** by default URI encodes output. Objects are stringified as you would expect:
```javascript
assert.equal(qs.stringify({ a: 'b' }), 'a=b');
assert.equal(qs.stringify({ a: { b: 'c' } }), 'a%5Bb%5D=c');
```
This encoding can be disabled by setting the `encode` option to `false`:
```javascript
var unencoded = qs.stringify({ a: { b: 'c' } }, { encode: false });
assert.equal(unencoded, 'a[b]=c');
```
Encoding can be disabled for keys by setting the `encodeValuesOnly` option to `true`:
```javascript
var encodedValues = qs.stringify(
{ a: 'b', c: ['d', 'e=f'], f: [['g'], ['h']] },
{ encodeValuesOnly: true }
);
assert.equal(encodedValues,'a=b&c[0]=d&c[1]=e%3Df&f[0][0]=g&f[1][0]=h');
```
This encoding can also be replaced by a custom encoding method set as `encoder` option:
```javascript
var encoded = qs.stringify({ a: { b: 'c' } }, { encoder: function (str) {
// Passed in values `a`, `b`, `c`
return // Return encoded string
}})
```
_(Note: the `encoder` option does not apply if `encode` is `false`)_
Analogue to the `encoder` there is a `decoder` option for `parse` to override decoding of properties and values:
```javascript
var decoded = qs.parse('x=z', { decoder: function (str) {
// Passed in values `x`, `z`
return // Return decoded string
}})
```
You can encode keys and values using different logic by using the type argument provided to the encoder:
```javascript
var encoded = qs.stringify({ a: { b: 'c' } }, { encoder: function (str, defaultEncoder, charset, type) {
if (type === 'key') {
return // Encoded key
} else if (type === 'value') {
return // Encoded value
}
}})
```
The type argument is also provided to the decoder:
```javascript
var decoded = qs.parse('x=z', { decoder: function (str, defaultEncoder, charset, type) {
if (type === 'key') {
return // Decoded key
} else if (type === 'value') {
return // Decoded value
}
}})
```
Examples beyond this point will be shown as though the output is not URI encoded for clarity. Please note that the return values in these cases *will* be URI encoded during real usage.
When arrays are stringified, by default they are given explicit indices:
```javascript
qs.stringify({ a: ['b', 'c', 'd'] });
// 'a[0]=b&a[1]=c&a[2]=d'
```
You may override this by setting the `indices` option to `false`:
```javascript
qs.stringify({ a: ['b', 'c', 'd'] }, { indices: false });
// 'a=b&a=c&a=d'
```
You may use the `arrayFormat` option to specify the format of the output array:
```javascript
qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'indices' })
// 'a[0]=b&a[1]=c'
qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'brackets' })
// 'a[]=b&a[]=c'
qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'repeat' })
// 'a=b&a=c'
qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'comma' })
// 'a=b,c'
```
When objects are stringified, by default they use bracket notation:
```javascript
qs.stringify({ a: { b: { c: 'd', e: 'f' } } });
// 'a[b][c]=d&a[b][e]=f'
```
You may override this to use dot notation by setting the `allowDots` option to `true`:
```javascript
qs.stringify({ a: { b: { c: 'd', e: 'f' } } }, { allowDots: true });
// 'a.b.c=d&a.b.e=f'
```
Empty strings and null values will omit the value, but the equals sign (=) remains in place:
```javascript
assert.equal(qs.stringify({ a: '' }), 'a=');
```
Key with no values (such as an empty object or array) will return nothing:
```javascript
assert.equal(qs.stringify({ a: [] }), '');
assert.equal(qs.stringify({ a: {} }), '');
assert.equal(qs.stringify({ a: [{}] }), '');
assert.equal(qs.stringify({ a: { b: []} }), '');
assert.equal(qs.stringify({ a: { b: {}} }), '');
```
Properties that are set to `undefined` will be omitted entirely:
```javascript
assert.equal(qs.stringify({ a: null, b: undefined }), 'a=');
```
The query string may optionally be prepended with a question mark:
```javascript
assert.equal(qs.stringify({ a: 'b', c: 'd' }, { addQueryPrefix: true }), '?a=b&c=d');
```
The delimiter may be overridden with stringify as well:
```javascript
assert.equal(qs.stringify({ a: 'b', c: 'd' }, { delimiter: ';' }), 'a=b;c=d');
```
If you only want to override the serialization of `Date` objects, you can provide a `serializeDate` option:
```javascript
var date = new Date(7);
assert.equal(qs.stringify({ a: date }), 'a=1970-01-01T00:00:00.007Z'.replace(/:/g, '%3A'));
assert.equal(
qs.stringify({ a: date }, { serializeDate: function (d) { return d.getTime(); } }),
'a=7'
);
```
You may use the `sort` option to affect the order of parameter keys:
```javascript
function alphabeticalSort(a, b) {
return a.localeCompare(b);
}
assert.equal(qs.stringify({ a: 'c', z: 'y', b : 'f' }, { sort: alphabeticalSort }), 'a=c&b=f&z=y');
```
Finally, you can use the `filter` option to restrict which keys will be included in the stringified output.
If you pass a function, it will be called for each key to obtain the replacement value. Otherwise, if you
pass an array, it will be used to select properties and array indices for stringification:
```javascript
function filterFunc(prefix, value) {
if (prefix == 'b') {
// Return an `undefined` value to omit a property.
return;
}
if (prefix == 'e[f]') {
return value.getTime();
}
if (prefix == 'e[g][0]') {
return value * 2;
}
return value;
}
qs.stringify({ a: 'b', c: 'd', e: { f: new Date(123), g: [2] } }, { filter: filterFunc });
// 'a=b&c=d&e[f]=123&e[g][0]=4'
qs.stringify({ a: 'b', c: 'd', e: 'f' }, { filter: ['a', 'e'] });
// 'a=b&e=f'
qs.stringify({ a: ['b', 'c', 'd'], e: 'f' }, { filter: ['a', 0, 2] });
// 'a[0]=b&a[2]=d'
```
### Handling of `null` values
By default, `null` values are treated like empty strings:
```javascript
var withNull = qs.stringify({ a: null, b: '' });
assert.equal(withNull, 'a=&b=');
```
Parsing does not distinguish between parameters with and without equal signs. Both are converted to empty strings.
```javascript
var equalsInsensitive = qs.parse('a&b=');
assert.deepEqual(equalsInsensitive, { a: '', b: '' });
```
To distinguish between `null` values and empty strings use the `strictNullHandling` flag. In the result string the `null`
values have no `=` sign:
```javascript
var strictNull = qs.stringify({ a: null, b: '' }, { strictNullHandling: true });
assert.equal(strictNull, 'a&b=');
```
To parse values without `=` back to `null` use the `strictNullHandling` flag:
```javascript
var parsedStrictNull = qs.parse('a&b=', { strictNullHandling: true });
assert.deepEqual(parsedStrictNull, { a: null, b: '' });
```
To completely skip rendering keys with `null` values, use the `skipNulls` flag:
```javascript
var nullsSkipped = qs.stringify({ a: 'b', c: null}, { skipNulls: true });
assert.equal(nullsSkipped, 'a=b');
```
If you're communicating with legacy systems, you can switch to `iso-8859-1`
using the `charset` option:
```javascript
var iso = qs.stringify({ æ: 'æ' }, { charset: 'iso-8859-1' });
assert.equal(iso, '%E6=%E6');
```
Characters that don't exist in `iso-8859-1` will be converted to numeric
entities, similar to what browsers do:
```javascript
var numeric = qs.stringify({ a: '☺' }, { charset: 'iso-8859-1' });
assert.equal(numeric, 'a=%26%239786%3B');
```
You can use the `charsetSentinel` option to announce the character by
including an `utf8=✓` parameter with the proper encoding if the checkmark,
similar to what Ruby on Rails and others do when submitting forms.
```javascript
var sentinel = qs.stringify({ a: '☺' }, { charsetSentinel: true });
assert.equal(sentinel, 'utf8=%E2%9C%93&a=%E2%98%BA');
var isoSentinel = qs.stringify({ a: 'æ' }, { charsetSentinel: true, charset: 'iso-8859-1' });
assert.equal(isoSentinel, 'utf8=%26%2310003%3B&a=%E6');
```
### Dealing with special character sets
By default the encoding and decoding of characters is done in `utf-8`,
and `iso-8859-1` support is also built in via the `charset` parameter.
If you wish to encode querystrings to a different character set (i.e.
[Shift JIS](https://en.wikipedia.org/wiki/Shift_JIS)) you can use the
[`qs-iconv`](https://github.com/martinheidegger/qs-iconv) library:
```javascript
var encoder = require('qs-iconv/encoder')('shift_jis');
var shiftJISEncoded = qs.stringify({ a: 'こんにちは!' }, { encoder: encoder });
assert.equal(shiftJISEncoded, 'a=%82%B1%82%F1%82%C9%82%BF%82%CD%81I');
```
This also works for decoding of query strings:
```javascript
var decoder = require('qs-iconv/decoder')('shift_jis');
var obj = qs.parse('a=%82%B1%82%F1%82%C9%82%BF%82%CD%81I', { decoder: decoder });
assert.deepEqual(obj, { a: 'こんにちは!' });
```
### RFC 3986 and RFC 1738 space encoding
RFC3986 used as default option and encodes ' ' to *%20* which is backward compatible.
In the same time, output can be stringified as per RFC1738 with ' ' equal to '+'.
```
assert.equal(qs.stringify({ a: 'b c' }), 'a=b%20c');
assert.equal(qs.stringify({ a: 'b c' }, { format : 'RFC3986' }), 'a=b%20c');
assert.equal(qs.stringify({ a: 'b c' }, { format : 'RFC1738' }), 'a=b+c');
```
## Security
Please email [@ljharb](https://github.com/ljharb) or see https://tidelift.com/security if you have a potential security vulnerability to report.
## qs for enterprise
Available as part of the Tidelift Subscription
The maintainers of qs and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/npm-qs?utm_source=npm-qs&utm_medium=referral&utm_campaign=enterprise&utm_term=repo)
[1]: https://npmjs.org/package/qs
[2]: http://versionbadg.es/ljharb/qs.svg
[3]: https://api.travis-ci.org/ljharb/qs.svg
[4]: https://travis-ci.org/ljharb/qs
[5]: https://david-dm.org/ljharb/qs.svg
[6]: https://david-dm.org/ljharb/qs
[7]: https://david-dm.org/ljharb/qs/dev-status.svg
[8]: https://david-dm.org/ljharb/qs?type=dev
[9]: https://ci.testling.com/ljharb/qs.png
[10]: https://ci.testling.com/ljharb/qs
[11]: https://nodei.co/npm/qs.png?downloads=true&stars=true
[license-image]: http://img.shields.io/npm/l/qs.svg
[license-url]: LICENSE
[downloads-image]: http://img.shields.io/npm/dm/qs.svg
[downloads-url]: http://npm-stat.com/charts.html?package=qs

832
node_modules/qs/dist/qs.js generated vendored Normal file
View File

@ -0,0 +1,832 @@
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Qs = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
'use strict';
var replace = String.prototype.replace;
var percentTwenties = /%20/g;
var util = require('./utils');
var Format = {
RFC1738: 'RFC1738',
RFC3986: 'RFC3986'
};
module.exports = util.assign(
{
'default': Format.RFC3986,
formatters: {
RFC1738: function (value) {
return replace.call(value, percentTwenties, '+');
},
RFC3986: function (value) {
return String(value);
}
}
},
Format
);
},{"./utils":5}],2:[function(require,module,exports){
'use strict';
var stringify = require('./stringify');
var parse = require('./parse');
var formats = require('./formats');
module.exports = {
formats: formats,
parse: parse,
stringify: stringify
};
},{"./formats":1,"./parse":3,"./stringify":4}],3:[function(require,module,exports){
'use strict';
var utils = require('./utils');
var has = Object.prototype.hasOwnProperty;
var isArray = Array.isArray;
var defaults = {
allowDots: false,
allowPrototypes: false,
arrayLimit: 20,
charset: 'utf-8',
charsetSentinel: false,
comma: false,
decoder: utils.decode,
delimiter: '&',
depth: 5,
ignoreQueryPrefix: false,
interpretNumericEntities: false,
parameterLimit: 1000,
parseArrays: true,
plainObjects: false,
strictNullHandling: false
};
var interpretNumericEntities = function (str) {
return str.replace(/&#(\d+);/g, function ($0, numberStr) {
return String.fromCharCode(parseInt(numberStr, 10));
});
};
var parseArrayValue = function (val, options) {
if (val && typeof val === 'string' && options.comma && val.indexOf(',') > -1) {
return val.split(',');
}
return val;
};
var maybeMap = function maybeMap(val, fn) {
if (isArray(val)) {
var mapped = [];
for (var i = 0; i < val.length; i += 1) {
mapped.push(fn(val[i]));
}
return mapped;
}
return fn(val);
};
// This is what browsers will submit when the ✓ character occurs in an
// application/x-www-form-urlencoded body and the encoding of the page containing
// the form is iso-8859-1, or when the submitted form has an accept-charset
// attribute of iso-8859-1. Presumably also with other charsets that do not contain
// the ✓ character, such as us-ascii.
var isoSentinel = 'utf8=%26%2310003%3B'; // encodeURIComponent('&#10003;')
// These are the percent-encoded utf-8 octets representing a checkmark, indicating that the request actually is utf-8 encoded.
var charsetSentinel = 'utf8=%E2%9C%93'; // encodeURIComponent('✓')
var parseValues = function parseQueryStringValues(str, options) {
var obj = {};
var cleanStr = options.ignoreQueryPrefix ? str.replace(/^\?/, '') : str;
var limit = options.parameterLimit === Infinity ? undefined : options.parameterLimit;
var parts = cleanStr.split(options.delimiter, limit);
var skipIndex = -1; // Keep track of where the utf8 sentinel was found
var i;
var charset = options.charset;
if (options.charsetSentinel) {
for (i = 0; i < parts.length; ++i) {
if (parts[i].indexOf('utf8=') === 0) {
if (parts[i] === charsetSentinel) {
charset = 'utf-8';
} else if (parts[i] === isoSentinel) {
charset = 'iso-8859-1';
}
skipIndex = i;
i = parts.length; // The eslint settings do not allow break;
}
}
}
for (i = 0; i < parts.length; ++i) {
if (i === skipIndex) {
continue;
}
var part = parts[i];
var bracketEqualsPos = part.indexOf(']=');
var pos = bracketEqualsPos === -1 ? part.indexOf('=') : bracketEqualsPos + 1;
var key, val;
if (pos === -1) {
key = options.decoder(part, defaults.decoder, charset, 'key');
val = options.strictNullHandling ? null : '';
} else {
key = options.decoder(part.slice(0, pos), defaults.decoder, charset, 'key');
val = maybeMap(
parseArrayValue(part.slice(pos + 1), options),
function (encodedVal) {
return options.decoder(encodedVal, defaults.decoder, charset, 'value');
}
);
}
if (val && options.interpretNumericEntities && charset === 'iso-8859-1') {
val = interpretNumericEntities(val);
}
if (part.indexOf('[]=') > -1) {
val = isArray(val) ? [val] : val;
}
if (has.call(obj, key)) {
obj[key] = utils.combine(obj[key], val);
} else {
obj[key] = val;
}
}
return obj;
};
var parseObject = function (chain, val, options, valuesParsed) {
var leaf = valuesParsed ? val : parseArrayValue(val, options);
for (var i = chain.length - 1; i >= 0; --i) {
var obj;
var root = chain[i];
if (root === '[]' && options.parseArrays) {
obj = [].concat(leaf);
} else {
obj = options.plainObjects ? Object.create(null) : {};
var cleanRoot = root.charAt(0) === '[' && root.charAt(root.length - 1) === ']' ? root.slice(1, -1) : root;
var index = parseInt(cleanRoot, 10);
if (!options.parseArrays && cleanRoot === '') {
obj = { 0: leaf };
} else if (
!isNaN(index)
&& root !== cleanRoot
&& String(index) === cleanRoot
&& index >= 0
&& (options.parseArrays && index <= options.arrayLimit)
) {
obj = [];
obj[index] = leaf;
} else {
obj[cleanRoot] = leaf;
}
}
leaf = obj; // eslint-disable-line no-param-reassign
}
return leaf;
};
var parseKeys = function parseQueryStringKeys(givenKey, val, options, valuesParsed) {
if (!givenKey) {
return;
}
// Transform dot notation to bracket notation
var key = options.allowDots ? givenKey.replace(/\.([^.[]+)/g, '[$1]') : givenKey;
// The regex chunks
var brackets = /(\[[^[\]]*])/;
var child = /(\[[^[\]]*])/g;
// Get the parent
var segment = options.depth > 0 && brackets.exec(key);
var parent = segment ? key.slice(0, segment.index) : key;
// Stash the parent if it exists
var keys = [];
if (parent) {
// If we aren't using plain objects, optionally prefix keys that would overwrite object prototype properties
if (!options.plainObjects && has.call(Object.prototype, parent)) {
if (!options.allowPrototypes) {
return;
}
}
keys.push(parent);
}
// Loop through children appending to the array until we hit depth
var i = 0;
while (options.depth > 0 && (segment = child.exec(key)) !== null && i < options.depth) {
i += 1;
if (!options.plainObjects && has.call(Object.prototype, segment[1].slice(1, -1))) {
if (!options.allowPrototypes) {
return;
}
}
keys.push(segment[1]);
}
// If there's a remainder, just add whatever is left
if (segment) {
keys.push('[' + key.slice(segment.index) + ']');
}
return parseObject(keys, val, options, valuesParsed);
};
var normalizeParseOptions = function normalizeParseOptions(opts) {
if (!opts) {
return defaults;
}
if (opts.decoder !== null && opts.decoder !== undefined && typeof opts.decoder !== 'function') {
throw new TypeError('Decoder has to be a function.');
}
if (typeof opts.charset !== 'undefined' && opts.charset !== 'utf-8' && opts.charset !== 'iso-8859-1') {
throw new TypeError('The charset option must be either utf-8, iso-8859-1, or undefined');
}
var charset = typeof opts.charset === 'undefined' ? defaults.charset : opts.charset;
return {
allowDots: typeof opts.allowDots === 'undefined' ? defaults.allowDots : !!opts.allowDots,
allowPrototypes: typeof opts.allowPrototypes === 'boolean' ? opts.allowPrototypes : defaults.allowPrototypes,
arrayLimit: typeof opts.arrayLimit === 'number' ? opts.arrayLimit : defaults.arrayLimit,
charset: charset,
charsetSentinel: typeof opts.charsetSentinel === 'boolean' ? opts.charsetSentinel : defaults.charsetSentinel,
comma: typeof opts.comma === 'boolean' ? opts.comma : defaults.comma,
decoder: typeof opts.decoder === 'function' ? opts.decoder : defaults.decoder,
delimiter: typeof opts.delimiter === 'string' || utils.isRegExp(opts.delimiter) ? opts.delimiter : defaults.delimiter,
// eslint-disable-next-line no-implicit-coercion, no-extra-parens
depth: (typeof opts.depth === 'number' || opts.depth === false) ? +opts.depth : defaults.depth,
ignoreQueryPrefix: opts.ignoreQueryPrefix === true,
interpretNumericEntities: typeof opts.interpretNumericEntities === 'boolean' ? opts.interpretNumericEntities : defaults.interpretNumericEntities,
parameterLimit: typeof opts.parameterLimit === 'number' ? opts.parameterLimit : defaults.parameterLimit,
parseArrays: opts.parseArrays !== false,
plainObjects: typeof opts.plainObjects === 'boolean' ? opts.plainObjects : defaults.plainObjects,
strictNullHandling: typeof opts.strictNullHandling === 'boolean' ? opts.strictNullHandling : defaults.strictNullHandling
};
};
module.exports = function (str, opts) {
var options = normalizeParseOptions(opts);
if (str === '' || str === null || typeof str === 'undefined') {
return options.plainObjects ? Object.create(null) : {};
}
var tempObj = typeof str === 'string' ? parseValues(str, options) : str;
var obj = options.plainObjects ? Object.create(null) : {};
// Iterate over the keys and setup the new object
var keys = Object.keys(tempObj);
for (var i = 0; i < keys.length; ++i) {
var key = keys[i];
var newObj = parseKeys(key, tempObj[key], options, typeof str === 'string');
obj = utils.merge(obj, newObj, options);
}
return utils.compact(obj);
};
},{"./utils":5}],4:[function(require,module,exports){
'use strict';
var utils = require('./utils');
var formats = require('./formats');
var has = Object.prototype.hasOwnProperty;
var arrayPrefixGenerators = {
brackets: function brackets(prefix) {
return prefix + '[]';
},
comma: 'comma',
indices: function indices(prefix, key) {
return prefix + '[' + key + ']';
},
repeat: function repeat(prefix) {
return prefix;
}
};
var isArray = Array.isArray;
var push = Array.prototype.push;
var pushToArray = function (arr, valueOrArray) {
push.apply(arr, isArray(valueOrArray) ? valueOrArray : [valueOrArray]);
};
var toISO = Date.prototype.toISOString;
var defaultFormat = formats['default'];
var defaults = {
addQueryPrefix: false,
allowDots: false,
charset: 'utf-8',
charsetSentinel: false,
delimiter: '&',
encode: true,
encoder: utils.encode,
encodeValuesOnly: false,
format: defaultFormat,
formatter: formats.formatters[defaultFormat],
// deprecated
indices: false,
serializeDate: function serializeDate(date) {
return toISO.call(date);
},
skipNulls: false,
strictNullHandling: false
};
var isNonNullishPrimitive = function isNonNullishPrimitive(v) {
return typeof v === 'string'
|| typeof v === 'number'
|| typeof v === 'boolean'
|| typeof v === 'symbol'
|| typeof v === 'bigint';
};
var stringify = function stringify(
object,
prefix,
generateArrayPrefix,
strictNullHandling,
skipNulls,
encoder,
filter,
sort,
allowDots,
serializeDate,
formatter,
encodeValuesOnly,
charset
) {
var obj = object;
if (typeof filter === 'function') {
obj = filter(prefix, obj);
} else if (obj instanceof Date) {
obj = serializeDate(obj);
} else if (generateArrayPrefix === 'comma' && isArray(obj)) {
obj = obj.join(',');
}
if (obj === null) {
if (strictNullHandling) {
return encoder && !encodeValuesOnly ? encoder(prefix, defaults.encoder, charset, 'key') : prefix;
}
obj = '';
}
if (isNonNullishPrimitive(obj) || utils.isBuffer(obj)) {
if (encoder) {
var keyValue = encodeValuesOnly ? prefix : encoder(prefix, defaults.encoder, charset, 'key');
return [formatter(keyValue) + '=' + formatter(encoder(obj, defaults.encoder, charset, 'value'))];
}
return [formatter(prefix) + '=' + formatter(String(obj))];
}
var values = [];
if (typeof obj === 'undefined') {
return values;
}
var objKeys;
if (isArray(filter)) {
objKeys = filter;
} else {
var keys = Object.keys(obj);
objKeys = sort ? keys.sort(sort) : keys;
}
for (var i = 0; i < objKeys.length; ++i) {
var key = objKeys[i];
if (skipNulls && obj[key] === null) {
continue;
}
if (isArray(obj)) {
pushToArray(values, stringify(
obj[key],
typeof generateArrayPrefix === 'function' ? generateArrayPrefix(prefix, key) : prefix,
generateArrayPrefix,
strictNullHandling,
skipNulls,
encoder,
filter,
sort,
allowDots,
serializeDate,
formatter,
encodeValuesOnly,
charset
));
} else {
pushToArray(values, stringify(
obj[key],
prefix + (allowDots ? '.' + key : '[' + key + ']'),
generateArrayPrefix,
strictNullHandling,
skipNulls,
encoder,
filter,
sort,
allowDots,
serializeDate,
formatter,
encodeValuesOnly,
charset
));
}
}
return values;
};
var normalizeStringifyOptions = function normalizeStringifyOptions(opts) {
if (!opts) {
return defaults;
}
if (opts.encoder !== null && opts.encoder !== undefined && typeof opts.encoder !== 'function') {
throw new TypeError('Encoder has to be a function.');
}
var charset = opts.charset || defaults.charset;
if (typeof opts.charset !== 'undefined' && opts.charset !== 'utf-8' && opts.charset !== 'iso-8859-1') {
throw new TypeError('The charset option must be either utf-8, iso-8859-1, or undefined');
}
var format = formats['default'];
if (typeof opts.format !== 'undefined') {
if (!has.call(formats.formatters, opts.format)) {
throw new TypeError('Unknown format option provided.');
}
format = opts.format;
}
var formatter = formats.formatters[format];
var filter = defaults.filter;
if (typeof opts.filter === 'function' || isArray(opts.filter)) {
filter = opts.filter;
}
return {
addQueryPrefix: typeof opts.addQueryPrefix === 'boolean' ? opts.addQueryPrefix : defaults.addQueryPrefix,
allowDots: typeof opts.allowDots === 'undefined' ? defaults.allowDots : !!opts.allowDots,
charset: charset,
charsetSentinel: typeof opts.charsetSentinel === 'boolean' ? opts.charsetSentinel : defaults.charsetSentinel,
delimiter: typeof opts.delimiter === 'undefined' ? defaults.delimiter : opts.delimiter,
encode: typeof opts.encode === 'boolean' ? opts.encode : defaults.encode,
encoder: typeof opts.encoder === 'function' ? opts.encoder : defaults.encoder,
encodeValuesOnly: typeof opts.encodeValuesOnly === 'boolean' ? opts.encodeValuesOnly : defaults.encodeValuesOnly,
filter: filter,
formatter: formatter,
serializeDate: typeof opts.serializeDate === 'function' ? opts.serializeDate : defaults.serializeDate,
skipNulls: typeof opts.skipNulls === 'boolean' ? opts.skipNulls : defaults.skipNulls,
sort: typeof opts.sort === 'function' ? opts.sort : null,
strictNullHandling: typeof opts.strictNullHandling === 'boolean' ? opts.strictNullHandling : defaults.strictNullHandling
};
};
module.exports = function (object, opts) {
var obj = object;
var options = normalizeStringifyOptions(opts);
var objKeys;
var filter;
if (typeof options.filter === 'function') {
filter = options.filter;
obj = filter('', obj);
} else if (isArray(options.filter)) {
filter = options.filter;
objKeys = filter;
}
var keys = [];
if (typeof obj !== 'object' || obj === null) {
return '';
}
var arrayFormat;
if (opts && opts.arrayFormat in arrayPrefixGenerators) {
arrayFormat = opts.arrayFormat;
} else if (opts && 'indices' in opts) {
arrayFormat = opts.indices ? 'indices' : 'repeat';
} else {
arrayFormat = 'indices';
}
var generateArrayPrefix = arrayPrefixGenerators[arrayFormat];
if (!objKeys) {
objKeys = Object.keys(obj);
}
if (options.sort) {
objKeys.sort(options.sort);
}
for (var i = 0; i < objKeys.length; ++i) {
var key = objKeys[i];
if (options.skipNulls && obj[key] === null) {
continue;
}
pushToArray(keys, stringify(
obj[key],
key,
generateArrayPrefix,
options.strictNullHandling,
options.skipNulls,
options.encode ? options.encoder : null,
options.filter,
options.sort,
options.allowDots,
options.serializeDate,
options.formatter,
options.encodeValuesOnly,
options.charset
));
}
var joined = keys.join(options.delimiter);
var prefix = options.addQueryPrefix === true ? '?' : '';
if (options.charsetSentinel) {
if (options.charset === 'iso-8859-1') {
// encodeURIComponent('&#10003;'), the "numeric entity" representation of a checkmark
prefix += 'utf8=%26%2310003%3B&';
} else {
// encodeURIComponent('✓')
prefix += 'utf8=%E2%9C%93&';
}
}
return joined.length > 0 ? prefix + joined : '';
};
},{"./formats":1,"./utils":5}],5:[function(require,module,exports){
'use strict';
var has = Object.prototype.hasOwnProperty;
var isArray = Array.isArray;
var hexTable = (function () {
var array = [];
for (var i = 0; i < 256; ++i) {
array.push('%' + ((i < 16 ? '0' : '') + i.toString(16)).toUpperCase());
}
return array;
}());
var compactQueue = function compactQueue(queue) {
while (queue.length > 1) {
var item = queue.pop();
var obj = item.obj[item.prop];
if (isArray(obj)) {
var compacted = [];
for (var j = 0; j < obj.length; ++j) {
if (typeof obj[j] !== 'undefined') {
compacted.push(obj[j]);
}
}
item.obj[item.prop] = compacted;
}
}
};
var arrayToObject = function arrayToObject(source, options) {
var obj = options && options.plainObjects ? Object.create(null) : {};
for (var i = 0; i < source.length; ++i) {
if (typeof source[i] !== 'undefined') {
obj[i] = source[i];
}
}
return obj;
};
var merge = function merge(target, source, options) {
/* eslint no-param-reassign: 0 */
if (!source) {
return target;
}
if (typeof source !== 'object') {
if (isArray(target)) {
target.push(source);
} else if (target && typeof target === 'object') {
if ((options && (options.plainObjects || options.allowPrototypes)) || !has.call(Object.prototype, source)) {
target[source] = true;
}
} else {
return [target, source];
}
return target;
}
if (!target || typeof target !== 'object') {
return [target].concat(source);
}
var mergeTarget = target;
if (isArray(target) && !isArray(source)) {
mergeTarget = arrayToObject(target, options);
}
if (isArray(target) && isArray(source)) {
source.forEach(function (item, i) {
if (has.call(target, i)) {
var targetItem = target[i];
if (targetItem && typeof targetItem === 'object' && item && typeof item === 'object') {
target[i] = merge(targetItem, item, options);
} else {
target.push(item);
}
} else {
target[i] = item;
}
});
return target;
}
return Object.keys(source).reduce(function (acc, key) {
var value = source[key];
if (has.call(acc, key)) {
acc[key] = merge(acc[key], value, options);
} else {
acc[key] = value;
}
return acc;
}, mergeTarget);
};
var assign = function assignSingleSource(target, source) {
return Object.keys(source).reduce(function (acc, key) {
acc[key] = source[key];
return acc;
}, target);
};
var decode = function (str, decoder, charset) {
var strWithoutPlus = str.replace(/\+/g, ' ');
if (charset === 'iso-8859-1') {
// unescape never throws, no try...catch needed:
return strWithoutPlus.replace(/%[0-9a-f]{2}/gi, unescape);
}
// utf-8
try {
return decodeURIComponent(strWithoutPlus);
} catch (e) {
return strWithoutPlus;
}
};
var encode = function encode(str, defaultEncoder, charset) {
// This code was originally written by Brian White (mscdex) for the io.js core querystring library.
// It has been adapted here for stricter adherence to RFC 3986
if (str.length === 0) {
return str;
}
var string = str;
if (typeof str === 'symbol') {
string = Symbol.prototype.toString.call(str);
} else if (typeof str !== 'string') {
string = String(str);
}
if (charset === 'iso-8859-1') {
return escape(string).replace(/%u[0-9a-f]{4}/gi, function ($0) {
return '%26%23' + parseInt($0.slice(2), 16) + '%3B';
});
}
var out = '';
for (var i = 0; i < string.length; ++i) {
var c = string.charCodeAt(i);
if (
c === 0x2D // -
|| c === 0x2E // .
|| c === 0x5F // _
|| c === 0x7E // ~
|| (c >= 0x30 && c <= 0x39) // 0-9
|| (c >= 0x41 && c <= 0x5A) // a-z
|| (c >= 0x61 && c <= 0x7A) // A-Z
) {
out += string.charAt(i);
continue;
}
if (c < 0x80) {
out = out + hexTable[c];
continue;
}
if (c < 0x800) {
out = out + (hexTable[0xC0 | (c >> 6)] + hexTable[0x80 | (c & 0x3F)]);
continue;
}
if (c < 0xD800 || c >= 0xE000) {
out = out + (hexTable[0xE0 | (c >> 12)] + hexTable[0x80 | ((c >> 6) & 0x3F)] + hexTable[0x80 | (c & 0x3F)]);
continue;
}
i += 1;
c = 0x10000 + (((c & 0x3FF) << 10) | (string.charCodeAt(i) & 0x3FF));
out += hexTable[0xF0 | (c >> 18)]
+ hexTable[0x80 | ((c >> 12) & 0x3F)]
+ hexTable[0x80 | ((c >> 6) & 0x3F)]
+ hexTable[0x80 | (c & 0x3F)];
}
return out;
};
var compact = function compact(value) {
var queue = [{ obj: { o: value }, prop: 'o' }];
var refs = [];
for (var i = 0; i < queue.length; ++i) {
var item = queue[i];
var obj = item.obj[item.prop];
var keys = Object.keys(obj);
for (var j = 0; j < keys.length; ++j) {
var key = keys[j];
var val = obj[key];
if (typeof val === 'object' && val !== null && refs.indexOf(val) === -1) {
queue.push({ obj: obj, prop: key });
refs.push(val);
}
}
}
compactQueue(queue);
return value;
};
var isRegExp = function isRegExp(obj) {
return Object.prototype.toString.call(obj) === '[object RegExp]';
};
var isBuffer = function isBuffer(obj) {
if (!obj || typeof obj !== 'object') {
return false;
}
return !!(obj.constructor && obj.constructor.isBuffer && obj.constructor.isBuffer(obj));
};
var combine = function combine(a, b) {
return [].concat(a, b);
};
module.exports = {
arrayToObject: arrayToObject,
assign: assign,
combine: combine,
compact: compact,
decode: decode,
encode: encode,
isBuffer: isBuffer,
isRegExp: isRegExp,
merge: merge
};
},{}]},{},[2])(2)
});

26
node_modules/qs/lib/formats.js generated vendored Normal file
View File

@ -0,0 +1,26 @@
'use strict';
var replace = String.prototype.replace;
var percentTwenties = /%20/g;
var util = require('./utils');
var Format = {
RFC1738: 'RFC1738',
RFC3986: 'RFC3986'
};
module.exports = util.assign(
{
'default': Format.RFC3986,
formatters: {
RFC1738: function (value) {
return replace.call(value, percentTwenties, '+');
},
RFC3986: function (value) {
return String(value);
}
}
},
Format
);

11
node_modules/qs/lib/index.js generated vendored Normal file
View File

@ -0,0 +1,11 @@
'use strict';
var stringify = require('./stringify');
var parse = require('./parse');
var formats = require('./formats');
module.exports = {
formats: formats,
parse: parse,
stringify: stringify
};

268
node_modules/qs/lib/parse.js generated vendored Normal file
View File

@ -0,0 +1,268 @@
'use strict';
var utils = require('./utils');
var has = Object.prototype.hasOwnProperty;
var isArray = Array.isArray;
var defaults = {
allowDots: false,
allowPrototypes: false,
arrayLimit: 20,
charset: 'utf-8',
charsetSentinel: false,
comma: false,
decoder: utils.decode,
delimiter: '&',
depth: 5,
ignoreQueryPrefix: false,
interpretNumericEntities: false,
parameterLimit: 1000,
parseArrays: true,
plainObjects: false,
strictNullHandling: false
};
var interpretNumericEntities = function (str) {
return str.replace(/&#(\d+);/g, function ($0, numberStr) {
return String.fromCharCode(parseInt(numberStr, 10));
});
};
var parseArrayValue = function (val, options) {
if (val && typeof val === 'string' && options.comma && val.indexOf(',') > -1) {
return val.split(',');
}
return val;
};
var maybeMap = function maybeMap(val, fn) {
if (isArray(val)) {
var mapped = [];
for (var i = 0; i < val.length; i += 1) {
mapped.push(fn(val[i]));
}
return mapped;
}
return fn(val);
};
// This is what browsers will submit when the ✓ character occurs in an
// application/x-www-form-urlencoded body and the encoding of the page containing
// the form is iso-8859-1, or when the submitted form has an accept-charset
// attribute of iso-8859-1. Presumably also with other charsets that do not contain
// the ✓ character, such as us-ascii.
var isoSentinel = 'utf8=%26%2310003%3B'; // encodeURIComponent('&#10003;')
// These are the percent-encoded utf-8 octets representing a checkmark, indicating that the request actually is utf-8 encoded.
var charsetSentinel = 'utf8=%E2%9C%93'; // encodeURIComponent('✓')
var parseValues = function parseQueryStringValues(str, options) {
var obj = {};
var cleanStr = options.ignoreQueryPrefix ? str.replace(/^\?/, '') : str;
var limit = options.parameterLimit === Infinity ? undefined : options.parameterLimit;
var parts = cleanStr.split(options.delimiter, limit);
var skipIndex = -1; // Keep track of where the utf8 sentinel was found
var i;
var charset = options.charset;
if (options.charsetSentinel) {
for (i = 0; i < parts.length; ++i) {
if (parts[i].indexOf('utf8=') === 0) {
if (parts[i] === charsetSentinel) {
charset = 'utf-8';
} else if (parts[i] === isoSentinel) {
charset = 'iso-8859-1';
}
skipIndex = i;
i = parts.length; // The eslint settings do not allow break;
}
}
}
for (i = 0; i < parts.length; ++i) {
if (i === skipIndex) {
continue;
}
var part = parts[i];
var bracketEqualsPos = part.indexOf(']=');
var pos = bracketEqualsPos === -1 ? part.indexOf('=') : bracketEqualsPos + 1;
var key, val;
if (pos === -1) {
key = options.decoder(part, defaults.decoder, charset, 'key');
val = options.strictNullHandling ? null : '';
} else {
key = options.decoder(part.slice(0, pos), defaults.decoder, charset, 'key');
val = maybeMap(
parseArrayValue(part.slice(pos + 1), options),
function (encodedVal) {
return options.decoder(encodedVal, defaults.decoder, charset, 'value');
}
);
}
if (val && options.interpretNumericEntities && charset === 'iso-8859-1') {
val = interpretNumericEntities(val);
}
if (part.indexOf('[]=') > -1) {
val = isArray(val) ? [val] : val;
}
if (has.call(obj, key)) {
obj[key] = utils.combine(obj[key], val);
} else {
obj[key] = val;
}
}
return obj;
};
var parseObject = function (chain, val, options, valuesParsed) {
var leaf = valuesParsed ? val : parseArrayValue(val, options);
for (var i = chain.length - 1; i >= 0; --i) {
var obj;
var root = chain[i];
if (root === '[]' && options.parseArrays) {
obj = [].concat(leaf);
} else {
obj = options.plainObjects ? Object.create(null) : {};
var cleanRoot = root.charAt(0) === '[' && root.charAt(root.length - 1) === ']' ? root.slice(1, -1) : root;
var index = parseInt(cleanRoot, 10);
if (!options.parseArrays && cleanRoot === '') {
obj = { 0: leaf };
} else if (
!isNaN(index)
&& root !== cleanRoot
&& String(index) === cleanRoot
&& index >= 0
&& (options.parseArrays && index <= options.arrayLimit)
) {
obj = [];
obj[index] = leaf;
} else {
obj[cleanRoot] = leaf;
}
}
leaf = obj; // eslint-disable-line no-param-reassign
}
return leaf;
};
var parseKeys = function parseQueryStringKeys(givenKey, val, options, valuesParsed) {
if (!givenKey) {
return;
}
// Transform dot notation to bracket notation
var key = options.allowDots ? givenKey.replace(/\.([^.[]+)/g, '[$1]') : givenKey;
// The regex chunks
var brackets = /(\[[^[\]]*])/;
var child = /(\[[^[\]]*])/g;
// Get the parent
var segment = options.depth > 0 && brackets.exec(key);
var parent = segment ? key.slice(0, segment.index) : key;
// Stash the parent if it exists
var keys = [];
if (parent) {
// If we aren't using plain objects, optionally prefix keys that would overwrite object prototype properties
if (!options.plainObjects && has.call(Object.prototype, parent)) {
if (!options.allowPrototypes) {
return;
}
}
keys.push(parent);
}
// Loop through children appending to the array until we hit depth
var i = 0;
while (options.depth > 0 && (segment = child.exec(key)) !== null && i < options.depth) {
i += 1;
if (!options.plainObjects && has.call(Object.prototype, segment[1].slice(1, -1))) {
if (!options.allowPrototypes) {
return;
}
}
keys.push(segment[1]);
}
// If there's a remainder, just add whatever is left
if (segment) {
keys.push('[' + key.slice(segment.index) + ']');
}
return parseObject(keys, val, options, valuesParsed);
};
var normalizeParseOptions = function normalizeParseOptions(opts) {
if (!opts) {
return defaults;
}
if (opts.decoder !== null && opts.decoder !== undefined && typeof opts.decoder !== 'function') {
throw new TypeError('Decoder has to be a function.');
}
if (typeof opts.charset !== 'undefined' && opts.charset !== 'utf-8' && opts.charset !== 'iso-8859-1') {
throw new TypeError('The charset option must be either utf-8, iso-8859-1, or undefined');
}
var charset = typeof opts.charset === 'undefined' ? defaults.charset : opts.charset;
return {
allowDots: typeof opts.allowDots === 'undefined' ? defaults.allowDots : !!opts.allowDots,
allowPrototypes: typeof opts.allowPrototypes === 'boolean' ? opts.allowPrototypes : defaults.allowPrototypes,
arrayLimit: typeof opts.arrayLimit === 'number' ? opts.arrayLimit : defaults.arrayLimit,
charset: charset,
charsetSentinel: typeof opts.charsetSentinel === 'boolean' ? opts.charsetSentinel : defaults.charsetSentinel,
comma: typeof opts.comma === 'boolean' ? opts.comma : defaults.comma,
decoder: typeof opts.decoder === 'function' ? opts.decoder : defaults.decoder,
delimiter: typeof opts.delimiter === 'string' || utils.isRegExp(opts.delimiter) ? opts.delimiter : defaults.delimiter,
// eslint-disable-next-line no-implicit-coercion, no-extra-parens
depth: (typeof opts.depth === 'number' || opts.depth === false) ? +opts.depth : defaults.depth,
ignoreQueryPrefix: opts.ignoreQueryPrefix === true,
interpretNumericEntities: typeof opts.interpretNumericEntities === 'boolean' ? opts.interpretNumericEntities : defaults.interpretNumericEntities,
parameterLimit: typeof opts.parameterLimit === 'number' ? opts.parameterLimit : defaults.parameterLimit,
parseArrays: opts.parseArrays !== false,
plainObjects: typeof opts.plainObjects === 'boolean' ? opts.plainObjects : defaults.plainObjects,
strictNullHandling: typeof opts.strictNullHandling === 'boolean' ? opts.strictNullHandling : defaults.strictNullHandling
};
};
module.exports = function (str, opts) {
var options = normalizeParseOptions(opts);
if (str === '' || str === null || typeof str === 'undefined') {
return options.plainObjects ? Object.create(null) : {};
}
var tempObj = typeof str === 'string' ? parseValues(str, options) : str;
var obj = options.plainObjects ? Object.create(null) : {};
// Iterate over the keys and setup the new object
var keys = Object.keys(tempObj);
for (var i = 0; i < keys.length; ++i) {
var key = keys[i];
var newObj = parseKeys(key, tempObj[key], options, typeof str === 'string');
obj = utils.merge(obj, newObj, options);
}
return utils.compact(obj);
};

279
node_modules/qs/lib/stringify.js generated vendored Normal file
View File

@ -0,0 +1,279 @@
'use strict';
var utils = require('./utils');
var formats = require('./formats');
var has = Object.prototype.hasOwnProperty;
var arrayPrefixGenerators = {
brackets: function brackets(prefix) {
return prefix + '[]';
},
comma: 'comma',
indices: function indices(prefix, key) {
return prefix + '[' + key + ']';
},
repeat: function repeat(prefix) {
return prefix;
}
};
var isArray = Array.isArray;
var push = Array.prototype.push;
var pushToArray = function (arr, valueOrArray) {
push.apply(arr, isArray(valueOrArray) ? valueOrArray : [valueOrArray]);
};
var toISO = Date.prototype.toISOString;
var defaultFormat = formats['default'];
var defaults = {
addQueryPrefix: false,
allowDots: false,
charset: 'utf-8',
charsetSentinel: false,
delimiter: '&',
encode: true,
encoder: utils.encode,
encodeValuesOnly: false,
format: defaultFormat,
formatter: formats.formatters[defaultFormat],
// deprecated
indices: false,
serializeDate: function serializeDate(date) {
return toISO.call(date);
},
skipNulls: false,
strictNullHandling: false
};
var isNonNullishPrimitive = function isNonNullishPrimitive(v) {
return typeof v === 'string'
|| typeof v === 'number'
|| typeof v === 'boolean'
|| typeof v === 'symbol'
|| typeof v === 'bigint';
};
var stringify = function stringify(
object,
prefix,
generateArrayPrefix,
strictNullHandling,
skipNulls,
encoder,
filter,
sort,
allowDots,
serializeDate,
formatter,
encodeValuesOnly,
charset
) {
var obj = object;
if (typeof filter === 'function') {
obj = filter(prefix, obj);
} else if (obj instanceof Date) {
obj = serializeDate(obj);
} else if (generateArrayPrefix === 'comma' && isArray(obj)) {
obj = obj.join(',');
}
if (obj === null) {
if (strictNullHandling) {
return encoder && !encodeValuesOnly ? encoder(prefix, defaults.encoder, charset, 'key') : prefix;
}
obj = '';
}
if (isNonNullishPrimitive(obj) || utils.isBuffer(obj)) {
if (encoder) {
var keyValue = encodeValuesOnly ? prefix : encoder(prefix, defaults.encoder, charset, 'key');
return [formatter(keyValue) + '=' + formatter(encoder(obj, defaults.encoder, charset, 'value'))];
}
return [formatter(prefix) + '=' + formatter(String(obj))];
}
var values = [];
if (typeof obj === 'undefined') {
return values;
}
var objKeys;
if (isArray(filter)) {
objKeys = filter;
} else {
var keys = Object.keys(obj);
objKeys = sort ? keys.sort(sort) : keys;
}
for (var i = 0; i < objKeys.length; ++i) {
var key = objKeys[i];
if (skipNulls && obj[key] === null) {
continue;
}
if (isArray(obj)) {
pushToArray(values, stringify(
obj[key],
typeof generateArrayPrefix === 'function' ? generateArrayPrefix(prefix, key) : prefix,
generateArrayPrefix,
strictNullHandling,
skipNulls,
encoder,
filter,
sort,
allowDots,
serializeDate,
formatter,
encodeValuesOnly,
charset
));
} else {
pushToArray(values, stringify(
obj[key],
prefix + (allowDots ? '.' + key : '[' + key + ']'),
generateArrayPrefix,
strictNullHandling,
skipNulls,
encoder,
filter,
sort,
allowDots,
serializeDate,
formatter,
encodeValuesOnly,
charset
));
}
}
return values;
};
var normalizeStringifyOptions = function normalizeStringifyOptions(opts) {
if (!opts) {
return defaults;
}
if (opts.encoder !== null && opts.encoder !== undefined && typeof opts.encoder !== 'function') {
throw new TypeError('Encoder has to be a function.');
}
var charset = opts.charset || defaults.charset;
if (typeof opts.charset !== 'undefined' && opts.charset !== 'utf-8' && opts.charset !== 'iso-8859-1') {
throw new TypeError('The charset option must be either utf-8, iso-8859-1, or undefined');
}
var format = formats['default'];
if (typeof opts.format !== 'undefined') {
if (!has.call(formats.formatters, opts.format)) {
throw new TypeError('Unknown format option provided.');
}
format = opts.format;
}
var formatter = formats.formatters[format];
var filter = defaults.filter;
if (typeof opts.filter === 'function' || isArray(opts.filter)) {
filter = opts.filter;
}
return {
addQueryPrefix: typeof opts.addQueryPrefix === 'boolean' ? opts.addQueryPrefix : defaults.addQueryPrefix,
allowDots: typeof opts.allowDots === 'undefined' ? defaults.allowDots : !!opts.allowDots,
charset: charset,
charsetSentinel: typeof opts.charsetSentinel === 'boolean' ? opts.charsetSentinel : defaults.charsetSentinel,
delimiter: typeof opts.delimiter === 'undefined' ? defaults.delimiter : opts.delimiter,
encode: typeof opts.encode === 'boolean' ? opts.encode : defaults.encode,
encoder: typeof opts.encoder === 'function' ? opts.encoder : defaults.encoder,
encodeValuesOnly: typeof opts.encodeValuesOnly === 'boolean' ? opts.encodeValuesOnly : defaults.encodeValuesOnly,
filter: filter,
formatter: formatter,
serializeDate: typeof opts.serializeDate === 'function' ? opts.serializeDate : defaults.serializeDate,
skipNulls: typeof opts.skipNulls === 'boolean' ? opts.skipNulls : defaults.skipNulls,
sort: typeof opts.sort === 'function' ? opts.sort : null,
strictNullHandling: typeof opts.strictNullHandling === 'boolean' ? opts.strictNullHandling : defaults.strictNullHandling
};
};
module.exports = function (object, opts) {
var obj = object;
var options = normalizeStringifyOptions(opts);
var objKeys;
var filter;
if (typeof options.filter === 'function') {
filter = options.filter;
obj = filter('', obj);
} else if (isArray(options.filter)) {
filter = options.filter;
objKeys = filter;
}
var keys = [];
if (typeof obj !== 'object' || obj === null) {
return '';
}
var arrayFormat;
if (opts && opts.arrayFormat in arrayPrefixGenerators) {
arrayFormat = opts.arrayFormat;
} else if (opts && 'indices' in opts) {
arrayFormat = opts.indices ? 'indices' : 'repeat';
} else {
arrayFormat = 'indices';
}
var generateArrayPrefix = arrayPrefixGenerators[arrayFormat];
if (!objKeys) {
objKeys = Object.keys(obj);
}
if (options.sort) {
objKeys.sort(options.sort);
}
for (var i = 0; i < objKeys.length; ++i) {
var key = objKeys[i];
if (options.skipNulls && obj[key] === null) {
continue;
}
pushToArray(keys, stringify(
obj[key],
key,
generateArrayPrefix,
options.strictNullHandling,
options.skipNulls,
options.encode ? options.encoder : null,
options.filter,
options.sort,
options.allowDots,
options.serializeDate,
options.formatter,
options.encodeValuesOnly,
options.charset
));
}
var joined = keys.join(options.delimiter);
var prefix = options.addQueryPrefix === true ? '?' : '';
if (options.charsetSentinel) {
if (options.charset === 'iso-8859-1') {
// encodeURIComponent('&#10003;'), the "numeric entity" representation of a checkmark
prefix += 'utf8=%26%2310003%3B&';
} else {
// encodeURIComponent('✓')
prefix += 'utf8=%E2%9C%93&';
}
}
return joined.length > 0 ? prefix + joined : '';
};

236
node_modules/qs/lib/utils.js generated vendored Normal file
View File

@ -0,0 +1,236 @@
'use strict';
var has = Object.prototype.hasOwnProperty;
var isArray = Array.isArray;
var hexTable = (function () {
var array = [];
for (var i = 0; i < 256; ++i) {
array.push('%' + ((i < 16 ? '0' : '') + i.toString(16)).toUpperCase());
}
return array;
}());
var compactQueue = function compactQueue(queue) {
while (queue.length > 1) {
var item = queue.pop();
var obj = item.obj[item.prop];
if (isArray(obj)) {
var compacted = [];
for (var j = 0; j < obj.length; ++j) {
if (typeof obj[j] !== 'undefined') {
compacted.push(obj[j]);
}
}
item.obj[item.prop] = compacted;
}
}
};
var arrayToObject = function arrayToObject(source, options) {
var obj = options && options.plainObjects ? Object.create(null) : {};
for (var i = 0; i < source.length; ++i) {
if (typeof source[i] !== 'undefined') {
obj[i] = source[i];
}
}
return obj;
};
var merge = function merge(target, source, options) {
/* eslint no-param-reassign: 0 */
if (!source) {
return target;
}
if (typeof source !== 'object') {
if (isArray(target)) {
target.push(source);
} else if (target && typeof target === 'object') {
if ((options && (options.plainObjects || options.allowPrototypes)) || !has.call(Object.prototype, source)) {
target[source] = true;
}
} else {
return [target, source];
}
return target;
}
if (!target || typeof target !== 'object') {
return [target].concat(source);
}
var mergeTarget = target;
if (isArray(target) && !isArray(source)) {
mergeTarget = arrayToObject(target, options);
}
if (isArray(target) && isArray(source)) {
source.forEach(function (item, i) {
if (has.call(target, i)) {
var targetItem = target[i];
if (targetItem && typeof targetItem === 'object' && item && typeof item === 'object') {
target[i] = merge(targetItem, item, options);
} else {
target.push(item);
}
} else {
target[i] = item;
}
});
return target;
}
return Object.keys(source).reduce(function (acc, key) {
var value = source[key];
if (has.call(acc, key)) {
acc[key] = merge(acc[key], value, options);
} else {
acc[key] = value;
}
return acc;
}, mergeTarget);
};
var assign = function assignSingleSource(target, source) {
return Object.keys(source).reduce(function (acc, key) {
acc[key] = source[key];
return acc;
}, target);
};
var decode = function (str, decoder, charset) {
var strWithoutPlus = str.replace(/\+/g, ' ');
if (charset === 'iso-8859-1') {
// unescape never throws, no try...catch needed:
return strWithoutPlus.replace(/%[0-9a-f]{2}/gi, unescape);
}
// utf-8
try {
return decodeURIComponent(strWithoutPlus);
} catch (e) {
return strWithoutPlus;
}
};
var encode = function encode(str, defaultEncoder, charset) {
// This code was originally written by Brian White (mscdex) for the io.js core querystring library.
// It has been adapted here for stricter adherence to RFC 3986
if (str.length === 0) {
return str;
}
var string = str;
if (typeof str === 'symbol') {
string = Symbol.prototype.toString.call(str);
} else if (typeof str !== 'string') {
string = String(str);
}
if (charset === 'iso-8859-1') {
return escape(string).replace(/%u[0-9a-f]{4}/gi, function ($0) {
return '%26%23' + parseInt($0.slice(2), 16) + '%3B';
});
}
var out = '';
for (var i = 0; i < string.length; ++i) {
var c = string.charCodeAt(i);
if (
c === 0x2D // -
|| c === 0x2E // .
|| c === 0x5F // _
|| c === 0x7E // ~
|| (c >= 0x30 && c <= 0x39) // 0-9
|| (c >= 0x41 && c <= 0x5A) // a-z
|| (c >= 0x61 && c <= 0x7A) // A-Z
) {
out += string.charAt(i);
continue;
}
if (c < 0x80) {
out = out + hexTable[c];
continue;
}
if (c < 0x800) {
out = out + (hexTable[0xC0 | (c >> 6)] + hexTable[0x80 | (c & 0x3F)]);
continue;
}
if (c < 0xD800 || c >= 0xE000) {
out = out + (hexTable[0xE0 | (c >> 12)] + hexTable[0x80 | ((c >> 6) & 0x3F)] + hexTable[0x80 | (c & 0x3F)]);
continue;
}
i += 1;
c = 0x10000 + (((c & 0x3FF) << 10) | (string.charCodeAt(i) & 0x3FF));
out += hexTable[0xF0 | (c >> 18)]
+ hexTable[0x80 | ((c >> 12) & 0x3F)]
+ hexTable[0x80 | ((c >> 6) & 0x3F)]
+ hexTable[0x80 | (c & 0x3F)];
}
return out;
};
var compact = function compact(value) {
var queue = [{ obj: { o: value }, prop: 'o' }];
var refs = [];
for (var i = 0; i < queue.length; ++i) {
var item = queue[i];
var obj = item.obj[item.prop];
var keys = Object.keys(obj);
for (var j = 0; j < keys.length; ++j) {
var key = keys[j];
var val = obj[key];
if (typeof val === 'object' && val !== null && refs.indexOf(val) === -1) {
queue.push({ obj: obj, prop: key });
refs.push(val);
}
}
}
compactQueue(queue);
return value;
};
var isRegExp = function isRegExp(obj) {
return Object.prototype.toString.call(obj) === '[object RegExp]';
};
var isBuffer = function isBuffer(obj) {
if (!obj || typeof obj !== 'object') {
return false;
}
return !!(obj.constructor && obj.constructor.isBuffer && obj.constructor.isBuffer(obj));
};
var combine = function combine(a, b) {
return [].concat(a, b);
};
module.exports = {
arrayToObject: arrayToObject,
assign: assign,
combine: combine,
compact: compact,
decode: decode,
encode: encode,
isBuffer: isBuffer,
isRegExp: isRegExp,
merge: merge
};

69
node_modules/qs/package.json generated vendored Normal file
View File

@ -0,0 +1,69 @@
{
"name": "qs",
"description": "A querystring parser that supports nesting and arrays, with a depth limit",
"homepage": "https://github.com/ljharb/qs",
"version": "6.9.3",
"repository": {
"type": "git",
"url": "https://github.com/ljharb/qs.git"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
},
"main": "lib/index.js",
"contributors": [
{
"name": "Jordan Harband",
"email": "ljharb@gmail.com",
"url": "http://ljharb.codes"
}
],
"keywords": [
"querystring",
"qs",
"query",
"url",
"parse",
"stringify"
],
"engines": {
"node": ">=0.6"
},
"dependencies": {},
"devDependencies": {
"@ljharb/eslint-config": "^16.0.0",
"browserify": "^16.5.0",
"covert": "^1.1.1",
"eclint": "^2.8.1",
"eslint": "^6.8.0",
"evalmd": "^0.0.19",
"for-each": "^0.3.3",
"has-symbols": "^1.0.1",
"iconv-lite": "^0.5.1",
"mkdirp": "^0.5.4",
"object-inspect": "^1.7.0",
"qs-iconv": "^1.0.4",
"safe-publish-latest": "^1.1.4",
"safer-buffer": "^2.1.2",
"tape": "^5.0.0-next.5"
},
"scripts": {
"prepublish": "safe-publish-latest && npm run dist",
"pretest": "npm run --silent readme && npm run --silent lint",
"test": "npm run --silent coverage",
"tests-only": "node test",
"posttest": "npx aud --production",
"readme": "evalmd README.md",
"postlint": "eclint check * lib/* test/*",
"lint": "eslint lib/*.js test/*.js",
"coverage": "covert test",
"dist": "mkdirp dist && browserify --standalone Qs lib/index.js > dist/qs.js"
},
"license": "BSD-3-Clause",
"greenkeeper": {
"ignore": [
"iconv-lite",
"mkdirp"
]
}
}

18
node_modules/qs/test/.eslintrc generated vendored Normal file
View File

@ -0,0 +1,18 @@
{
"rules": {
"array-bracket-newline": 0,
"array-element-newline": 0,
"consistent-return": 2,
"function-paren-newline": 0,
"max-lines": 0,
"max-lines-per-function": 0,
"max-nested-callbacks": [2, 3],
"max-statements": 0,
"no-buffer-constructor": 0,
"no-extend-native": 0,
"no-magic-numbers": 0,
"no-throw-literal": 0,
"object-curly-newline": 0,
"sort-keys": 0,
}
}

7
node_modules/qs/test/index.js generated vendored Normal file
View File

@ -0,0 +1,7 @@
'use strict';
require('./parse');
require('./stringify');
require('./utils');

772
node_modules/qs/test/parse.js generated vendored Normal file
View File

@ -0,0 +1,772 @@
'use strict';
var test = require('tape');
var qs = require('../');
var utils = require('../lib/utils');
var iconv = require('iconv-lite');
var SaferBuffer = require('safer-buffer').Buffer;
test('parse()', function (t) {
t.test('parses a simple string', function (st) {
st.deepEqual(qs.parse('0=foo'), { 0: 'foo' });
st.deepEqual(qs.parse('foo=c++'), { foo: 'c ' });
st.deepEqual(qs.parse('a[>=]=23'), { a: { '>=': '23' } });
st.deepEqual(qs.parse('a[<=>]==23'), { a: { '<=>': '=23' } });
st.deepEqual(qs.parse('a[==]=23'), { a: { '==': '23' } });
st.deepEqual(qs.parse('foo', { strictNullHandling: true }), { foo: null });
st.deepEqual(qs.parse('foo'), { foo: '' });
st.deepEqual(qs.parse('foo='), { foo: '' });
st.deepEqual(qs.parse('foo=bar'), { foo: 'bar' });
st.deepEqual(qs.parse(' foo = bar = baz '), { ' foo ': ' bar = baz ' });
st.deepEqual(qs.parse('foo=bar=baz'), { foo: 'bar=baz' });
st.deepEqual(qs.parse('foo=bar&bar=baz'), { foo: 'bar', bar: 'baz' });
st.deepEqual(qs.parse('foo2=bar2&baz2='), { foo2: 'bar2', baz2: '' });
st.deepEqual(qs.parse('foo=bar&baz', { strictNullHandling: true }), { foo: 'bar', baz: null });
st.deepEqual(qs.parse('foo=bar&baz'), { foo: 'bar', baz: '' });
st.deepEqual(qs.parse('cht=p3&chd=t:60,40&chs=250x100&chl=Hello|World'), {
cht: 'p3',
chd: 't:60,40',
chs: '250x100',
chl: 'Hello|World'
});
st.end();
});
t.test('arrayFormat: brackets allows only explicit arrays', function (st) {
st.deepEqual(qs.parse('a[]=b&a[]=c', { arrayFormat: 'brackets' }), { a: ['b', 'c'] });
st.deepEqual(qs.parse('a[0]=b&a[1]=c', { arrayFormat: 'brackets' }), { a: ['b', 'c'] });
st.deepEqual(qs.parse('a=b,c', { arrayFormat: 'brackets' }), { a: 'b,c' });
st.deepEqual(qs.parse('a=b&a=c', { arrayFormat: 'brackets' }), { a: ['b', 'c'] });
st.end();
});
t.test('arrayFormat: indices allows only indexed arrays', function (st) {
st.deepEqual(qs.parse('a[]=b&a[]=c', { arrayFormat: 'indices' }), { a: ['b', 'c'] });
st.deepEqual(qs.parse('a[0]=b&a[1]=c', { arrayFormat: 'indices' }), { a: ['b', 'c'] });
st.deepEqual(qs.parse('a=b,c', { arrayFormat: 'indices' }), { a: 'b,c' });
st.deepEqual(qs.parse('a=b&a=c', { arrayFormat: 'indices' }), { a: ['b', 'c'] });
st.end();
});
t.test('arrayFormat: comma allows only comma-separated arrays', function (st) {
st.deepEqual(qs.parse('a[]=b&a[]=c', { arrayFormat: 'comma' }), { a: ['b', 'c'] });
st.deepEqual(qs.parse('a[0]=b&a[1]=c', { arrayFormat: 'comma' }), { a: ['b', 'c'] });
st.deepEqual(qs.parse('a=b,c', { arrayFormat: 'comma' }), { a: 'b,c' });
st.deepEqual(qs.parse('a=b&a=c', { arrayFormat: 'comma' }), { a: ['b', 'c'] });
st.end();
});
t.test('arrayFormat: repeat allows only repeated values', function (st) {
st.deepEqual(qs.parse('a[]=b&a[]=c', { arrayFormat: 'repeat' }), { a: ['b', 'c'] });
st.deepEqual(qs.parse('a[0]=b&a[1]=c', { arrayFormat: 'repeat' }), { a: ['b', 'c'] });
st.deepEqual(qs.parse('a=b,c', { arrayFormat: 'repeat' }), { a: 'b,c' });
st.deepEqual(qs.parse('a=b&a=c', { arrayFormat: 'repeat' }), { a: ['b', 'c'] });
st.end();
});
t.test('allows enabling dot notation', function (st) {
st.deepEqual(qs.parse('a.b=c'), { 'a.b': 'c' });
st.deepEqual(qs.parse('a.b=c', { allowDots: true }), { a: { b: 'c' } });
st.end();
});
t.deepEqual(qs.parse('a[b]=c'), { a: { b: 'c' } }, 'parses a single nested string');
t.deepEqual(qs.parse('a[b][c]=d'), { a: { b: { c: 'd' } } }, 'parses a double nested string');
t.deepEqual(
qs.parse('a[b][c][d][e][f][g][h]=i'),
{ a: { b: { c: { d: { e: { f: { '[g][h]': 'i' } } } } } } },
'defaults to a depth of 5'
);
t.test('only parses one level when depth = 1', function (st) {
st.deepEqual(qs.parse('a[b][c]=d', { depth: 1 }), { a: { b: { '[c]': 'd' } } });
st.deepEqual(qs.parse('a[b][c][d]=e', { depth: 1 }), { a: { b: { '[c][d]': 'e' } } });
st.end();
});
t.test('uses original key when depth = 0', function (st) {
st.deepEqual(qs.parse('a[0]=b&a[1]=c', { depth: 0 }), { 'a[0]': 'b', 'a[1]': 'c' });
st.deepEqual(qs.parse('a[0][0]=b&a[0][1]=c&a[1]=d&e=2', { depth: 0 }), { 'a[0][0]': 'b', 'a[0][1]': 'c', 'a[1]': 'd', e: '2' });
st.end();
});
t.test('uses original key when depth = false', function (st) {
st.deepEqual(qs.parse('a[0]=b&a[1]=c', { depth: false }), { 'a[0]': 'b', 'a[1]': 'c' });
st.deepEqual(qs.parse('a[0][0]=b&a[0][1]=c&a[1]=d&e=2', { depth: false }), { 'a[0][0]': 'b', 'a[0][1]': 'c', 'a[1]': 'd', e: '2' });
st.end();
});
t.deepEqual(qs.parse('a=b&a=c'), { a: ['b', 'c'] }, 'parses a simple array');
t.test('parses an explicit array', function (st) {
st.deepEqual(qs.parse('a[]=b'), { a: ['b'] });
st.deepEqual(qs.parse('a[]=b&a[]=c'), { a: ['b', 'c'] });
st.deepEqual(qs.parse('a[]=b&a[]=c&a[]=d'), { a: ['b', 'c', 'd'] });
st.end();
});
t.test('parses a mix of simple and explicit arrays', function (st) {
st.deepEqual(qs.parse('a=b&a[]=c'), { a: ['b', 'c'] });
st.deepEqual(qs.parse('a[]=b&a=c'), { a: ['b', 'c'] });
st.deepEqual(qs.parse('a[0]=b&a=c'), { a: ['b', 'c'] });
st.deepEqual(qs.parse('a=b&a[0]=c'), { a: ['b', 'c'] });
st.deepEqual(qs.parse('a[1]=b&a=c', { arrayLimit: 20 }), { a: ['b', 'c'] });
st.deepEqual(qs.parse('a[]=b&a=c', { arrayLimit: 0 }), { a: ['b', 'c'] });
st.deepEqual(qs.parse('a[]=b&a=c'), { a: ['b', 'c'] });
st.deepEqual(qs.parse('a=b&a[1]=c', { arrayLimit: 20 }), { a: ['b', 'c'] });
st.deepEqual(qs.parse('a=b&a[]=c', { arrayLimit: 0 }), { a: ['b', 'c'] });
st.deepEqual(qs.parse('a=b&a[]=c'), { a: ['b', 'c'] });
st.end();
});
t.test('parses a nested array', function (st) {
st.deepEqual(qs.parse('a[b][]=c&a[b][]=d'), { a: { b: ['c', 'd'] } });
st.deepEqual(qs.parse('a[>=]=25'), { a: { '>=': '25' } });
st.end();
});
t.test('allows to specify array indices', function (st) {
st.deepEqual(qs.parse('a[1]=c&a[0]=b&a[2]=d'), { a: ['b', 'c', 'd'] });
st.deepEqual(qs.parse('a[1]=c&a[0]=b'), { a: ['b', 'c'] });
st.deepEqual(qs.parse('a[1]=c', { arrayLimit: 20 }), { a: ['c'] });
st.deepEqual(qs.parse('a[1]=c', { arrayLimit: 0 }), { a: { 1: 'c' } });
st.deepEqual(qs.parse('a[1]=c'), { a: ['c'] });
st.end();
});
t.test('limits specific array indices to arrayLimit', function (st) {
st.deepEqual(qs.parse('a[20]=a', { arrayLimit: 20 }), { a: ['a'] });
st.deepEqual(qs.parse('a[21]=a', { arrayLimit: 20 }), { a: { 21: 'a' } });
st.end();
});
t.deepEqual(qs.parse('a[12b]=c'), { a: { '12b': 'c' } }, 'supports keys that begin with a number');
t.test('supports encoded = signs', function (st) {
st.deepEqual(qs.parse('he%3Dllo=th%3Dere'), { 'he=llo': 'th=ere' });
st.end();
});
t.test('is ok with url encoded strings', function (st) {
st.deepEqual(qs.parse('a[b%20c]=d'), { a: { 'b c': 'd' } });
st.deepEqual(qs.parse('a[b]=c%20d'), { a: { b: 'c d' } });
st.end();
});
t.test('allows brackets in the value', function (st) {
st.deepEqual(qs.parse('pets=["tobi"]'), { pets: '["tobi"]' });
st.deepEqual(qs.parse('operators=[">=", "<="]'), { operators: '[">=", "<="]' });
st.end();
});
t.test('allows empty values', function (st) {
st.deepEqual(qs.parse(''), {});
st.deepEqual(qs.parse(null), {});
st.deepEqual(qs.parse(undefined), {});
st.end();
});
t.test('transforms arrays to objects', function (st) {
st.deepEqual(qs.parse('foo[0]=bar&foo[bad]=baz'), { foo: { 0: 'bar', bad: 'baz' } });
st.deepEqual(qs.parse('foo[bad]=baz&foo[0]=bar'), { foo: { bad: 'baz', 0: 'bar' } });
st.deepEqual(qs.parse('foo[bad]=baz&foo[]=bar'), { foo: { bad: 'baz', 0: 'bar' } });
st.deepEqual(qs.parse('foo[]=bar&foo[bad]=baz'), { foo: { 0: 'bar', bad: 'baz' } });
st.deepEqual(qs.parse('foo[bad]=baz&foo[]=bar&foo[]=foo'), { foo: { bad: 'baz', 0: 'bar', 1: 'foo' } });
st.deepEqual(qs.parse('foo[0][a]=a&foo[0][b]=b&foo[1][a]=aa&foo[1][b]=bb'), { foo: [{ a: 'a', b: 'b' }, { a: 'aa', b: 'bb' }] });
st.deepEqual(qs.parse('a[]=b&a[t]=u&a[hasOwnProperty]=c', { allowPrototypes: false }), { a: { 0: 'b', t: 'u' } });
st.deepEqual(qs.parse('a[]=b&a[t]=u&a[hasOwnProperty]=c', { allowPrototypes: true }), { a: { 0: 'b', t: 'u', hasOwnProperty: 'c' } });
st.deepEqual(qs.parse('a[]=b&a[hasOwnProperty]=c&a[x]=y', { allowPrototypes: false }), { a: { 0: 'b', x: 'y' } });
st.deepEqual(qs.parse('a[]=b&a[hasOwnProperty]=c&a[x]=y', { allowPrototypes: true }), { a: { 0: 'b', hasOwnProperty: 'c', x: 'y' } });
st.end();
});
t.test('transforms arrays to objects (dot notation)', function (st) {
st.deepEqual(qs.parse('foo[0].baz=bar&fool.bad=baz', { allowDots: true }), { foo: [{ baz: 'bar' }], fool: { bad: 'baz' } });
st.deepEqual(qs.parse('foo[0].baz=bar&fool.bad.boo=baz', { allowDots: true }), { foo: [{ baz: 'bar' }], fool: { bad: { boo: 'baz' } } });
st.deepEqual(qs.parse('foo[0][0].baz=bar&fool.bad=baz', { allowDots: true }), { foo: [[{ baz: 'bar' }]], fool: { bad: 'baz' } });
st.deepEqual(qs.parse('foo[0].baz[0]=15&foo[0].bar=2', { allowDots: true }), { foo: [{ baz: ['15'], bar: '2' }] });
st.deepEqual(qs.parse('foo[0].baz[0]=15&foo[0].baz[1]=16&foo[0].bar=2', { allowDots: true }), { foo: [{ baz: ['15', '16'], bar: '2' }] });
st.deepEqual(qs.parse('foo.bad=baz&foo[0]=bar', { allowDots: true }), { foo: { bad: 'baz', 0: 'bar' } });
st.deepEqual(qs.parse('foo.bad=baz&foo[]=bar', { allowDots: true }), { foo: { bad: 'baz', 0: 'bar' } });
st.deepEqual(qs.parse('foo[]=bar&foo.bad=baz', { allowDots: true }), { foo: { 0: 'bar', bad: 'baz' } });
st.deepEqual(qs.parse('foo.bad=baz&foo[]=bar&foo[]=foo', { allowDots: true }), { foo: { bad: 'baz', 0: 'bar', 1: 'foo' } });
st.deepEqual(qs.parse('foo[0].a=a&foo[0].b=b&foo[1].a=aa&foo[1].b=bb', { allowDots: true }), { foo: [{ a: 'a', b: 'b' }, { a: 'aa', b: 'bb' }] });
st.end();
});
t.test('correctly prunes undefined values when converting an array to an object', function (st) {
st.deepEqual(qs.parse('a[2]=b&a[99999999]=c'), { a: { 2: 'b', 99999999: 'c' } });
st.end();
});
t.test('supports malformed uri characters', function (st) {
st.deepEqual(qs.parse('{%:%}', { strictNullHandling: true }), { '{%:%}': null });
st.deepEqual(qs.parse('{%:%}='), { '{%:%}': '' });
st.deepEqual(qs.parse('foo=%:%}'), { foo: '%:%}' });
st.end();
});
t.test('doesn\'t produce empty keys', function (st) {
st.deepEqual(qs.parse('_r=1&'), { _r: '1' });
st.end();
});
t.test('cannot access Object prototype', function (st) {
qs.parse('constructor[prototype][bad]=bad');
qs.parse('bad[constructor][prototype][bad]=bad');
st.equal(typeof Object.prototype.bad, 'undefined');
st.end();
});
t.test('parses arrays of objects', function (st) {
st.deepEqual(qs.parse('a[][b]=c'), { a: [{ b: 'c' }] });
st.deepEqual(qs.parse('a[0][b]=c'), { a: [{ b: 'c' }] });
st.end();
});
t.test('allows for empty strings in arrays', function (st) {
st.deepEqual(qs.parse('a[]=b&a[]=&a[]=c'), { a: ['b', '', 'c'] });
st.deepEqual(
qs.parse('a[0]=b&a[1]&a[2]=c&a[19]=', { strictNullHandling: true, arrayLimit: 20 }),
{ a: ['b', null, 'c', ''] },
'with arrayLimit 20 + array indices: null then empty string works'
);
st.deepEqual(
qs.parse('a[]=b&a[]&a[]=c&a[]=', { strictNullHandling: true, arrayLimit: 0 }),
{ a: ['b', null, 'c', ''] },
'with arrayLimit 0 + array brackets: null then empty string works'
);
st.deepEqual(
qs.parse('a[0]=b&a[1]=&a[2]=c&a[19]', { strictNullHandling: true, arrayLimit: 20 }),
{ a: ['b', '', 'c', null] },
'with arrayLimit 20 + array indices: empty string then null works'
);
st.deepEqual(
qs.parse('a[]=b&a[]=&a[]=c&a[]', { strictNullHandling: true, arrayLimit: 0 }),
{ a: ['b', '', 'c', null] },
'with arrayLimit 0 + array brackets: empty string then null works'
);
st.deepEqual(
qs.parse('a[]=&a[]=b&a[]=c'),
{ a: ['', 'b', 'c'] },
'array brackets: empty strings work'
);
st.end();
});
t.test('compacts sparse arrays', function (st) {
st.deepEqual(qs.parse('a[10]=1&a[2]=2', { arrayLimit: 20 }), { a: ['2', '1'] });
st.deepEqual(qs.parse('a[1][b][2][c]=1', { arrayLimit: 20 }), { a: [{ b: [{ c: '1' }] }] });
st.deepEqual(qs.parse('a[1][2][3][c]=1', { arrayLimit: 20 }), { a: [[[{ c: '1' }]]] });
st.deepEqual(qs.parse('a[1][2][3][c][1]=1', { arrayLimit: 20 }), { a: [[[{ c: ['1'] }]]] });
st.end();
});
t.test('parses semi-parsed strings', function (st) {
st.deepEqual(qs.parse({ 'a[b]': 'c' }), { a: { b: 'c' } });
st.deepEqual(qs.parse({ 'a[b]': 'c', 'a[d]': 'e' }), { a: { b: 'c', d: 'e' } });
st.end();
});
t.test('parses buffers correctly', function (st) {
var b = SaferBuffer.from('test');
st.deepEqual(qs.parse({ a: b }), { a: b });
st.end();
});
t.test('parses jquery-param strings', function (st) {
// readable = 'filter[0][]=int1&filter[0][]==&filter[0][]=77&filter[]=and&filter[2][]=int2&filter[2][]==&filter[2][]=8'
var encoded = 'filter%5B0%5D%5B%5D=int1&filter%5B0%5D%5B%5D=%3D&filter%5B0%5D%5B%5D=77&filter%5B%5D=and&filter%5B2%5D%5B%5D=int2&filter%5B2%5D%5B%5D=%3D&filter%5B2%5D%5B%5D=8';
var expected = { filter: [['int1', '=', '77'], 'and', ['int2', '=', '8']] };
st.deepEqual(qs.parse(encoded), expected);
st.end();
});
t.test('continues parsing when no parent is found', function (st) {
st.deepEqual(qs.parse('[]=&a=b'), { 0: '', a: 'b' });
st.deepEqual(qs.parse('[]&a=b', { strictNullHandling: true }), { 0: null, a: 'b' });
st.deepEqual(qs.parse('[foo]=bar'), { foo: 'bar' });
st.end();
});
t.test('does not error when parsing a very long array', function (st) {
var str = 'a[]=a';
while (Buffer.byteLength(str) < 128 * 1024) {
str = str + '&' + str;
}
st.doesNotThrow(function () {
qs.parse(str);
});
st.end();
});
t.test('should not throw when a native prototype has an enumerable property', function (st) {
Object.prototype.crash = '';
Array.prototype.crash = '';
st.doesNotThrow(qs.parse.bind(null, 'a=b'));
st.deepEqual(qs.parse('a=b'), { a: 'b' });
st.doesNotThrow(qs.parse.bind(null, 'a[][b]=c'));
st.deepEqual(qs.parse('a[][b]=c'), { a: [{ b: 'c' }] });
delete Object.prototype.crash;
delete Array.prototype.crash;
st.end();
});
t.test('parses a string with an alternative string delimiter', function (st) {
st.deepEqual(qs.parse('a=b;c=d', { delimiter: ';' }), { a: 'b', c: 'd' });
st.end();
});
t.test('parses a string with an alternative RegExp delimiter', function (st) {
st.deepEqual(qs.parse('a=b; c=d', { delimiter: /[;,] */ }), { a: 'b', c: 'd' });
st.end();
});
t.test('does not use non-splittable objects as delimiters', function (st) {
st.deepEqual(qs.parse('a=b&c=d', { delimiter: true }), { a: 'b', c: 'd' });
st.end();
});
t.test('allows overriding parameter limit', function (st) {
st.deepEqual(qs.parse('a=b&c=d', { parameterLimit: 1 }), { a: 'b' });
st.end();
});
t.test('allows setting the parameter limit to Infinity', function (st) {
st.deepEqual(qs.parse('a=b&c=d', { parameterLimit: Infinity }), { a: 'b', c: 'd' });
st.end();
});
t.test('allows overriding array limit', function (st) {
st.deepEqual(qs.parse('a[0]=b', { arrayLimit: -1 }), { a: { 0: 'b' } });
st.deepEqual(qs.parse('a[-1]=b', { arrayLimit: -1 }), { a: { '-1': 'b' } });
st.deepEqual(qs.parse('a[0]=b&a[1]=c', { arrayLimit: 0 }), { a: { 0: 'b', 1: 'c' } });
st.end();
});
t.test('allows disabling array parsing', function (st) {
var indices = qs.parse('a[0]=b&a[1]=c', { parseArrays: false });
st.deepEqual(indices, { a: { 0: 'b', 1: 'c' } });
st.equal(Array.isArray(indices.a), false, 'parseArrays:false, indices case is not an array');
var emptyBrackets = qs.parse('a[]=b', { parseArrays: false });
st.deepEqual(emptyBrackets, { a: { 0: 'b' } });
st.equal(Array.isArray(emptyBrackets.a), false, 'parseArrays:false, empty brackets case is not an array');
st.end();
});
t.test('allows for query string prefix', function (st) {
st.deepEqual(qs.parse('?foo=bar', { ignoreQueryPrefix: true }), { foo: 'bar' });
st.deepEqual(qs.parse('foo=bar', { ignoreQueryPrefix: true }), { foo: 'bar' });
st.deepEqual(qs.parse('?foo=bar', { ignoreQueryPrefix: false }), { '?foo': 'bar' });
st.end();
});
t.test('parses an object', function (st) {
var input = {
'user[name]': { 'pop[bob]': 3 },
'user[email]': null
};
var expected = {
user: {
name: { 'pop[bob]': 3 },
email: null
}
};
var result = qs.parse(input);
st.deepEqual(result, expected);
st.end();
});
t.test('parses string with comma as array divider', function (st) {
st.deepEqual(qs.parse('foo=bar,tee', { comma: true }), { foo: ['bar', 'tee'] });
st.deepEqual(qs.parse('foo[bar]=coffee,tee', { comma: true }), { foo: { bar: ['coffee', 'tee'] } });
st.deepEqual(qs.parse('foo=', { comma: true }), { foo: '' });
st.deepEqual(qs.parse('foo', { comma: true }), { foo: '' });
st.deepEqual(qs.parse('foo', { comma: true, strictNullHandling: true }), { foo: null });
st.end();
});
t.test('parses values with comma as array divider', function (st) {
st.deepEqual(qs.parse({ foo: 'bar,tee' }, { comma: false }), { foo: 'bar,tee' });
st.deepEqual(qs.parse({ foo: 'bar,tee' }, { comma: true }), { foo: ['bar', 'tee'] });
st.end();
});
t.test('use number decoder, parses string that has one number with comma option enabled', function (st) {
var decoder = function (str, defaultDecoder, charset, type) {
if (!isNaN(Number(str))) {
return parseFloat(str);
}
return defaultDecoder(str, defaultDecoder, charset, type);
};
st.deepEqual(qs.parse('foo=1', { comma: true, decoder: decoder }), { foo: 1 });
st.deepEqual(qs.parse('foo=0', { comma: true, decoder: decoder }), { foo: 0 });
st.end();
});
t.test('parses brackets holds array of arrays when having two parts of strings with comma as array divider', function (st) {
st.deepEqual(qs.parse('foo[]=1,2,3&foo[]=4,5,6', { comma: true }), { foo: [['1', '2', '3'], ['4', '5', '6']] });
st.deepEqual(qs.parse('foo[]=1,2,3&foo[]=', { comma: true }), { foo: [['1', '2', '3'], ''] });
st.deepEqual(qs.parse('foo[]=1,2,3&foo[]=,', { comma: true }), { foo: [['1', '2', '3'], ['', '']] });
st.deepEqual(qs.parse('foo[]=1,2,3&foo[]=a', { comma: true }), { foo: [['1', '2', '3'], 'a'] });
st.end();
});
t.test('parses comma delimited array while having percent-encoded comma treated as normal text', function (st) {
st.deepEqual(qs.parse('foo=a%2Cb', { comma: true }), { foo: 'a,b' });
st.deepEqual(qs.parse('foo=a%2C%20b,d', { comma: true }), { foo: ['a, b', 'd'] });
st.deepEqual(qs.parse('foo=a%2C%20b,c%2C%20d', { comma: true }), { foo: ['a, b', 'c, d'] });
st.end();
});
t.test('parses an object in dot notation', function (st) {
var input = {
'user.name': { 'pop[bob]': 3 },
'user.email.': null
};
var expected = {
user: {
name: { 'pop[bob]': 3 },
email: null
}
};
var result = qs.parse(input, { allowDots: true });
st.deepEqual(result, expected);
st.end();
});
t.test('parses an object and not child values', function (st) {
var input = {
'user[name]': { 'pop[bob]': { test: 3 } },
'user[email]': null
};
var expected = {
user: {
name: { 'pop[bob]': { test: 3 } },
email: null
}
};
var result = qs.parse(input);
st.deepEqual(result, expected);
st.end();
});
t.test('does not blow up when Buffer global is missing', function (st) {
var tempBuffer = global.Buffer;
delete global.Buffer;
var result = qs.parse('a=b&c=d');
global.Buffer = tempBuffer;
st.deepEqual(result, { a: 'b', c: 'd' });
st.end();
});
t.test('does not crash when parsing circular references', function (st) {
var a = {};
a.b = a;
var parsed;
st.doesNotThrow(function () {
parsed = qs.parse({ 'foo[bar]': 'baz', 'foo[baz]': a });
});
st.equal('foo' in parsed, true, 'parsed has "foo" property');
st.equal('bar' in parsed.foo, true);
st.equal('baz' in parsed.foo, true);
st.equal(parsed.foo.bar, 'baz');
st.deepEqual(parsed.foo.baz, a);
st.end();
});
t.test('does not crash when parsing deep objects', function (st) {
var parsed;
var str = 'foo';
for (var i = 0; i < 5000; i++) {
str += '[p]';
}
str += '=bar';
st.doesNotThrow(function () {
parsed = qs.parse(str, { depth: 5000 });
});
st.equal('foo' in parsed, true, 'parsed has "foo" property');
var depth = 0;
var ref = parsed.foo;
while ((ref = ref.p)) {
depth += 1;
}
st.equal(depth, 5000, 'parsed is 5000 properties deep');
st.end();
});
t.test('parses null objects correctly', { skip: !Object.create }, function (st) {
var a = Object.create(null);
a.b = 'c';
st.deepEqual(qs.parse(a), { b: 'c' });
var result = qs.parse({ a: a });
st.equal('a' in result, true, 'result has "a" property');
st.deepEqual(result.a, a);
st.end();
});
t.test('parses dates correctly', function (st) {
var now = new Date();
st.deepEqual(qs.parse({ a: now }), { a: now });
st.end();
});
t.test('parses regular expressions correctly', function (st) {
var re = /^test$/;
st.deepEqual(qs.parse({ a: re }), { a: re });
st.end();
});
t.test('does not allow overwriting prototype properties', function (st) {
st.deepEqual(qs.parse('a[hasOwnProperty]=b', { allowPrototypes: false }), {});
st.deepEqual(qs.parse('hasOwnProperty=b', { allowPrototypes: false }), {});
st.deepEqual(
qs.parse('toString', { allowPrototypes: false }),
{},
'bare "toString" results in {}'
);
st.end();
});
t.test('can allow overwriting prototype properties', function (st) {
st.deepEqual(qs.parse('a[hasOwnProperty]=b', { allowPrototypes: true }), { a: { hasOwnProperty: 'b' } });
st.deepEqual(qs.parse('hasOwnProperty=b', { allowPrototypes: true }), { hasOwnProperty: 'b' });
st.deepEqual(
qs.parse('toString', { allowPrototypes: true }),
{ toString: '' },
'bare "toString" results in { toString: "" }'
);
st.end();
});
t.test('params starting with a closing bracket', function (st) {
st.deepEqual(qs.parse(']=toString'), { ']': 'toString' });
st.deepEqual(qs.parse(']]=toString'), { ']]': 'toString' });
st.deepEqual(qs.parse(']hello]=toString'), { ']hello]': 'toString' });
st.end();
});
t.test('params starting with a starting bracket', function (st) {
st.deepEqual(qs.parse('[=toString'), { '[': 'toString' });
st.deepEqual(qs.parse('[[=toString'), { '[[': 'toString' });
st.deepEqual(qs.parse('[hello[=toString'), { '[hello[': 'toString' });
st.end();
});
t.test('add keys to objects', function (st) {
st.deepEqual(
qs.parse('a[b]=c&a=d'),
{ a: { b: 'c', d: true } },
'can add keys to objects'
);
st.deepEqual(
qs.parse('a[b]=c&a=toString'),
{ a: { b: 'c' } },
'can not overwrite prototype'
);
st.deepEqual(
qs.parse('a[b]=c&a=toString', { allowPrototypes: true }),
{ a: { b: 'c', toString: true } },
'can overwrite prototype with allowPrototypes true'
);
st.deepEqual(
qs.parse('a[b]=c&a=toString', { plainObjects: true }),
{ __proto__: null, a: { __proto__: null, b: 'c', toString: true } },
'can overwrite prototype with plainObjects true'
);
st.end();
});
t.test('can return null objects', { skip: !Object.create }, function (st) {
var expected = Object.create(null);
expected.a = Object.create(null);
expected.a.b = 'c';
expected.a.hasOwnProperty = 'd';
st.deepEqual(qs.parse('a[b]=c&a[hasOwnProperty]=d', { plainObjects: true }), expected);
st.deepEqual(qs.parse(null, { plainObjects: true }), Object.create(null));
var expectedArray = Object.create(null);
expectedArray.a = Object.create(null);
expectedArray.a[0] = 'b';
expectedArray.a.c = 'd';
st.deepEqual(qs.parse('a[]=b&a[c]=d', { plainObjects: true }), expectedArray);
st.end();
});
t.test('can parse with custom encoding', function (st) {
st.deepEqual(qs.parse('%8c%a7=%91%e5%8d%e3%95%7b', {
decoder: function (str) {
var reg = /%([0-9A-F]{2})/ig;
var result = [];
var parts = reg.exec(str);
while (parts) {
result.push(parseInt(parts[1], 16));
parts = reg.exec(str);
}
return String(iconv.decode(SaferBuffer.from(result), 'shift_jis'));
}
}), { : '大阪府' });
st.end();
});
t.test('receives the default decoder as a second argument', function (st) {
st.plan(1);
qs.parse('a', {
decoder: function (str, defaultDecoder) {
st.equal(defaultDecoder, utils.decode);
}
});
st.end();
});
t.test('throws error with wrong decoder', function (st) {
st['throws'](function () {
qs.parse({}, { decoder: 'string' });
}, new TypeError('Decoder has to be a function.'));
st.end();
});
t.test('does not mutate the options argument', function (st) {
var options = {};
qs.parse('a[b]=true', options);
st.deepEqual(options, {});
st.end();
});
t.test('throws if an invalid charset is specified', function (st) {
st['throws'](function () {
qs.parse('a=b', { charset: 'foobar' });
}, new TypeError('The charset option must be either utf-8, iso-8859-1, or undefined'));
st.end();
});
t.test('parses an iso-8859-1 string if asked to', function (st) {
st.deepEqual(qs.parse('%A2=%BD', { charset: 'iso-8859-1' }), { '¢': '½' });
st.end();
});
var urlEncodedCheckmarkInUtf8 = '%E2%9C%93';
var urlEncodedOSlashInUtf8 = '%C3%B8';
var urlEncodedNumCheckmark = '%26%2310003%3B';
var urlEncodedNumSmiley = '%26%239786%3B';
t.test('prefers an utf-8 charset specified by the utf8 sentinel to a default charset of iso-8859-1', function (st) {
st.deepEqual(qs.parse('utf8=' + urlEncodedCheckmarkInUtf8 + '&' + urlEncodedOSlashInUtf8 + '=' + urlEncodedOSlashInUtf8, { charsetSentinel: true, charset: 'iso-8859-1' }), { ø: 'ø' });
st.end();
});
t.test('prefers an iso-8859-1 charset specified by the utf8 sentinel to a default charset of utf-8', function (st) {
st.deepEqual(qs.parse('utf8=' + urlEncodedNumCheckmark + '&' + urlEncodedOSlashInUtf8 + '=' + urlEncodedOSlashInUtf8, { charsetSentinel: true, charset: 'utf-8' }), { 'ø': 'ø' });
st.end();
});
t.test('does not require the utf8 sentinel to be defined before the parameters whose decoding it affects', function (st) {
st.deepEqual(qs.parse('a=' + urlEncodedOSlashInUtf8 + '&utf8=' + urlEncodedNumCheckmark, { charsetSentinel: true, charset: 'utf-8' }), { a: 'ø' });
st.end();
});
t.test('should ignore an utf8 sentinel with an unknown value', function (st) {
st.deepEqual(qs.parse('utf8=foo&' + urlEncodedOSlashInUtf8 + '=' + urlEncodedOSlashInUtf8, { charsetSentinel: true, charset: 'utf-8' }), { ø: 'ø' });
st.end();
});
t.test('uses the utf8 sentinel to switch to utf-8 when no default charset is given', function (st) {
st.deepEqual(qs.parse('utf8=' + urlEncodedCheckmarkInUtf8 + '&' + urlEncodedOSlashInUtf8 + '=' + urlEncodedOSlashInUtf8, { charsetSentinel: true }), { ø: 'ø' });
st.end();
});
t.test('uses the utf8 sentinel to switch to iso-8859-1 when no default charset is given', function (st) {
st.deepEqual(qs.parse('utf8=' + urlEncodedNumCheckmark + '&' + urlEncodedOSlashInUtf8 + '=' + urlEncodedOSlashInUtf8, { charsetSentinel: true }), { 'ø': 'ø' });
st.end();
});
t.test('interprets numeric entities in iso-8859-1 when `interpretNumericEntities`', function (st) {
st.deepEqual(qs.parse('foo=' + urlEncodedNumSmiley, { charset: 'iso-8859-1', interpretNumericEntities: true }), { foo: '☺' });
st.end();
});
t.test('handles a custom decoder returning `null`, in the `iso-8859-1` charset, when `interpretNumericEntities`', function (st) {
st.deepEqual(qs.parse('foo=&bar=' + urlEncodedNumSmiley, {
charset: 'iso-8859-1',
decoder: function (str, defaultDecoder, charset) {
return str ? defaultDecoder(str, defaultDecoder, charset) : null;
},
interpretNumericEntities: true
}), { foo: null, bar: '☺' });
st.end();
});
t.test('does not interpret numeric entities in iso-8859-1 when `interpretNumericEntities` is absent', function (st) {
st.deepEqual(qs.parse('foo=' + urlEncodedNumSmiley, { charset: 'iso-8859-1' }), { foo: '&#9786;' });
st.end();
});
t.test('does not interpret numeric entities when the charset is utf-8, even when `interpretNumericEntities`', function (st) {
st.deepEqual(qs.parse('foo=' + urlEncodedNumSmiley, { charset: 'utf-8', interpretNumericEntities: true }), { foo: '&#9786;' });
st.end();
});
t.test('does not interpret %uXXXX syntax in iso-8859-1 mode', function (st) {
st.deepEqual(qs.parse('%u263A=%u263A', { charset: 'iso-8859-1' }), { '%u263A': '%u263A' });
st.end();
});
t.test('allows for decoding keys and values differently', function (st) {
var decoder = function (str, defaultDecoder, charset, type) {
if (type === 'key') {
return defaultDecoder(str, defaultDecoder, charset, type).toLowerCase();
}
if (type === 'value') {
return defaultDecoder(str, defaultDecoder, charset, type).toUpperCase();
}
throw 'this should never happen! type: ' + type;
};
st.deepEqual(qs.parse('KeY=vAlUe', { decoder: decoder }), { key: 'VALUE' });
st.end();
});
t.end();
});

738
node_modules/qs/test/stringify.js generated vendored Normal file
View File

@ -0,0 +1,738 @@
'use strict';
var test = require('tape');
var qs = require('../');
var utils = require('../lib/utils');
var iconv = require('iconv-lite');
var SaferBuffer = require('safer-buffer').Buffer;
var hasSymbols = require('has-symbols');
var hasBigInt = typeof BigInt === 'function';
test('stringify()', function (t) {
t.test('stringifies a querystring object', function (st) {
st.equal(qs.stringify({ a: 'b' }), 'a=b');
st.equal(qs.stringify({ a: 1 }), 'a=1');
st.equal(qs.stringify({ a: 1, b: 2 }), 'a=1&b=2');
st.equal(qs.stringify({ a: 'A_Z' }), 'a=A_Z');
st.equal(qs.stringify({ a: '€' }), 'a=%E2%82%AC');
st.equal(qs.stringify({ a: '' }), 'a=%EE%80%80');
st.equal(qs.stringify({ a: 'א' }), 'a=%D7%90');
st.equal(qs.stringify({ a: '𐐷' }), 'a=%F0%90%90%B7');
st.end();
});
t.test('stringifies falsy values', function (st) {
st.equal(qs.stringify(undefined), '');
st.equal(qs.stringify(null), '');
st.equal(qs.stringify(null, { strictNullHandling: true }), '');
st.equal(qs.stringify(false), '');
st.equal(qs.stringify(0), '');
st.end();
});
t.test('stringifies symbols', { skip: !hasSymbols() }, function (st) {
st.equal(qs.stringify(Symbol.iterator), '');
st.equal(qs.stringify([Symbol.iterator]), '0=Symbol%28Symbol.iterator%29');
st.equal(qs.stringify({ a: Symbol.iterator }), 'a=Symbol%28Symbol.iterator%29');
st.equal(
qs.stringify({ a: [Symbol.iterator] }, { encodeValuesOnly: true, arrayFormat: 'brackets' }),
'a[]=Symbol%28Symbol.iterator%29'
);
st.end();
});
t.test('stringifies bigints', { skip: !hasBigInt }, function (st) {
var three = BigInt(3);
var encodeWithN = function (value, defaultEncoder, charset) {
var result = defaultEncoder(value, defaultEncoder, charset);
return typeof value === 'bigint' ? result + 'n' : result;
};
st.equal(qs.stringify(three), '');
st.equal(qs.stringify([three]), '0=3');
st.equal(qs.stringify([three], { encoder: encodeWithN }), '0=3n');
st.equal(qs.stringify({ a: three }), 'a=3');
st.equal(qs.stringify({ a: three }, { encoder: encodeWithN }), 'a=3n');
st.equal(
qs.stringify({ a: [three] }, { encodeValuesOnly: true, arrayFormat: 'brackets' }),
'a[]=3'
);
st.equal(
qs.stringify({ a: [three] }, { encodeValuesOnly: true, encoder: encodeWithN, arrayFormat: 'brackets' }),
'a[]=3n'
);
st.end();
});
t.test('adds query prefix', function (st) {
st.equal(qs.stringify({ a: 'b' }, { addQueryPrefix: true }), '?a=b');
st.end();
});
t.test('with query prefix, outputs blank string given an empty object', function (st) {
st.equal(qs.stringify({}, { addQueryPrefix: true }), '');
st.end();
});
t.test('stringifies nested falsy values', function (st) {
st.equal(qs.stringify({ a: { b: { c: null } } }), 'a%5Bb%5D%5Bc%5D=');
st.equal(qs.stringify({ a: { b: { c: null } } }, { strictNullHandling: true }), 'a%5Bb%5D%5Bc%5D');
st.equal(qs.stringify({ a: { b: { c: false } } }), 'a%5Bb%5D%5Bc%5D=false');
st.end();
});
t.test('stringifies a nested object', function (st) {
st.equal(qs.stringify({ a: { b: 'c' } }), 'a%5Bb%5D=c');
st.equal(qs.stringify({ a: { b: { c: { d: 'e' } } } }), 'a%5Bb%5D%5Bc%5D%5Bd%5D=e');
st.end();
});
t.test('stringifies a nested object with dots notation', function (st) {
st.equal(qs.stringify({ a: { b: 'c' } }, { allowDots: true }), 'a.b=c');
st.equal(qs.stringify({ a: { b: { c: { d: 'e' } } } }, { allowDots: true }), 'a.b.c.d=e');
st.end();
});
t.test('stringifies an array value', function (st) {
st.equal(
qs.stringify({ a: ['b', 'c', 'd'] }, { arrayFormat: 'indices' }),
'a%5B0%5D=b&a%5B1%5D=c&a%5B2%5D=d',
'indices => indices'
);
st.equal(
qs.stringify({ a: ['b', 'c', 'd'] }, { arrayFormat: 'brackets' }),
'a%5B%5D=b&a%5B%5D=c&a%5B%5D=d',
'brackets => brackets'
);
st.equal(
qs.stringify({ a: ['b', 'c', 'd'] }, { arrayFormat: 'comma' }),
'a=b%2Cc%2Cd',
'comma => comma'
);
st.equal(
qs.stringify({ a: ['b', 'c', 'd'] }),
'a%5B0%5D=b&a%5B1%5D=c&a%5B2%5D=d',
'default => indices'
);
st.end();
});
t.test('omits nulls when asked', function (st) {
st.equal(qs.stringify({ a: 'b', c: null }, { skipNulls: true }), 'a=b');
st.end();
});
t.test('omits nested nulls when asked', function (st) {
st.equal(qs.stringify({ a: { b: 'c', d: null } }, { skipNulls: true }), 'a%5Bb%5D=c');
st.end();
});
t.test('omits array indices when asked', function (st) {
st.equal(qs.stringify({ a: ['b', 'c', 'd'] }, { indices: false }), 'a=b&a=c&a=d');
st.end();
});
t.test('stringifies a nested array value', function (st) {
st.equal(qs.stringify({ a: { b: ['c', 'd'] } }, { arrayFormat: 'indices' }), 'a%5Bb%5D%5B0%5D=c&a%5Bb%5D%5B1%5D=d');
st.equal(qs.stringify({ a: { b: ['c', 'd'] } }, { arrayFormat: 'brackets' }), 'a%5Bb%5D%5B%5D=c&a%5Bb%5D%5B%5D=d');
st.equal(qs.stringify({ a: { b: ['c', 'd'] } }, { arrayFormat: 'comma' }), 'a%5Bb%5D=c%2Cd'); // a[b]=c,d
st.equal(qs.stringify({ a: { b: ['c', 'd'] } }), 'a%5Bb%5D%5B0%5D=c&a%5Bb%5D%5B1%5D=d');
st.end();
});
t.test('stringifies a nested array value with dots notation', function (st) {
st.equal(
qs.stringify(
{ a: { b: ['c', 'd'] } },
{ allowDots: true, encode: false, arrayFormat: 'indices' }
),
'a.b[0]=c&a.b[1]=d',
'indices: stringifies with dots + indices'
);
st.equal(
qs.stringify(
{ a: { b: ['c', 'd'] } },
{ allowDots: true, encode: false, arrayFormat: 'brackets' }
),
'a.b[]=c&a.b[]=d',
'brackets: stringifies with dots + brackets'
);
st.equal(
qs.stringify(
{ a: { b: ['c', 'd'] } },
{ allowDots: true, encode: false, arrayFormat: 'comma' }
),
'a.b=c,d',
'comma: stringifies with dots + comma'
);
st.equal(
qs.stringify(
{ a: { b: ['c', 'd'] } },
{ allowDots: true, encode: false }
),
'a.b[0]=c&a.b[1]=d',
'default: stringifies with dots + indices'
);
st.end();
});
t.test('stringifies an object inside an array', function (st) {
st.equal(
qs.stringify({ a: [{ b: 'c' }] }, { arrayFormat: 'indices' }),
'a%5B0%5D%5Bb%5D=c', // a[0][b]=c
'indices => brackets'
);
st.equal(
qs.stringify({ a: [{ b: 'c' }] }, { arrayFormat: 'brackets' }),
'a%5B%5D%5Bb%5D=c', // a[][b]=c
'brackets => brackets'
);
st.equal(
qs.stringify({ a: [{ b: 'c' }] }),
'a%5B0%5D%5Bb%5D=c',
'default => indices'
);
st.equal(
qs.stringify({ a: [{ b: { c: [1] } }] }, { arrayFormat: 'indices' }),
'a%5B0%5D%5Bb%5D%5Bc%5D%5B0%5D=1',
'indices => indices'
);
st.equal(
qs.stringify({ a: [{ b: { c: [1] } }] }, { arrayFormat: 'brackets' }),
'a%5B%5D%5Bb%5D%5Bc%5D%5B%5D=1',
'brackets => brackets'
);
st.equal(
qs.stringify({ a: [{ b: { c: [1] } }] }),
'a%5B0%5D%5Bb%5D%5Bc%5D%5B0%5D=1',
'default => indices'
);
st.end();
});
t.test('stringifies an array with mixed objects and primitives', function (st) {
st.equal(
qs.stringify({ a: [{ b: 1 }, 2, 3] }, { encode: false, arrayFormat: 'indices' }),
'a[0][b]=1&a[1]=2&a[2]=3',
'indices => indices'
);
st.equal(
qs.stringify({ a: [{ b: 1 }, 2, 3] }, { encode: false, arrayFormat: 'brackets' }),
'a[][b]=1&a[]=2&a[]=3',
'brackets => brackets'
);
st.equal(
qs.stringify({ a: [{ b: 1 }, 2, 3] }, { encode: false }),
'a[0][b]=1&a[1]=2&a[2]=3',
'default => indices'
);
st.end();
});
t.test('stringifies an object inside an array with dots notation', function (st) {
st.equal(
qs.stringify(
{ a: [{ b: 'c' }] },
{ allowDots: true, encode: false, arrayFormat: 'indices' }
),
'a[0].b=c',
'indices => indices'
);
st.equal(
qs.stringify(
{ a: [{ b: 'c' }] },
{ allowDots: true, encode: false, arrayFormat: 'brackets' }
),
'a[].b=c',
'brackets => brackets'
);
st.equal(
qs.stringify(
{ a: [{ b: 'c' }] },
{ allowDots: true, encode: false }
),
'a[0].b=c',
'default => indices'
);
st.equal(
qs.stringify(
{ a: [{ b: { c: [1] } }] },
{ allowDots: true, encode: false, arrayFormat: 'indices' }
),
'a[0].b.c[0]=1',
'indices => indices'
);
st.equal(
qs.stringify(
{ a: [{ b: { c: [1] } }] },
{ allowDots: true, encode: false, arrayFormat: 'brackets' }
),
'a[].b.c[]=1',
'brackets => brackets'
);
st.equal(
qs.stringify(
{ a: [{ b: { c: [1] } }] },
{ allowDots: true, encode: false }
),
'a[0].b.c[0]=1',
'default => indices'
);
st.end();
});
t.test('does not omit object keys when indices = false', function (st) {
st.equal(qs.stringify({ a: [{ b: 'c' }] }, { indices: false }), 'a%5Bb%5D=c');
st.end();
});
t.test('uses indices notation for arrays when indices=true', function (st) {
st.equal(qs.stringify({ a: ['b', 'c'] }, { indices: true }), 'a%5B0%5D=b&a%5B1%5D=c');
st.end();
});
t.test('uses indices notation for arrays when no arrayFormat is specified', function (st) {
st.equal(qs.stringify({ a: ['b', 'c'] }), 'a%5B0%5D=b&a%5B1%5D=c');
st.end();
});
t.test('uses indices notation for arrays when no arrayFormat=indices', function (st) {
st.equal(qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'indices' }), 'a%5B0%5D=b&a%5B1%5D=c');
st.end();
});
t.test('uses repeat notation for arrays when no arrayFormat=repeat', function (st) {
st.equal(qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'repeat' }), 'a=b&a=c');
st.end();
});
t.test('uses brackets notation for arrays when no arrayFormat=brackets', function (st) {
st.equal(qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'brackets' }), 'a%5B%5D=b&a%5B%5D=c');
st.end();
});
t.test('stringifies a complicated object', function (st) {
st.equal(qs.stringify({ a: { b: 'c', d: 'e' } }), 'a%5Bb%5D=c&a%5Bd%5D=e');
st.end();
});
t.test('stringifies an empty value', function (st) {
st.equal(qs.stringify({ a: '' }), 'a=');
st.equal(qs.stringify({ a: null }, { strictNullHandling: true }), 'a');
st.equal(qs.stringify({ a: '', b: '' }), 'a=&b=');
st.equal(qs.stringify({ a: null, b: '' }, { strictNullHandling: true }), 'a&b=');
st.equal(qs.stringify({ a: { b: '' } }), 'a%5Bb%5D=');
st.equal(qs.stringify({ a: { b: null } }, { strictNullHandling: true }), 'a%5Bb%5D');
st.equal(qs.stringify({ a: { b: null } }, { strictNullHandling: false }), 'a%5Bb%5D=');
st.end();
});
t.test('stringifies a null object', { skip: !Object.create }, function (st) {
var obj = Object.create(null);
obj.a = 'b';
st.equal(qs.stringify(obj), 'a=b');
st.end();
});
t.test('returns an empty string for invalid input', function (st) {
st.equal(qs.stringify(undefined), '');
st.equal(qs.stringify(false), '');
st.equal(qs.stringify(null), '');
st.equal(qs.stringify(''), '');
st.end();
});
t.test('stringifies an object with a null object as a child', { skip: !Object.create }, function (st) {
var obj = { a: Object.create(null) };
obj.a.b = 'c';
st.equal(qs.stringify(obj), 'a%5Bb%5D=c');
st.end();
});
t.test('drops keys with a value of undefined', function (st) {
st.equal(qs.stringify({ a: undefined }), '');
st.equal(qs.stringify({ a: { b: undefined, c: null } }, { strictNullHandling: true }), 'a%5Bc%5D');
st.equal(qs.stringify({ a: { b: undefined, c: null } }, { strictNullHandling: false }), 'a%5Bc%5D=');
st.equal(qs.stringify({ a: { b: undefined, c: '' } }), 'a%5Bc%5D=');
st.end();
});
t.test('url encodes values', function (st) {
st.equal(qs.stringify({ a: 'b c' }), 'a=b%20c');
st.end();
});
t.test('stringifies a date', function (st) {
var now = new Date();
var str = 'a=' + encodeURIComponent(now.toISOString());
st.equal(qs.stringify({ a: now }), str);
st.end();
});
t.test('stringifies the weird object from qs', function (st) {
st.equal(qs.stringify({ 'my weird field': '~q1!2"\'w$5&7/z8)?' }), 'my%20weird%20field=~q1%212%22%27w%245%267%2Fz8%29%3F');
st.end();
});
t.test('skips properties that are part of the object prototype', function (st) {
Object.prototype.crash = 'test';
st.equal(qs.stringify({ a: 'b' }), 'a=b');
st.equal(qs.stringify({ a: { b: 'c' } }), 'a%5Bb%5D=c');
delete Object.prototype.crash;
st.end();
});
t.test('stringifies boolean values', function (st) {
st.equal(qs.stringify({ a: true }), 'a=true');
st.equal(qs.stringify({ a: { b: true } }), 'a%5Bb%5D=true');
st.equal(qs.stringify({ b: false }), 'b=false');
st.equal(qs.stringify({ b: { c: false } }), 'b%5Bc%5D=false');
st.end();
});
t.test('stringifies buffer values', function (st) {
st.equal(qs.stringify({ a: SaferBuffer.from('test') }), 'a=test');
st.equal(qs.stringify({ a: { b: SaferBuffer.from('test') } }), 'a%5Bb%5D=test');
st.end();
});
t.test('stringifies an object using an alternative delimiter', function (st) {
st.equal(qs.stringify({ a: 'b', c: 'd' }, { delimiter: ';' }), 'a=b;c=d');
st.end();
});
t.test('doesn\'t blow up when Buffer global is missing', function (st) {
var tempBuffer = global.Buffer;
delete global.Buffer;
var result = qs.stringify({ a: 'b', c: 'd' });
global.Buffer = tempBuffer;
st.equal(result, 'a=b&c=d');
st.end();
});
t.test('selects properties when filter=array', function (st) {
st.equal(qs.stringify({ a: 'b' }, { filter: ['a'] }), 'a=b');
st.equal(qs.stringify({ a: 1 }, { filter: [] }), '');
st.equal(
qs.stringify(
{ a: { b: [1, 2, 3, 4], c: 'd' }, c: 'f' },
{ filter: ['a', 'b', 0, 2], arrayFormat: 'indices' }
),
'a%5Bb%5D%5B0%5D=1&a%5Bb%5D%5B2%5D=3',
'indices => indices'
);
st.equal(
qs.stringify(
{ a: { b: [1, 2, 3, 4], c: 'd' }, c: 'f' },
{ filter: ['a', 'b', 0, 2], arrayFormat: 'brackets' }
),
'a%5Bb%5D%5B%5D=1&a%5Bb%5D%5B%5D=3',
'brackets => brackets'
);
st.equal(
qs.stringify(
{ a: { b: [1, 2, 3, 4], c: 'd' }, c: 'f' },
{ filter: ['a', 'b', 0, 2] }
),
'a%5Bb%5D%5B0%5D=1&a%5Bb%5D%5B2%5D=3',
'default => indices'
);
st.end();
});
t.test('supports custom representations when filter=function', function (st) {
var calls = 0;
var obj = { a: 'b', c: 'd', e: { f: new Date(1257894000000) } };
var filterFunc = function (prefix, value) {
calls += 1;
if (calls === 1) {
st.equal(prefix, '', 'prefix is empty');
st.equal(value, obj);
} else if (prefix === 'c') {
return void 0;
} else if (value instanceof Date) {
st.equal(prefix, 'e[f]');
return value.getTime();
}
return value;
};
st.equal(qs.stringify(obj, { filter: filterFunc }), 'a=b&e%5Bf%5D=1257894000000');
st.equal(calls, 5);
st.end();
});
t.test('can disable uri encoding', function (st) {
st.equal(qs.stringify({ a: 'b' }, { encode: false }), 'a=b');
st.equal(qs.stringify({ a: { b: 'c' } }, { encode: false }), 'a[b]=c');
st.equal(qs.stringify({ a: 'b', c: null }, { strictNullHandling: true, encode: false }), 'a=b&c');
st.end();
});
t.test('can sort the keys', function (st) {
var sort = function (a, b) {
return a.localeCompare(b);
};
st.equal(qs.stringify({ a: 'c', z: 'y', b: 'f' }, { sort: sort }), 'a=c&b=f&z=y');
st.equal(qs.stringify({ a: 'c', z: { j: 'a', i: 'b' }, b: 'f' }, { sort: sort }), 'a=c&b=f&z%5Bi%5D=b&z%5Bj%5D=a');
st.end();
});
t.test('can sort the keys at depth 3 or more too', function (st) {
var sort = function (a, b) {
return a.localeCompare(b);
};
st.equal(
qs.stringify(
{ a: 'a', z: { zj: { zjb: 'zjb', zja: 'zja' }, zi: { zib: 'zib', zia: 'zia' } }, b: 'b' },
{ sort: sort, encode: false }
),
'a=a&b=b&z[zi][zia]=zia&z[zi][zib]=zib&z[zj][zja]=zja&z[zj][zjb]=zjb'
);
st.equal(
qs.stringify(
{ a: 'a', z: { zj: { zjb: 'zjb', zja: 'zja' }, zi: { zib: 'zib', zia: 'zia' } }, b: 'b' },
{ sort: null, encode: false }
),
'a=a&z[zj][zjb]=zjb&z[zj][zja]=zja&z[zi][zib]=zib&z[zi][zia]=zia&b=b'
);
st.end();
});
t.test('can stringify with custom encoding', function (st) {
st.equal(qs.stringify({ : '大阪府', '': '' }, {
encoder: function (str) {
if (str.length === 0) {
return '';
}
var buf = iconv.encode(str, 'shiftjis');
var result = [];
for (var i = 0; i < buf.length; ++i) {
result.push(buf.readUInt8(i).toString(16));
}
return '%' + result.join('%');
}
}), '%8c%a7=%91%e5%8d%e3%95%7b&=');
st.end();
});
t.test('receives the default encoder as a second argument', function (st) {
st.plan(2);
qs.stringify({ a: 1 }, {
encoder: function (str, defaultEncoder) {
st.equal(defaultEncoder, utils.encode);
}
});
st.end();
});
t.test('throws error with wrong encoder', function (st) {
st['throws'](function () {
qs.stringify({}, { encoder: 'string' });
}, new TypeError('Encoder has to be a function.'));
st.end();
});
t.test('can use custom encoder for a buffer object', { skip: typeof Buffer === 'undefined' }, function (st) {
st.equal(qs.stringify({ a: SaferBuffer.from([1]) }, {
encoder: function (buffer) {
if (typeof buffer === 'string') {
return buffer;
}
return String.fromCharCode(buffer.readUInt8(0) + 97);
}
}), 'a=b');
st.equal(qs.stringify({ a: SaferBuffer.from('a b') }, {
encoder: function (buffer) {
return buffer;
}
}), 'a=a b');
st.end();
});
t.test('serializeDate option', function (st) {
var date = new Date();
st.equal(
qs.stringify({ a: date }),
'a=' + date.toISOString().replace(/:/g, '%3A'),
'default is toISOString'
);
var mutatedDate = new Date();
mutatedDate.toISOString = function () {
throw new SyntaxError();
};
st['throws'](function () {
mutatedDate.toISOString();
}, SyntaxError);
st.equal(
qs.stringify({ a: mutatedDate }),
'a=' + Date.prototype.toISOString.call(mutatedDate).replace(/:/g, '%3A'),
'toISOString works even when method is not locally present'
);
var specificDate = new Date(6);
st.equal(
qs.stringify(
{ a: specificDate },
{ serializeDate: function (d) { return d.getTime() * 7; } }
),
'a=42',
'custom serializeDate function called'
);
st.end();
});
t.test('RFC 1738 spaces serialization', function (st) {
st.equal(qs.stringify({ a: 'b c' }, { format: qs.formats.RFC1738 }), 'a=b+c');
st.equal(qs.stringify({ 'a b': 'c d' }, { format: qs.formats.RFC1738 }), 'a+b=c+d');
st.equal(qs.stringify({ 'a b': SaferBuffer.from('a b') }, { format: qs.formats.RFC1738 }), 'a+b=a+b');
st.end();
});
t.test('RFC 3986 spaces serialization', function (st) {
st.equal(qs.stringify({ a: 'b c' }, { format: qs.formats.RFC3986 }), 'a=b%20c');
st.equal(qs.stringify({ 'a b': 'c d' }, { format: qs.formats.RFC3986 }), 'a%20b=c%20d');
st.equal(qs.stringify({ 'a b': SaferBuffer.from('a b') }, { format: qs.formats.RFC3986 }), 'a%20b=a%20b');
st.end();
});
t.test('Backward compatibility to RFC 3986', function (st) {
st.equal(qs.stringify({ a: 'b c' }), 'a=b%20c');
st.equal(qs.stringify({ 'a b': SaferBuffer.from('a b') }), 'a%20b=a%20b');
st.end();
});
t.test('Edge cases and unknown formats', function (st) {
['UFO1234', false, 1234, null, {}, []].forEach(
function (format) {
st['throws'](
function () {
qs.stringify({ a: 'b c' }, { format: format });
},
new TypeError('Unknown format option provided.')
);
}
);
st.end();
});
t.test('encodeValuesOnly', function (st) {
st.equal(
qs.stringify(
{ a: 'b', c: ['d', 'e=f'], f: [['g'], ['h']] },
{ encodeValuesOnly: true }
),
'a=b&c[0]=d&c[1]=e%3Df&f[0][0]=g&f[1][0]=h'
);
st.equal(
qs.stringify(
{ a: 'b', c: ['d', 'e'], f: [['g'], ['h']] }
),
'a=b&c%5B0%5D=d&c%5B1%5D=e&f%5B0%5D%5B0%5D=g&f%5B1%5D%5B0%5D=h'
);
st.end();
});
t.test('encodeValuesOnly - strictNullHandling', function (st) {
st.equal(
qs.stringify(
{ a: { b: null } },
{ encodeValuesOnly: true, strictNullHandling: true }
),
'a[b]'
);
st.end();
});
t.test('throws if an invalid charset is specified', function (st) {
st['throws'](function () {
qs.stringify({ a: 'b' }, { charset: 'foobar' });
}, new TypeError('The charset option must be either utf-8, iso-8859-1, or undefined'));
st.end();
});
t.test('respects a charset of iso-8859-1', function (st) {
st.equal(qs.stringify({ æ: 'æ' }, { charset: 'iso-8859-1' }), '%E6=%E6');
st.end();
});
t.test('encodes unrepresentable chars as numeric entities in iso-8859-1 mode', function (st) {
st.equal(qs.stringify({ a: '☺' }, { charset: 'iso-8859-1' }), 'a=%26%239786%3B');
st.end();
});
t.test('respects an explicit charset of utf-8 (the default)', function (st) {
st.equal(qs.stringify({ a: 'æ' }, { charset: 'utf-8' }), 'a=%C3%A6');
st.end();
});
t.test('adds the right sentinel when instructed to and the charset is utf-8', function (st) {
st.equal(qs.stringify({ a: 'æ' }, { charsetSentinel: true, charset: 'utf-8' }), 'utf8=%E2%9C%93&a=%C3%A6');
st.end();
});
t.test('adds the right sentinel when instructed to and the charset is iso-8859-1', function (st) {
st.equal(qs.stringify({ a: 'æ' }, { charsetSentinel: true, charset: 'iso-8859-1' }), 'utf8=%26%2310003%3B&a=%E6');
st.end();
});
t.test('does not mutate the options argument', function (st) {
var options = {};
qs.stringify({}, options);
st.deepEqual(options, {});
st.end();
});
t.test('strictNullHandling works with custom filter', function (st) {
var filter = function (prefix, value) {
return value;
};
var options = { strictNullHandling: true, filter: filter };
st.equal(qs.stringify({ key: null }, options), 'key');
st.end();
});
t.test('strictNullHandling works with null serializeDate', function (st) {
var serializeDate = function () {
return null;
};
var options = { strictNullHandling: true, serializeDate: serializeDate };
var date = new Date();
st.equal(qs.stringify({ key: date }, options), 'key');
st.end();
});
t.test('allows for encoding keys and values differently', function (st) {
var encoder = function (str, defaultEncoder, charset, type) {
if (type === 'key') {
return defaultEncoder(str, defaultEncoder, charset, type).toLowerCase();
}
if (type === 'value') {
return defaultEncoder(str, defaultEncoder, charset, type).toUpperCase();
}
throw 'this should never happen! type: ' + type;
};
st.deepEqual(qs.stringify({ KeY: 'vAlUe' }, { encoder: encoder }), 'key=VALUE');
st.end();
});
t.end();
});

136
node_modules/qs/test/utils.js generated vendored Normal file
View File

@ -0,0 +1,136 @@
'use strict';
var test = require('tape');
var inspect = require('object-inspect');
var SaferBuffer = require('safer-buffer').Buffer;
var forEach = require('for-each');
var utils = require('../lib/utils');
test('merge()', function (t) {
t.deepEqual(utils.merge(null, true), [null, true], 'merges true into null');
t.deepEqual(utils.merge(null, [42]), [null, 42], 'merges null into an array');
t.deepEqual(utils.merge({ a: 'b' }, { a: 'c' }), { a: ['b', 'c'] }, 'merges two objects with the same key');
var oneMerged = utils.merge({ foo: 'bar' }, { foo: { first: '123' } });
t.deepEqual(oneMerged, { foo: ['bar', { first: '123' }] }, 'merges a standalone and an object into an array');
var twoMerged = utils.merge({ foo: ['bar', { first: '123' }] }, { foo: { second: '456' } });
t.deepEqual(twoMerged, { foo: { 0: 'bar', 1: { first: '123' }, second: '456' } }, 'merges a standalone and two objects into an array');
var sandwiched = utils.merge({ foo: ['bar', { first: '123', second: '456' }] }, { foo: 'baz' });
t.deepEqual(sandwiched, { foo: ['bar', { first: '123', second: '456' }, 'baz'] }, 'merges an object sandwiched by two standalones into an array');
var nestedArrays = utils.merge({ foo: ['baz'] }, { foo: ['bar', 'xyzzy'] });
t.deepEqual(nestedArrays, { foo: ['baz', 'bar', 'xyzzy'] });
var noOptionsNonObjectSource = utils.merge({ foo: 'baz' }, 'bar');
t.deepEqual(noOptionsNonObjectSource, { foo: 'baz', bar: true });
t.test(
'avoids invoking array setters unnecessarily',
{ skip: typeof Object.defineProperty !== 'function' },
function (st) {
var setCount = 0;
var getCount = 0;
var observed = [];
Object.defineProperty(observed, 0, {
get: function () {
getCount += 1;
return { bar: 'baz' };
},
set: function () { setCount += 1; }
});
utils.merge(observed, [null]);
st.equal(setCount, 0);
st.equal(getCount, 1);
observed[0] = observed[0]; // eslint-disable-line no-self-assign
st.equal(setCount, 1);
st.equal(getCount, 2);
st.end();
}
);
t.end();
});
test('assign()', function (t) {
var target = { a: 1, b: 2 };
var source = { b: 3, c: 4 };
var result = utils.assign(target, source);
t.equal(result, target, 'returns the target');
t.deepEqual(target, { a: 1, b: 3, c: 4 }, 'target and source are merged');
t.deepEqual(source, { b: 3, c: 4 }, 'source is untouched');
t.end();
});
test('combine()', function (t) {
t.test('both arrays', function (st) {
var a = [1];
var b = [2];
var combined = utils.combine(a, b);
st.deepEqual(a, [1], 'a is not mutated');
st.deepEqual(b, [2], 'b is not mutated');
st.notEqual(a, combined, 'a !== combined');
st.notEqual(b, combined, 'b !== combined');
st.deepEqual(combined, [1, 2], 'combined is a + b');
st.end();
});
t.test('one array, one non-array', function (st) {
var aN = 1;
var a = [aN];
var bN = 2;
var b = [bN];
var combinedAnB = utils.combine(aN, b);
st.deepEqual(b, [bN], 'b is not mutated');
st.notEqual(aN, combinedAnB, 'aN + b !== aN');
st.notEqual(a, combinedAnB, 'aN + b !== a');
st.notEqual(bN, combinedAnB, 'aN + b !== bN');
st.notEqual(b, combinedAnB, 'aN + b !== b');
st.deepEqual([1, 2], combinedAnB, 'first argument is array-wrapped when not an array');
var combinedABn = utils.combine(a, bN);
st.deepEqual(a, [aN], 'a is not mutated');
st.notEqual(aN, combinedABn, 'a + bN !== aN');
st.notEqual(a, combinedABn, 'a + bN !== a');
st.notEqual(bN, combinedABn, 'a + bN !== bN');
st.notEqual(b, combinedABn, 'a + bN !== b');
st.deepEqual([1, 2], combinedABn, 'second argument is array-wrapped when not an array');
st.end();
});
t.test('neither is an array', function (st) {
var combined = utils.combine(1, 2);
st.notEqual(1, combined, '1 + 2 !== 1');
st.notEqual(2, combined, '1 + 2 !== 2');
st.deepEqual([1, 2], combined, 'both arguments are array-wrapped when not an array');
st.end();
});
t.end();
});
test('isBuffer()', function (t) {
forEach([null, undefined, true, false, '', 'abc', 42, 0, NaN, {}, [], function () {}, /a/g], function (x) {
t.equal(utils.isBuffer(x), false, inspect(x) + ' is not a buffer');
});
var fakeBuffer = { constructor: Buffer };
t.equal(utils.isBuffer(fakeBuffer), false, 'fake buffer is not a buffer');
var saferBuffer = SaferBuffer.from('abc');
t.equal(utils.isBuffer(saferBuffer), true, 'SaferBuffer instance is a buffer');
var buffer = Buffer.from && Buffer.alloc ? Buffer.from('abc') : new Buffer('abc');
t.equal(utils.isBuffer(buffer), true, 'real Buffer instance is a buffer');
t.end();
});

21
node_modules/safe-buffer/LICENSE generated vendored Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) Feross Aboukhadijeh
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

584
node_modules/safe-buffer/README.md generated vendored Normal file
View File

@ -0,0 +1,584 @@
# safe-buffer [![travis][travis-image]][travis-url] [![npm][npm-image]][npm-url] [![downloads][downloads-image]][downloads-url] [![javascript style guide][standard-image]][standard-url]
[travis-image]: https://img.shields.io/travis/feross/safe-buffer/master.svg
[travis-url]: https://travis-ci.org/feross/safe-buffer
[npm-image]: https://img.shields.io/npm/v/safe-buffer.svg
[npm-url]: https://npmjs.org/package/safe-buffer
[downloads-image]: https://img.shields.io/npm/dm/safe-buffer.svg
[downloads-url]: https://npmjs.org/package/safe-buffer
[standard-image]: https://img.shields.io/badge/code_style-standard-brightgreen.svg
[standard-url]: https://standardjs.com
#### Safer Node.js Buffer API
**Use the new Node.js Buffer APIs (`Buffer.from`, `Buffer.alloc`,
`Buffer.allocUnsafe`, `Buffer.allocUnsafeSlow`) in all versions of Node.js.**
**Uses the built-in implementation when available.**
## install
```
npm install safe-buffer
```
## usage
The goal of this package is to provide a safe replacement for the node.js `Buffer`.
It's a drop-in replacement for `Buffer`. You can use it by adding one `require` line to
the top of your node.js modules:
```js
var Buffer = require('safe-buffer').Buffer
// Existing buffer code will continue to work without issues:
new Buffer('hey', 'utf8')
new Buffer([1, 2, 3], 'utf8')
new Buffer(obj)
new Buffer(16) // create an uninitialized buffer (potentially unsafe)
// But you can use these new explicit APIs to make clear what you want:
Buffer.from('hey', 'utf8') // convert from many types to a Buffer
Buffer.alloc(16) // create a zero-filled buffer (safe)
Buffer.allocUnsafe(16) // create an uninitialized buffer (potentially unsafe)
```
## api
### Class Method: Buffer.from(array)
<!-- YAML
added: v3.0.0
-->
* `array` {Array}
Allocates a new `Buffer` using an `array` of octets.
```js
const buf = Buffer.from([0x62,0x75,0x66,0x66,0x65,0x72]);
// creates a new Buffer containing ASCII bytes
// ['b','u','f','f','e','r']
```
A `TypeError` will be thrown if `array` is not an `Array`.
### Class Method: Buffer.from(arrayBuffer[, byteOffset[, length]])
<!-- YAML
added: v5.10.0
-->
* `arrayBuffer` {ArrayBuffer} The `.buffer` property of a `TypedArray` or
a `new ArrayBuffer()`
* `byteOffset` {Number} Default: `0`
* `length` {Number} Default: `arrayBuffer.length - byteOffset`
When passed a reference to the `.buffer` property of a `TypedArray` instance,
the newly created `Buffer` will share the same allocated memory as the
TypedArray.
```js
const arr = new Uint16Array(2);
arr[0] = 5000;
arr[1] = 4000;
const buf = Buffer.from(arr.buffer); // shares the memory with arr;
console.log(buf);
// Prints: <Buffer 88 13 a0 0f>
// changing the TypedArray changes the Buffer also
arr[1] = 6000;
console.log(buf);
// Prints: <Buffer 88 13 70 17>
```
The optional `byteOffset` and `length` arguments specify a memory range within
the `arrayBuffer` that will be shared by the `Buffer`.
```js
const ab = new ArrayBuffer(10);
const buf = Buffer.from(ab, 0, 2);
console.log(buf.length);
// Prints: 2
```
A `TypeError` will be thrown if `arrayBuffer` is not an `ArrayBuffer`.
### Class Method: Buffer.from(buffer)
<!-- YAML
added: v3.0.0
-->
* `buffer` {Buffer}
Copies the passed `buffer` data onto a new `Buffer` instance.
```js
const buf1 = Buffer.from('buffer');
const buf2 = Buffer.from(buf1);
buf1[0] = 0x61;
console.log(buf1.toString());
// 'auffer'
console.log(buf2.toString());
// 'buffer' (copy is not changed)
```
A `TypeError` will be thrown if `buffer` is not a `Buffer`.
### Class Method: Buffer.from(str[, encoding])
<!-- YAML
added: v5.10.0
-->
* `str` {String} String to encode.
* `encoding` {String} Encoding to use, Default: `'utf8'`
Creates a new `Buffer` containing the given JavaScript string `str`. If
provided, the `encoding` parameter identifies the character encoding.
If not provided, `encoding` defaults to `'utf8'`.
```js
const buf1 = Buffer.from('this is a tést');
console.log(buf1.toString());
// prints: this is a tést
console.log(buf1.toString('ascii'));
// prints: this is a tC)st
const buf2 = Buffer.from('7468697320697320612074c3a97374', 'hex');
console.log(buf2.toString());
// prints: this is a tést
```
A `TypeError` will be thrown if `str` is not a string.
### Class Method: Buffer.alloc(size[, fill[, encoding]])
<!-- YAML
added: v5.10.0
-->
* `size` {Number}
* `fill` {Value} Default: `undefined`
* `encoding` {String} Default: `utf8`
Allocates a new `Buffer` of `size` bytes. If `fill` is `undefined`, the
`Buffer` will be *zero-filled*.
```js
const buf = Buffer.alloc(5);
console.log(buf);
// <Buffer 00 00 00 00 00>
```
The `size` must be less than or equal to the value of
`require('buffer').kMaxLength` (on 64-bit architectures, `kMaxLength` is
`(2^31)-1`). Otherwise, a [`RangeError`][] is thrown. A zero-length Buffer will
be created if a `size` less than or equal to 0 is specified.
If `fill` is specified, the allocated `Buffer` will be initialized by calling
`buf.fill(fill)`. See [`buf.fill()`][] for more information.
```js
const buf = Buffer.alloc(5, 'a');
console.log(buf);
// <Buffer 61 61 61 61 61>
```
If both `fill` and `encoding` are specified, the allocated `Buffer` will be
initialized by calling `buf.fill(fill, encoding)`. For example:
```js
const buf = Buffer.alloc(11, 'aGVsbG8gd29ybGQ=', 'base64');
console.log(buf);
// <Buffer 68 65 6c 6c 6f 20 77 6f 72 6c 64>
```
Calling `Buffer.alloc(size)` can be significantly slower than the alternative
`Buffer.allocUnsafe(size)` but ensures that the newly created `Buffer` instance
contents will *never contain sensitive data*.
A `TypeError` will be thrown if `size` is not a number.
### Class Method: Buffer.allocUnsafe(size)
<!-- YAML
added: v5.10.0
-->
* `size` {Number}
Allocates a new *non-zero-filled* `Buffer` of `size` bytes. The `size` must
be less than or equal to the value of `require('buffer').kMaxLength` (on 64-bit
architectures, `kMaxLength` is `(2^31)-1`). Otherwise, a [`RangeError`][] is
thrown. A zero-length Buffer will be created if a `size` less than or equal to
0 is specified.
The underlying memory for `Buffer` instances created in this way is *not
initialized*. The contents of the newly created `Buffer` are unknown and
*may contain sensitive data*. Use [`buf.fill(0)`][] to initialize such
`Buffer` instances to zeroes.
```js
const buf = Buffer.allocUnsafe(5);
console.log(buf);
// <Buffer 78 e0 82 02 01>
// (octets will be different, every time)
buf.fill(0);
console.log(buf);
// <Buffer 00 00 00 00 00>
```
A `TypeError` will be thrown if `size` is not a number.
Note that the `Buffer` module pre-allocates an internal `Buffer` instance of
size `Buffer.poolSize` that is used as a pool for the fast allocation of new
`Buffer` instances created using `Buffer.allocUnsafe(size)` (and the deprecated
`new Buffer(size)` constructor) only when `size` is less than or equal to
`Buffer.poolSize >> 1` (floor of `Buffer.poolSize` divided by two). The default
value of `Buffer.poolSize` is `8192` but can be modified.
Use of this pre-allocated internal memory pool is a key difference between
calling `Buffer.alloc(size, fill)` vs. `Buffer.allocUnsafe(size).fill(fill)`.
Specifically, `Buffer.alloc(size, fill)` will *never* use the internal Buffer
pool, while `Buffer.allocUnsafe(size).fill(fill)` *will* use the internal
Buffer pool if `size` is less than or equal to half `Buffer.poolSize`. The
difference is subtle but can be important when an application requires the
additional performance that `Buffer.allocUnsafe(size)` provides.
### Class Method: Buffer.allocUnsafeSlow(size)
<!-- YAML
added: v5.10.0
-->
* `size` {Number}
Allocates a new *non-zero-filled* and non-pooled `Buffer` of `size` bytes. The
`size` must be less than or equal to the value of
`require('buffer').kMaxLength` (on 64-bit architectures, `kMaxLength` is
`(2^31)-1`). Otherwise, a [`RangeError`][] is thrown. A zero-length Buffer will
be created if a `size` less than or equal to 0 is specified.
The underlying memory for `Buffer` instances created in this way is *not
initialized*. The contents of the newly created `Buffer` are unknown and
*may contain sensitive data*. Use [`buf.fill(0)`][] to initialize such
`Buffer` instances to zeroes.
When using `Buffer.allocUnsafe()` to allocate new `Buffer` instances,
allocations under 4KB are, by default, sliced from a single pre-allocated
`Buffer`. This allows applications to avoid the garbage collection overhead of
creating many individually allocated Buffers. This approach improves both
performance and memory usage by eliminating the need to track and cleanup as
many `Persistent` objects.
However, in the case where a developer may need to retain a small chunk of
memory from a pool for an indeterminate amount of time, it may be appropriate
to create an un-pooled Buffer instance using `Buffer.allocUnsafeSlow()` then
copy out the relevant bits.
```js
// need to keep around a few small chunks of memory
const store = [];
socket.on('readable', () => {
const data = socket.read();
// allocate for retained data
const sb = Buffer.allocUnsafeSlow(10);
// copy the data into the new allocation
data.copy(sb, 0, 0, 10);
store.push(sb);
});
```
Use of `Buffer.allocUnsafeSlow()` should be used only as a last resort *after*
a developer has observed undue memory retention in their applications.
A `TypeError` will be thrown if `size` is not a number.
### All the Rest
The rest of the `Buffer` API is exactly the same as in node.js.
[See the docs](https://nodejs.org/api/buffer.html).
## Related links
- [Node.js issue: Buffer(number) is unsafe](https://github.com/nodejs/node/issues/4660)
- [Node.js Enhancement Proposal: Buffer.from/Buffer.alloc/Buffer.zalloc/Buffer() soft-deprecate](https://github.com/nodejs/node-eps/pull/4)
## Why is `Buffer` unsafe?
Today, the node.js `Buffer` constructor is overloaded to handle many different argument
types like `String`, `Array`, `Object`, `TypedArrayView` (`Uint8Array`, etc.),
`ArrayBuffer`, and also `Number`.
The API is optimized for convenience: you can throw any type at it, and it will try to do
what you want.
Because the Buffer constructor is so powerful, you often see code like this:
```js
// Convert UTF-8 strings to hex
function toHex (str) {
return new Buffer(str).toString('hex')
}
```
***But what happens if `toHex` is called with a `Number` argument?***
### Remote Memory Disclosure
If an attacker can make your program call the `Buffer` constructor with a `Number`
argument, then they can make it allocate uninitialized memory from the node.js process.
This could potentially disclose TLS private keys, user data, or database passwords.
When the `Buffer` constructor is passed a `Number` argument, it returns an
**UNINITIALIZED** block of memory of the specified `size`. When you create a `Buffer` like
this, you **MUST** overwrite the contents before returning it to the user.
From the [node.js docs](https://nodejs.org/api/buffer.html#buffer_new_buffer_size):
> `new Buffer(size)`
>
> - `size` Number
>
> The underlying memory for `Buffer` instances created in this way is not initialized.
> **The contents of a newly created `Buffer` are unknown and could contain sensitive
> data.** Use `buf.fill(0)` to initialize a Buffer to zeroes.
(Emphasis our own.)
Whenever the programmer intended to create an uninitialized `Buffer` you often see code
like this:
```js
var buf = new Buffer(16)
// Immediately overwrite the uninitialized buffer with data from another buffer
for (var i = 0; i < buf.length; i++) {
buf[i] = otherBuf[i]
}
```
### Would this ever be a problem in real code?
Yes. It's surprisingly common to forget to check the type of your variables in a
dynamically-typed language like JavaScript.
Usually the consequences of assuming the wrong type is that your program crashes with an
uncaught exception. But the failure mode for forgetting to check the type of arguments to
the `Buffer` constructor is more catastrophic.
Here's an example of a vulnerable service that takes a JSON payload and converts it to
hex:
```js
// Take a JSON payload {str: "some string"} and convert it to hex
var server = http.createServer(function (req, res) {
var data = ''
req.setEncoding('utf8')
req.on('data', function (chunk) {
data += chunk
})
req.on('end', function () {
var body = JSON.parse(data)
res.end(new Buffer(body.str).toString('hex'))
})
})
server.listen(8080)
```
In this example, an http client just has to send:
```json
{
"str": 1000
}
```
and it will get back 1,000 bytes of uninitialized memory from the server.
This is a very serious bug. It's similar in severity to the
[the Heartbleed bug](http://heartbleed.com/) that allowed disclosure of OpenSSL process
memory by remote attackers.
### Which real-world packages were vulnerable?
#### [`bittorrent-dht`](https://www.npmjs.com/package/bittorrent-dht)
[Mathias Buus](https://github.com/mafintosh) and I
([Feross Aboukhadijeh](http://feross.org/)) found this issue in one of our own packages,
[`bittorrent-dht`](https://www.npmjs.com/package/bittorrent-dht). The bug would allow
anyone on the internet to send a series of messages to a user of `bittorrent-dht` and get
them to reveal 20 bytes at a time of uninitialized memory from the node.js process.
Here's
[the commit](https://github.com/feross/bittorrent-dht/commit/6c7da04025d5633699800a99ec3fbadf70ad35b8)
that fixed it. We released a new fixed version, created a
[Node Security Project disclosure](https://nodesecurity.io/advisories/68), and deprecated all
vulnerable versions on npm so users will get a warning to upgrade to a newer version.
#### [`ws`](https://www.npmjs.com/package/ws)
That got us wondering if there were other vulnerable packages. Sure enough, within a short
period of time, we found the same issue in [`ws`](https://www.npmjs.com/package/ws), the
most popular WebSocket implementation in node.js.
If certain APIs were called with `Number` parameters instead of `String` or `Buffer` as
expected, then uninitialized server memory would be disclosed to the remote peer.
These were the vulnerable methods:
```js
socket.send(number)
socket.ping(number)
socket.pong(number)
```
Here's a vulnerable socket server with some echo functionality:
```js
server.on('connection', function (socket) {
socket.on('message', function (message) {
message = JSON.parse(message)
if (message.type === 'echo') {
socket.send(message.data) // send back the user's message
}
})
})
```
`socket.send(number)` called on the server, will disclose server memory.
Here's [the release](https://github.com/websockets/ws/releases/tag/1.0.1) where the issue
was fixed, with a more detailed explanation. Props to
[Arnout Kazemier](https://github.com/3rd-Eden) for the quick fix. Here's the
[Node Security Project disclosure](https://nodesecurity.io/advisories/67).
### What's the solution?
It's important that node.js offers a fast way to get memory otherwise performance-critical
applications would needlessly get a lot slower.
But we need a better way to *signal our intent* as programmers. **When we want
uninitialized memory, we should request it explicitly.**
Sensitive functionality should not be packed into a developer-friendly API that loosely
accepts many different types. This type of API encourages the lazy practice of passing
variables in without checking the type very carefully.
#### A new API: `Buffer.allocUnsafe(number)`
The functionality of creating buffers with uninitialized memory should be part of another
API. We propose `Buffer.allocUnsafe(number)`. This way, it's not part of an API that
frequently gets user input of all sorts of different types passed into it.
```js
var buf = Buffer.allocUnsafe(16) // careful, uninitialized memory!
// Immediately overwrite the uninitialized buffer with data from another buffer
for (var i = 0; i < buf.length; i++) {
buf[i] = otherBuf[i]
}
```
### How do we fix node.js core?
We sent [a PR to node.js core](https://github.com/nodejs/node/pull/4514) (merged as
`semver-major`) which defends against one case:
```js
var str = 16
new Buffer(str, 'utf8')
```
In this situation, it's implied that the programmer intended the first argument to be a
string, since they passed an encoding as a second argument. Today, node.js will allocate
uninitialized memory in the case of `new Buffer(number, encoding)`, which is probably not
what the programmer intended.
But this is only a partial solution, since if the programmer does `new Buffer(variable)`
(without an `encoding` parameter) there's no way to know what they intended. If `variable`
is sometimes a number, then uninitialized memory will sometimes be returned.
### What's the real long-term fix?
We could deprecate and remove `new Buffer(number)` and use `Buffer.allocUnsafe(number)` when
we need uninitialized memory. But that would break 1000s of packages.
~~We believe the best solution is to:~~
~~1. Change `new Buffer(number)` to return safe, zeroed-out memory~~
~~2. Create a new API for creating uninitialized Buffers. We propose: `Buffer.allocUnsafe(number)`~~
#### Update
We now support adding three new APIs:
- `Buffer.from(value)` - convert from any type to a buffer
- `Buffer.alloc(size)` - create a zero-filled buffer
- `Buffer.allocUnsafe(size)` - create an uninitialized buffer with given size
This solves the core problem that affected `ws` and `bittorrent-dht` which is
`Buffer(variable)` getting tricked into taking a number argument.
This way, existing code continues working and the impact on the npm ecosystem will be
minimal. Over time, npm maintainers can migrate performance-critical code to use
`Buffer.allocUnsafe(number)` instead of `new Buffer(number)`.
### Conclusion
We think there's a serious design issue with the `Buffer` API as it exists today. It
promotes insecure software by putting high-risk functionality into a convenient API
with friendly "developer ergonomics".
This wasn't merely a theoretical exercise because we found the issue in some of the
most popular npm packages.
Fortunately, there's an easy fix that can be applied today. Use `safe-buffer` in place of
`buffer`.
```js
var Buffer = require('safe-buffer').Buffer
```
Eventually, we hope that node.js core can switch to this new, safer behavior. We believe
the impact on the ecosystem would be minimal since it's not a breaking change.
Well-maintained, popular packages would be updated to use `Buffer.alloc` quickly, while
older, insecure packages would magically become safe from this attack vector.
## links
- [Node.js PR: buffer: throw if both length and enc are passed](https://github.com/nodejs/node/pull/4514)
- [Node Security Project disclosure for `ws`](https://nodesecurity.io/advisories/67)
- [Node Security Project disclosure for`bittorrent-dht`](https://nodesecurity.io/advisories/68)
## credit
The original issues in `bittorrent-dht`
([disclosure](https://nodesecurity.io/advisories/68)) and
`ws` ([disclosure](https://nodesecurity.io/advisories/67)) were discovered by
[Mathias Buus](https://github.com/mafintosh) and
[Feross Aboukhadijeh](http://feross.org/).
Thanks to [Adam Baldwin](https://github.com/evilpacket) for helping disclose these issues
and for his work running the [Node Security Project](https://nodesecurity.io/).
Thanks to [John Hiesey](https://github.com/jhiesey) for proofreading this README and
auditing the code.
## license
MIT. Copyright (C) [Feross Aboukhadijeh](http://feross.org)

187
node_modules/safe-buffer/index.d.ts generated vendored Normal file
View File

@ -0,0 +1,187 @@
declare module "safe-buffer" {
export class Buffer {
length: number
write(string: string, offset?: number, length?: number, encoding?: string): number;
toString(encoding?: string, start?: number, end?: number): string;
toJSON(): { type: 'Buffer', data: any[] };
equals(otherBuffer: Buffer): boolean;
compare(otherBuffer: Buffer, targetStart?: number, targetEnd?: number, sourceStart?: number, sourceEnd?: number): number;
copy(targetBuffer: Buffer, targetStart?: number, sourceStart?: number, sourceEnd?: number): number;
slice(start?: number, end?: number): Buffer;
writeUIntLE(value: number, offset: number, byteLength: number, noAssert?: boolean): number;
writeUIntBE(value: number, offset: number, byteLength: number, noAssert?: boolean): number;
writeIntLE(value: number, offset: number, byteLength: number, noAssert?: boolean): number;
writeIntBE(value: number, offset: number, byteLength: number, noAssert?: boolean): number;
readUIntLE(offset: number, byteLength: number, noAssert?: boolean): number;
readUIntBE(offset: number, byteLength: number, noAssert?: boolean): number;
readIntLE(offset: number, byteLength: number, noAssert?: boolean): number;
readIntBE(offset: number, byteLength: number, noAssert?: boolean): number;
readUInt8(offset: number, noAssert?: boolean): number;
readUInt16LE(offset: number, noAssert?: boolean): number;
readUInt16BE(offset: number, noAssert?: boolean): number;
readUInt32LE(offset: number, noAssert?: boolean): number;
readUInt32BE(offset: number, noAssert?: boolean): number;
readInt8(offset: number, noAssert?: boolean): number;
readInt16LE(offset: number, noAssert?: boolean): number;
readInt16BE(offset: number, noAssert?: boolean): number;
readInt32LE(offset: number, noAssert?: boolean): number;
readInt32BE(offset: number, noAssert?: boolean): number;
readFloatLE(offset: number, noAssert?: boolean): number;
readFloatBE(offset: number, noAssert?: boolean): number;
readDoubleLE(offset: number, noAssert?: boolean): number;
readDoubleBE(offset: number, noAssert?: boolean): number;
swap16(): Buffer;
swap32(): Buffer;
swap64(): Buffer;
writeUInt8(value: number, offset: number, noAssert?: boolean): number;
writeUInt16LE(value: number, offset: number, noAssert?: boolean): number;
writeUInt16BE(value: number, offset: number, noAssert?: boolean): number;
writeUInt32LE(value: number, offset: number, noAssert?: boolean): number;
writeUInt32BE(value: number, offset: number, noAssert?: boolean): number;
writeInt8(value: number, offset: number, noAssert?: boolean): number;
writeInt16LE(value: number, offset: number, noAssert?: boolean): number;
writeInt16BE(value: number, offset: number, noAssert?: boolean): number;
writeInt32LE(value: number, offset: number, noAssert?: boolean): number;
writeInt32BE(value: number, offset: number, noAssert?: boolean): number;
writeFloatLE(value: number, offset: number, noAssert?: boolean): number;
writeFloatBE(value: number, offset: number, noAssert?: boolean): number;
writeDoubleLE(value: number, offset: number, noAssert?: boolean): number;
writeDoubleBE(value: number, offset: number, noAssert?: boolean): number;
fill(value: any, offset?: number, end?: number): this;
indexOf(value: string | number | Buffer, byteOffset?: number, encoding?: string): number;
lastIndexOf(value: string | number | Buffer, byteOffset?: number, encoding?: string): number;
includes(value: string | number | Buffer, byteOffset?: number, encoding?: string): boolean;
/**
* Allocates a new buffer containing the given {str}.
*
* @param str String to store in buffer.
* @param encoding encoding to use, optional. Default is 'utf8'
*/
constructor (str: string, encoding?: string);
/**
* Allocates a new buffer of {size} octets.
*
* @param size count of octets to allocate.
*/
constructor (size: number);
/**
* Allocates a new buffer containing the given {array} of octets.
*
* @param array The octets to store.
*/
constructor (array: Uint8Array);
/**
* Produces a Buffer backed by the same allocated memory as
* the given {ArrayBuffer}.
*
*
* @param arrayBuffer The ArrayBuffer with which to share memory.
*/
constructor (arrayBuffer: ArrayBuffer);
/**
* Allocates a new buffer containing the given {array} of octets.
*
* @param array The octets to store.
*/
constructor (array: any[]);
/**
* Copies the passed {buffer} data onto a new {Buffer} instance.
*
* @param buffer The buffer to copy.
*/
constructor (buffer: Buffer);
prototype: Buffer;
/**
* Allocates a new Buffer using an {array} of octets.
*
* @param array
*/
static from(array: any[]): Buffer;
/**
* When passed a reference to the .buffer property of a TypedArray instance,
* the newly created Buffer will share the same allocated memory as the TypedArray.
* The optional {byteOffset} and {length} arguments specify a memory range
* within the {arrayBuffer} that will be shared by the Buffer.
*
* @param arrayBuffer The .buffer property of a TypedArray or a new ArrayBuffer()
* @param byteOffset
* @param length
*/
static from(arrayBuffer: ArrayBuffer, byteOffset?: number, length?: number): Buffer;
/**
* Copies the passed {buffer} data onto a new Buffer instance.
*
* @param buffer
*/
static from(buffer: Buffer): Buffer;
/**
* Creates a new Buffer containing the given JavaScript string {str}.
* If provided, the {encoding} parameter identifies the character encoding.
* If not provided, {encoding} defaults to 'utf8'.
*
* @param str
*/
static from(str: string, encoding?: string): Buffer;
/**
* Returns true if {obj} is a Buffer
*
* @param obj object to test.
*/
static isBuffer(obj: any): obj is Buffer;
/**
* Returns true if {encoding} is a valid encoding argument.
* Valid string encodings in Node 0.12: 'ascii'|'utf8'|'utf16le'|'ucs2'(alias of 'utf16le')|'base64'|'binary'(deprecated)|'hex'
*
* @param encoding string to test.
*/
static isEncoding(encoding: string): boolean;
/**
* Gives the actual byte length of a string. encoding defaults to 'utf8'.
* This is not the same as String.prototype.length since that returns the number of characters in a string.
*
* @param string string to test.
* @param encoding encoding used to evaluate (defaults to 'utf8')
*/
static byteLength(string: string, encoding?: string): number;
/**
* Returns a buffer which is the result of concatenating all the buffers in the list together.
*
* If the list has no items, or if the totalLength is 0, then it returns a zero-length buffer.
* If the list has exactly one item, then the first item of the list is returned.
* If the list has more than one item, then a new Buffer is created.
*
* @param list An array of Buffer objects to concatenate
* @param totalLength Total length of the buffers when concatenated.
* If totalLength is not provided, it is read from the buffers in the list. However, this adds an additional loop to the function, so it is faster to provide the length explicitly.
*/
static concat(list: Buffer[], totalLength?: number): Buffer;
/**
* The same as buf1.compare(buf2).
*/
static compare(buf1: Buffer, buf2: Buffer): number;
/**
* Allocates a new buffer of {size} octets.
*
* @param size count of octets to allocate.
* @param fill if specified, buffer will be initialized by calling buf.fill(fill).
* If parameter is omitted, buffer will be filled with zeros.
* @param encoding encoding used for call to buf.fill while initalizing
*/
static alloc(size: number, fill?: string | Buffer | number, encoding?: string): Buffer;
/**
* Allocates a new buffer of {size} octets, leaving memory not initialized, so the contents
* of the newly created Buffer are unknown and may contain sensitive data.
*
* @param size count of octets to allocate
*/
static allocUnsafe(size: number): Buffer;
/**
* Allocates a new non-pooled buffer of {size} octets, leaving memory not initialized, so the contents
* of the newly created Buffer are unknown and may contain sensitive data.
*
* @param size count of octets to allocate
*/
static allocUnsafeSlow(size: number): Buffer;
}
}

65
node_modules/safe-buffer/index.js generated vendored Normal file
View File

@ -0,0 +1,65 @@
/*! safe-buffer. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
/* eslint-disable node/no-deprecated-api */
var buffer = require('buffer')
var Buffer = buffer.Buffer
// alternative to using Object.keys for old browsers
function copyProps (src, dst) {
for (var key in src) {
dst[key] = src[key]
}
}
if (Buffer.from && Buffer.alloc && Buffer.allocUnsafe && Buffer.allocUnsafeSlow) {
module.exports = buffer
} else {
// Copy properties from require('buffer')
copyProps(buffer, exports)
exports.Buffer = SafeBuffer
}
function SafeBuffer (arg, encodingOrOffset, length) {
return Buffer(arg, encodingOrOffset, length)
}
SafeBuffer.prototype = Object.create(Buffer.prototype)
// Copy static methods from Buffer
copyProps(Buffer, SafeBuffer)
SafeBuffer.from = function (arg, encodingOrOffset, length) {
if (typeof arg === 'number') {
throw new TypeError('Argument must not be a number')
}
return Buffer(arg, encodingOrOffset, length)
}
SafeBuffer.alloc = function (size, fill, encoding) {
if (typeof size !== 'number') {
throw new TypeError('Argument must be a number')
}
var buf = Buffer(size)
if (fill !== undefined) {
if (typeof encoding === 'string') {
buf.fill(fill, encoding)
} else {
buf.fill(fill)
}
} else {
buf.fill(0)
}
return buf
}
SafeBuffer.allocUnsafe = function (size) {
if (typeof size !== 'number') {
throw new TypeError('Argument must be a number')
}
return Buffer(size)
}
SafeBuffer.allocUnsafeSlow = function (size) {
if (typeof size !== 'number') {
throw new TypeError('Argument must be a number')
}
return buffer.SlowBuffer(size)
}

51
node_modules/safe-buffer/package.json generated vendored Normal file
View File

@ -0,0 +1,51 @@
{
"name": "safe-buffer",
"description": "Safer Node.js Buffer API",
"version": "5.2.1",
"author": {
"name": "Feross Aboukhadijeh",
"email": "feross@feross.org",
"url": "https://feross.org"
},
"bugs": {
"url": "https://github.com/feross/safe-buffer/issues"
},
"devDependencies": {
"standard": "*",
"tape": "^5.0.0"
},
"homepage": "https://github.com/feross/safe-buffer",
"keywords": [
"buffer",
"buffer allocate",
"node security",
"safe",
"safe-buffer",
"security",
"uninitialized"
],
"license": "MIT",
"main": "index.js",
"types": "index.d.ts",
"repository": {
"type": "git",
"url": "git://github.com/feross/safe-buffer.git"
},
"scripts": {
"test": "standard && tape test/*.js"
},
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
]
}

15
node_modules/wrappy/LICENSE generated vendored Normal file
View File

@ -0,0 +1,15 @@
The ISC License
Copyright (c) Isaac Z. Schlueter and Contributors
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

36
node_modules/wrappy/README.md generated vendored Normal file
View File

@ -0,0 +1,36 @@
# wrappy
Callback wrapping utility
## USAGE
```javascript
var wrappy = require("wrappy")
// var wrapper = wrappy(wrapperFunction)
// make sure a cb is called only once
// See also: http://npm.im/once for this specific use case
var once = wrappy(function (cb) {
var called = false
return function () {
if (called) return
called = true
return cb.apply(this, arguments)
}
})
function printBoo () {
console.log('boo')
}
// has some rando property
printBoo.iAmBooPrinter = true
var onlyPrintOnce = once(printBoo)
onlyPrintOnce() // prints 'boo'
onlyPrintOnce() // does nothing
// random property is retained!
assert.equal(onlyPrintOnce.iAmBooPrinter, true)
```

29
node_modules/wrappy/package.json generated vendored Normal file
View File

@ -0,0 +1,29 @@
{
"name": "wrappy",
"version": "1.0.2",
"description": "Callback wrapping utility",
"main": "wrappy.js",
"files": [
"wrappy.js"
],
"directories": {
"test": "test"
},
"dependencies": {},
"devDependencies": {
"tap": "^2.3.1"
},
"scripts": {
"test": "tap --coverage test/*.js"
},
"repository": {
"type": "git",
"url": "https://github.com/npm/wrappy"
},
"author": "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me/)",
"license": "ISC",
"bugs": {
"url": "https://github.com/npm/wrappy/issues"
},
"homepage": "https://github.com/npm/wrappy"
}

33
node_modules/wrappy/wrappy.js generated vendored Normal file
View File

@ -0,0 +1,33 @@
// Returns a wrapper function that returns a wrapped callback
// The wrapper function should do some stuff, and return a
// presumably different callback function.
// This makes sure that own properties are retained, so that
// decorations and such are not lost along the way.
module.exports = wrappy
function wrappy (fn, cb) {
if (fn && cb) return wrappy(fn)(cb)
if (typeof fn !== 'function')
throw new TypeError('need wrapper function')
Object.keys(fn).forEach(function (k) {
wrapper[k] = fn[k]
})
return wrapper
function wrapper() {
var args = new Array(arguments.length)
for (var i = 0; i < args.length; i++) {
args[i] = arguments[i]
}
var ret = fn.apply(this, args)
var cb = args[args.length-1]
if (typeof ret === 'function' && ret !== cb) {
Object.keys(cb).forEach(function (k) {
ret[k] = cb[k]
})
}
return ret
}
}

226
package-lock.json generated Normal file
View File

@ -0,0 +1,226 @@
{
"name": "pandoc-cloudron",
"version": "1.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "pandoc-cloudron",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"content-disposition": "^0.5.4",
"destroy": "^1.1.0",
"formidable": "^2.0.1",
"fs": "^0.0.1-security",
"on-finished": "^2.3.0"
}
},
"node_modules/asap": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
"integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY="
},
"node_modules/content-disposition": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
"integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
"dependencies": {
"safe-buffer": "5.2.1"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/destroy": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.1.0.tgz",
"integrity": "sha512-R5QZrOXxSs0JDUIU/VANvRJlQVMts9C0L76HToQdPdlftfZCE7W6dyH0G4GZ5UW9fRqUOhAoCE2aGekuu+3HjQ==",
"engines": {
"node": ">= 0.8",
"npm": "1.2.8000 || >= 1.4.16"
}
},
"node_modules/dezalgo": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz",
"integrity": "sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY=",
"dependencies": {
"asap": "^2.0.0",
"wrappy": "1"
}
},
"node_modules/ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
},
"node_modules/formidable": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/formidable/-/formidable-2.0.1.tgz",
"integrity": "sha512-rjTMNbp2BpfQShhFbR3Ruk3qk2y9jKpvMW78nJgx8QKtxjDVrwbZG+wvDOmVbifHyOUOQJXxqEy6r0faRrPzTQ==",
"dependencies": {
"dezalgo": "1.0.3",
"hexoid": "1.0.0",
"once": "1.4.0",
"qs": "6.9.3"
},
"funding": {
"url": "https://ko-fi.com/tunnckoCore/commissions"
}
},
"node_modules/fs": {
"version": "0.0.1-security",
"resolved": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz",
"integrity": "sha1-invTcYa23d84E/I4WLV+yq9eQdQ="
},
"node_modules/hexoid": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz",
"integrity": "sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==",
"engines": {
"node": ">=8"
}
},
"node_modules/on-finished": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
"integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
"dependencies": {
"ee-first": "1.1.1"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"dependencies": {
"wrappy": "1"
}
},
"node_modules/qs": {
"version": "6.9.3",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.9.3.tgz",
"integrity": "sha512-EbZYNarm6138UKKq46tdx08Yo/q9ZhFoAXAI1meAFd2GtbRDhbZY2WQSICskT0c5q99aFzLG1D4nvTk9tqfXIw==",
"engines": {
"node": ">=0.6"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
]
},
"node_modules/wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
}
},
"dependencies": {
"asap": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
"integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY="
},
"content-disposition": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
"integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
"requires": {
"safe-buffer": "5.2.1"
}
},
"destroy": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.1.0.tgz",
"integrity": "sha512-R5QZrOXxSs0JDUIU/VANvRJlQVMts9C0L76HToQdPdlftfZCE7W6dyH0G4GZ5UW9fRqUOhAoCE2aGekuu+3HjQ=="
},
"dezalgo": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz",
"integrity": "sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY=",
"requires": {
"asap": "^2.0.0",
"wrappy": "1"
}
},
"ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
},
"formidable": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/formidable/-/formidable-2.0.1.tgz",
"integrity": "sha512-rjTMNbp2BpfQShhFbR3Ruk3qk2y9jKpvMW78nJgx8QKtxjDVrwbZG+wvDOmVbifHyOUOQJXxqEy6r0faRrPzTQ==",
"requires": {
"dezalgo": "1.0.3",
"hexoid": "1.0.0",
"once": "1.4.0",
"qs": "6.9.3"
}
},
"fs": {
"version": "0.0.1-security",
"resolved": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz",
"integrity": "sha1-invTcYa23d84E/I4WLV+yq9eQdQ="
},
"hexoid": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz",
"integrity": "sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g=="
},
"on-finished": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
"integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
"requires": {
"ee-first": "1.1.1"
}
},
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"requires": {
"wrappy": "1"
}
},
"qs": {
"version": "6.9.3",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.9.3.tgz",
"integrity": "sha512-EbZYNarm6138UKKq46tdx08Yo/q9ZhFoAXAI1meAFd2GtbRDhbZY2WQSICskT0c5q99aFzLG1D4nvTk9tqfXIw=="
},
"safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
}
}
}

Some files were not shown because too many files have changed in this diff Show More