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) {