Initial commit
This commit is contained in:
commit
dfbb21800b
5220 files changed
+368059
No files matched your search
+16
@@ -0,0 +1,16 @@
|
||||
#!/bin/sh
|
||||
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
||||
|
||||
case `uname` in
|
||||
*CYGWIN*|*MINGW*|*MSYS*)
|
||||
if command -v cygpath > /dev/null 2>&1; then
|
||||
basedir=`cygpath -w "$basedir"`
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -x "$basedir/node" ]; then
|
||||
exec "$basedir/node" "$basedir/../mime/cli.js" "$@"
|
||||
else
|
||||
exec node "$basedir/../mime/cli.js" "$@"
|
||||
fi
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
@ECHO off
|
||||
GOTO start
|
||||
:find_dp0
|
||||
SET dp0=%~dp0
|
||||
EXIT /b
|
||||
:start
|
||||
SETLOCAL
|
||||
CALL :find_dp0
|
||||
|
||||
IF EXIST "%dp0%\node.exe" (
|
||||
SET "_prog=%dp0%\node.exe"
|
||||
) ELSE (
|
||||
SET "_prog=node"
|
||||
SET PATHEXT=%PATHEXT:;.JS;=;%
|
||||
)
|
||||
|
||||
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\mime\cli.js" %*
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env pwsh
|
||||
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
|
||||
|
||||
$exe=""
|
||||
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
|
||||
# Fix case when both the Windows and Linux builds of Node
|
||||
# are installed in the same directory
|
||||
$exe=".exe"
|
||||
}
|
||||
$ret=0
|
||||
if (Test-Path "$basedir/node$exe") {
|
||||
# Support pipeline input
|
||||
if ($MyInvocation.ExpectingInput) {
|
||||
$input | & "$basedir/node$exe" "$basedir/../mime/cli.js" $args
|
||||
} else {
|
||||
& "$basedir/node$exe" "$basedir/../mime/cli.js" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
} else {
|
||||
# Support pipeline input
|
||||
if ($MyInvocation.ExpectingInput) {
|
||||
$input | & "node$exe" "$basedir/../mime/cli.js" $args
|
||||
} else {
|
||||
& "node$exe" "$basedir/../mime/cli.js" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
}
|
||||
exit $ret
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
#!/bin/sh
|
||||
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
||||
|
||||
case `uname` in
|
||||
*CYGWIN*|*MINGW*|*MSYS*)
|
||||
if command -v cygpath > /dev/null 2>&1; then
|
||||
basedir=`cygpath -w "$basedir"`
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -x "$basedir/node" ]; then
|
||||
exec "$basedir/node" "$basedir/../sshpk/bin/sshpk-conv" "$@"
|
||||
else
|
||||
exec node "$basedir/../sshpk/bin/sshpk-conv" "$@"
|
||||
fi
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
@ECHO off
|
||||
GOTO start
|
||||
:find_dp0
|
||||
SET dp0=%~dp0
|
||||
EXIT /b
|
||||
:start
|
||||
SETLOCAL
|
||||
CALL :find_dp0
|
||||
|
||||
IF EXIST "%dp0%\node.exe" (
|
||||
SET "_prog=%dp0%\node.exe"
|
||||
) ELSE (
|
||||
SET "_prog=node"
|
||||
SET PATHEXT=%PATHEXT:;.JS;=;%
|
||||
)
|
||||
|
||||
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\sshpk\bin\sshpk-conv" %*
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env pwsh
|
||||
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
|
||||
|
||||
$exe=""
|
||||
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
|
||||
# Fix case when both the Windows and Linux builds of Node
|
||||
# are installed in the same directory
|
||||
$exe=".exe"
|
||||
}
|
||||
$ret=0
|
||||
if (Test-Path "$basedir/node$exe") {
|
||||
# Support pipeline input
|
||||
if ($MyInvocation.ExpectingInput) {
|
||||
$input | & "$basedir/node$exe" "$basedir/../sshpk/bin/sshpk-conv" $args
|
||||
} else {
|
||||
& "$basedir/node$exe" "$basedir/../sshpk/bin/sshpk-conv" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
} else {
|
||||
# Support pipeline input
|
||||
if ($MyInvocation.ExpectingInput) {
|
||||
$input | & "node$exe" "$basedir/../sshpk/bin/sshpk-conv" $args
|
||||
} else {
|
||||
& "node$exe" "$basedir/../sshpk/bin/sshpk-conv" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
}
|
||||
exit $ret
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
#!/bin/sh
|
||||
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
||||
|
||||
case `uname` in
|
||||
*CYGWIN*|*MINGW*|*MSYS*)
|
||||
if command -v cygpath > /dev/null 2>&1; then
|
||||
basedir=`cygpath -w "$basedir"`
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -x "$basedir/node" ]; then
|
||||
exec "$basedir/node" "$basedir/../sshpk/bin/sshpk-sign" "$@"
|
||||
else
|
||||
exec node "$basedir/../sshpk/bin/sshpk-sign" "$@"
|
||||
fi
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
@ECHO off
|
||||
GOTO start
|
||||
:find_dp0
|
||||
SET dp0=%~dp0
|
||||
EXIT /b
|
||||
:start
|
||||
SETLOCAL
|
||||
CALL :find_dp0
|
||||
|
||||
IF EXIST "%dp0%\node.exe" (
|
||||
SET "_prog=%dp0%\node.exe"
|
||||
) ELSE (
|
||||
SET "_prog=node"
|
||||
SET PATHEXT=%PATHEXT:;.JS;=;%
|
||||
)
|
||||
|
||||
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\sshpk\bin\sshpk-sign" %*
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env pwsh
|
||||
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
|
||||
|
||||
$exe=""
|
||||
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
|
||||
# Fix case when both the Windows and Linux builds of Node
|
||||
# are installed in the same directory
|
||||
$exe=".exe"
|
||||
}
|
||||
$ret=0
|
||||
if (Test-Path "$basedir/node$exe") {
|
||||
# Support pipeline input
|
||||
if ($MyInvocation.ExpectingInput) {
|
||||
$input | & "$basedir/node$exe" "$basedir/../sshpk/bin/sshpk-sign" $args
|
||||
} else {
|
||||
& "$basedir/node$exe" "$basedir/../sshpk/bin/sshpk-sign" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
} else {
|
||||
# Support pipeline input
|
||||
if ($MyInvocation.ExpectingInput) {
|
||||
$input | & "node$exe" "$basedir/../sshpk/bin/sshpk-sign" $args
|
||||
} else {
|
||||
& "node$exe" "$basedir/../sshpk/bin/sshpk-sign" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
}
|
||||
exit $ret
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
#!/bin/sh
|
||||
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
||||
|
||||
case `uname` in
|
||||
*CYGWIN*|*MINGW*|*MSYS*)
|
||||
if command -v cygpath > /dev/null 2>&1; then
|
||||
basedir=`cygpath -w "$basedir"`
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -x "$basedir/node" ]; then
|
||||
exec "$basedir/node" "$basedir/../sshpk/bin/sshpk-verify" "$@"
|
||||
else
|
||||
exec node "$basedir/../sshpk/bin/sshpk-verify" "$@"
|
||||
fi
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
@ECHO off
|
||||
GOTO start
|
||||
:find_dp0
|
||||
SET dp0=%~dp0
|
||||
EXIT /b
|
||||
:start
|
||||
SETLOCAL
|
||||
CALL :find_dp0
|
||||
|
||||
IF EXIST "%dp0%\node.exe" (
|
||||
SET "_prog=%dp0%\node.exe"
|
||||
) ELSE (
|
||||
SET "_prog=node"
|
||||
SET PATHEXT=%PATHEXT:;.JS;=;%
|
||||
)
|
||||
|
||||
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\sshpk\bin\sshpk-verify" %*
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env pwsh
|
||||
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
|
||||
|
||||
$exe=""
|
||||
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
|
||||
# Fix case when both the Windows and Linux builds of Node
|
||||
# are installed in the same directory
|
||||
$exe=".exe"
|
||||
}
|
||||
$ret=0
|
||||
if (Test-Path "$basedir/node$exe") {
|
||||
# Support pipeline input
|
||||
if ($MyInvocation.ExpectingInput) {
|
||||
$input | & "$basedir/node$exe" "$basedir/../sshpk/bin/sshpk-verify" $args
|
||||
} else {
|
||||
& "$basedir/node$exe" "$basedir/../sshpk/bin/sshpk-verify" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
} else {
|
||||
# Support pipeline input
|
||||
if ($MyInvocation.ExpectingInput) {
|
||||
$input | & "node$exe" "$basedir/../sshpk/bin/sshpk-verify" $args
|
||||
} else {
|
||||
& "node$exe" "$basedir/../sshpk/bin/sshpk-verify" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
}
|
||||
exit $ret
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
#!/bin/sh
|
||||
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
||||
|
||||
case `uname` in
|
||||
*CYGWIN*|*MINGW*|*MSYS*)
|
||||
if command -v cygpath > /dev/null 2>&1; then
|
||||
basedir=`cygpath -w "$basedir"`
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -x "$basedir/node" ]; then
|
||||
exec "$basedir/node" "$basedir/../tldts/bin/cli.js" "$@"
|
||||
else
|
||||
exec node "$basedir/../tldts/bin/cli.js" "$@"
|
||||
fi
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
@ECHO off
|
||||
GOTO start
|
||||
:find_dp0
|
||||
SET dp0=%~dp0
|
||||
EXIT /b
|
||||
:start
|
||||
SETLOCAL
|
||||
CALL :find_dp0
|
||||
|
||||
IF EXIST "%dp0%\node.exe" (
|
||||
SET "_prog=%dp0%\node.exe"
|
||||
) ELSE (
|
||||
SET "_prog=node"
|
||||
SET PATHEXT=%PATHEXT:;.JS;=;%
|
||||
)
|
||||
|
||||
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\tldts\bin\cli.js" %*
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env pwsh
|
||||
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
|
||||
|
||||
$exe=""
|
||||
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
|
||||
# Fix case when both the Windows and Linux builds of Node
|
||||
# are installed in the same directory
|
||||
$exe=".exe"
|
||||
}
|
||||
$ret=0
|
||||
if (Test-Path "$basedir/node$exe") {
|
||||
# Support pipeline input
|
||||
if ($MyInvocation.ExpectingInput) {
|
||||
$input | & "$basedir/node$exe" "$basedir/../tldts/bin/cli.js" $args
|
||||
} else {
|
||||
& "$basedir/node$exe" "$basedir/../tldts/bin/cli.js" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
} else {
|
||||
# Support pipeline input
|
||||
if ($MyInvocation.ExpectingInput) {
|
||||
$input | & "node$exe" "$basedir/../tldts/bin/cli.js" $args
|
||||
} else {
|
||||
& "node$exe" "$basedir/../tldts/bin/cli.js" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
}
|
||||
exit $ret
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
#!/bin/sh
|
||||
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
||||
|
||||
case `uname` in
|
||||
*CYGWIN*|*MINGW*|*MSYS*)
|
||||
if command -v cygpath > /dev/null 2>&1; then
|
||||
basedir=`cygpath -w "$basedir"`
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -x "$basedir/node" ]; then
|
||||
exec "$basedir/node" "$basedir/../uuid/dist/bin/uuid" "$@"
|
||||
else
|
||||
exec node "$basedir/../uuid/dist/bin/uuid" "$@"
|
||||
fi
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
@ECHO off
|
||||
GOTO start
|
||||
:find_dp0
|
||||
SET dp0=%~dp0
|
||||
EXIT /b
|
||||
:start
|
||||
SETLOCAL
|
||||
CALL :find_dp0
|
||||
|
||||
IF EXIST "%dp0%\node.exe" (
|
||||
SET "_prog=%dp0%\node.exe"
|
||||
) ELSE (
|
||||
SET "_prog=node"
|
||||
SET PATHEXT=%PATHEXT:;.JS;=;%
|
||||
)
|
||||
|
||||
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\uuid\dist\bin\uuid" %*
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env pwsh
|
||||
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
|
||||
|
||||
$exe=""
|
||||
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
|
||||
# Fix case when both the Windows and Linux builds of Node
|
||||
# are installed in the same directory
|
||||
$exe=".exe"
|
||||
}
|
||||
$ret=0
|
||||
if (Test-Path "$basedir/node$exe") {
|
||||
# Support pipeline input
|
||||
if ($MyInvocation.ExpectingInput) {
|
||||
$input | & "$basedir/node$exe" "$basedir/../uuid/dist/bin/uuid" $args
|
||||
} else {
|
||||
& "$basedir/node$exe" "$basedir/../uuid/dist/bin/uuid" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
} else {
|
||||
# Support pipeline input
|
||||
if ($MyInvocation.ExpectingInput) {
|
||||
$input | & "node$exe" "$basedir/../uuid/dist/bin/uuid" $args
|
||||
} else {
|
||||
& "node$exe" "$basedir/../uuid/dist/bin/uuid" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
}
|
||||
exit $ret
|
||||
+1963
File diff suppressed because it is too large.
Load diff
+46
@@ -0,0 +1,46 @@
|
||||
version: 2.1
|
||||
jobs:
|
||||
test:
|
||||
docker:
|
||||
- image: circleci/node:11.5.0
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- checkout
|
||||
|
||||
- restore_cache:
|
||||
keys:
|
||||
- v1-dependencies-{{ checksum "package.json" }}
|
||||
- v1-dependencies-
|
||||
- run: yarn install
|
||||
- save_cache:
|
||||
paths:
|
||||
- node_modules
|
||||
key: v1-dependencies-{{ checksum "package.json" }}
|
||||
- run: yarn test
|
||||
|
||||
release:
|
||||
docker:
|
||||
- image: cimg/node:18.12.1
|
||||
steps:
|
||||
- checkout
|
||||
- restore_cache:
|
||||
keys:
|
||||
- v1-dependencies-{{ checksum "package.json" }}
|
||||
- v1-dependencies-
|
||||
- run: yarn install
|
||||
- run: npx semantic-release
|
||||
|
||||
workflows:
|
||||
version: 2.1
|
||||
test_and_release:
|
||||
jobs:
|
||||
- test
|
||||
- release:
|
||||
context:
|
||||
- test-runner:npm-release
|
||||
requires:
|
||||
- test
|
||||
filters:
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2019, Nicolai Kamenzky, Ty Abonil, 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.
|
||||
+760
@@ -0,0 +1,760 @@
|
||||
<a href="http://promisesaplus.com/">
|
||||
<img src="https://promises-aplus.github.io/promises-spec/assets/logo-small.png" align="right" alt="Promises/A+ logo" />
|
||||
</a>
|
||||
|
||||
# Request-Promise
|
||||
|
||||
[](https://gitter.im/request/request-promise?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
[](https://travis-ci.org/request/request-promise)
|
||||
[](https://coveralls.io/r/request/request-promise)
|
||||
[](https://david-dm.org/request/request-promise)
|
||||
[](https://snyk.io/test/npm/request-promise)
|
||||
|
||||
# Deprecated!
|
||||
|
||||
As of Feb 11th 2020, [`request`](https://github.com/request/request) is fully deprecated. No new changes are expected to land. In fact, none have landed for some time. This package is also deprecated because it depends on `request`.
|
||||
|
||||
Fyi, here is the [reasoning of `request`'s deprecation](https://github.com/request/request/issues/3142) and a [list of alternative libraries](https://github.com/request/request/issues/3143).
|
||||
|
||||
---
|
||||
|
||||
The simplified HTTP request client 'request' with Promise support. Powered by Bluebird.
|
||||
|
||||
[Request](https://github.com/request/request) and [Bluebird](https://github.com/petkaantonov/bluebird) are pretty awesome, but I found myself using the same design pattern. Request-Promise adds a Bluebird-powered `.then(...)` method to Request call objects. By default, http response codes other than 2xx will cause the promise to be rejected. This can be overwritten by setting `options.simple = false`.
|
||||
|
||||
Also check out the new libraries that are **very similar to `request-promise` v4**:
|
||||
- [`request-promise-native`](https://github.com/request/request-promise-native) v1 – Does not depend on Bluebird and uses native ES6 promises instead.
|
||||
- [`request-promise-any`](https://github.com/request/request-promise-any) v1 – Allows you to register any Promise library supported by [`any-promise`](https://www.npmjs.com/package/any-promise).
|
||||
|
||||
---
|
||||
|
||||
## Migration from v3 to v4
|
||||
|
||||
1. `request` became a peer dependency. Thus make sure that `request` is installed into your project as a direct dependency. (`npm install --save request`)
|
||||
2. Continuation Local Storage is no longer supported. However, you [can get back the support](https://github.com/request/request-promise/wiki/Getting-Back-Support-for-Continuation-Local-Storage) by using `request-promise-any`.
|
||||
3. When you migrated your `transform` function to v3 and had to add `if (!(/^2/.test('' + response.statusCode))) { return resolveWithFullResponse ? response : body; }` you may now set the option `transform2xxOnly = true` instead.
|
||||
|
||||
## Migration from v2 to v3
|
||||
|
||||
1. The handling of the `transform` function got overhauled. This has two effects:
|
||||
- `StatusCodeError.response` is the transformed instead of the original response now. This error is thrown for non-2xx responses when `options.simple` is `true` (default). Please update your `transform` functions to also cover the transformation of non-2xx responses. To get the old behavior you may add `if (!(/^2/.test('' + response.statusCode))) { return resolveWithFullResponse ? response : body; }` to the first line of your `transform` functions that are used for requests with `options.simple === true`. However, you may prefer updating your `transform` functions to being able to transform 2xx as well as non-2xx responses because this decouples their implementation from the use of the `simple` option when doing requests.
|
||||
- If a transform operation throws an error, the request will be rejected with a `TransformError`. Its `cause` attribute contains the error thrown by the transform operation. Previously, the request was rejected directly with the error thrown by the transform operation. Wrapping it into a `TransformError` makes the error handling easier.
|
||||
|
||||
2. Bluebird got updated from v2 to v3. This won't make a difference for most use cases. However, if you use advanced Promise chains starting with the Promise returned by Request-Promise, please check [Bluebird's new features and changes](http://bluebirdjs.com/docs/new-in-bluebird-3.html).
|
||||
|
||||
---
|
||||
|
||||
## Installation
|
||||
|
||||
This module is installed via npm:
|
||||
|
||||
```
|
||||
npm install --save request
|
||||
npm install --save request-promise
|
||||
```
|
||||
|
||||
`request` is defined as a peer-dependency and thus has to be installed separately.
|
||||
|
||||
## Cheat Sheet
|
||||
|
||||
``` js
|
||||
var rp = require('request-promise');
|
||||
```
|
||||
|
||||
Since `request-promise` wraps around `request` everything that works with `request` also works with `request-promise`. Also check out the [`request` docs](https://github.com/request/request) for more examples.
|
||||
|
||||
### Crawl a webpage
|
||||
|
||||
``` js
|
||||
rp('http://www.google.com')
|
||||
.then(function (htmlString) {
|
||||
// Process html...
|
||||
})
|
||||
.catch(function (err) {
|
||||
// Crawling failed...
|
||||
});
|
||||
```
|
||||
|
||||
### Crawl a webpage better
|
||||
|
||||
``` js
|
||||
var cheerio = require('cheerio'); // Basically jQuery for node.js
|
||||
|
||||
var options = {
|
||||
uri: 'http://www.google.com',
|
||||
transform: function (body) {
|
||||
return cheerio.load(body);
|
||||
}
|
||||
};
|
||||
|
||||
rp(options)
|
||||
.then(function ($) {
|
||||
// Process html like you would with jQuery...
|
||||
})
|
||||
.catch(function (err) {
|
||||
// Crawling failed or Cheerio choked...
|
||||
});
|
||||
```
|
||||
|
||||
### GET something from a JSON REST API
|
||||
|
||||
``` js
|
||||
var options = {
|
||||
uri: 'https://api.github.com/user/repos',
|
||||
qs: {
|
||||
access_token: 'xxxxx xxxxx' // -> uri + '?access_token=xxxxx%20xxxxx'
|
||||
},
|
||||
headers: {
|
||||
'User-Agent': 'Request-Promise'
|
||||
},
|
||||
json: true // Automatically parses the JSON string in the response
|
||||
};
|
||||
|
||||
rp(options)
|
||||
.then(function (repos) {
|
||||
console.log('User has %d repos', repos.length);
|
||||
})
|
||||
.catch(function (err) {
|
||||
// API call failed...
|
||||
});
|
||||
```
|
||||
|
||||
### POST data to a JSON REST API
|
||||
|
||||
Set `option.body` to your data and `json: true` to encode the body as JSON. See below for HTML forms.
|
||||
|
||||
``` js
|
||||
var options = {
|
||||
method: 'POST',
|
||||
uri: 'http://api.posttestserver.com/post',
|
||||
body: {
|
||||
some: 'payload'
|
||||
},
|
||||
json: true // Automatically stringifies the body to JSON
|
||||
};
|
||||
|
||||
rp(options)
|
||||
.then(function (parsedBody) {
|
||||
// POST succeeded...
|
||||
})
|
||||
.catch(function (err) {
|
||||
// POST failed...
|
||||
});
|
||||
```
|
||||
|
||||
### POST like HTML forms do
|
||||
|
||||
Pass your data to `options.form` to encode the body the same way as HTML forms do:
|
||||
|
||||
``` js
|
||||
var options = {
|
||||
method: 'POST',
|
||||
uri: 'http://posttestserver.com/post.php',
|
||||
form: {
|
||||
// Like <input type="text" name="name">
|
||||
name: 'Josh'
|
||||
},
|
||||
headers: {
|
||||
/* 'content-type': 'application/x-www-form-urlencoded' */ // Is set automatically
|
||||
}
|
||||
};
|
||||
|
||||
rp(options)
|
||||
.then(function (body) {
|
||||
// POST succeeded...
|
||||
})
|
||||
.catch(function (err) {
|
||||
// POST failed...
|
||||
});
|
||||
```
|
||||
|
||||
If you want to include a file upload then use `options.formData`:
|
||||
|
||||
``` js
|
||||
var options = {
|
||||
method: 'POST',
|
||||
uri: 'http://posttestserver.com/post.php',
|
||||
formData: {
|
||||
// Like <input type="text" name="name">
|
||||
name: 'Jenn',
|
||||
// Like <input type="file" name="file">
|
||||
file: {
|
||||
value: fs.createReadStream('test/test.jpg'),
|
||||
options: {
|
||||
filename: 'test.jpg',
|
||||
contentType: 'image/jpg'
|
||||
}
|
||||
}
|
||||
},
|
||||
headers: {
|
||||
/* 'content-type': 'multipart/form-data' */ // Is set automatically
|
||||
}
|
||||
};
|
||||
|
||||
rp(options)
|
||||
.then(function (body) {
|
||||
// POST succeeded...
|
||||
})
|
||||
.catch(function (err) {
|
||||
// POST failed...
|
||||
});
|
||||
```
|
||||
|
||||
### Include a cookie
|
||||
|
||||
``` js
|
||||
var tough = require('tough-cookie');
|
||||
|
||||
// Easy creation of the cookie - see tough-cookie docs for details
|
||||
let cookie = new tough.Cookie({
|
||||
key: "some_key",
|
||||
value: "some_value",
|
||||
domain: 'api.mydomain.com',
|
||||
httpOnly: true,
|
||||
maxAge: 31536000
|
||||
});
|
||||
|
||||
// Put cookie in an jar which can be used across multiple requests
|
||||
var cookiejar = rp.jar();
|
||||
cookiejar.setCookie(cookie, 'https://api.mydomain.com');
|
||||
// ...all requests to https://api.mydomain.com will include the cookie
|
||||
|
||||
var options = {
|
||||
uri: 'https://api.mydomain.com/...',
|
||||
jar: cookiejar // Tells rp to include cookies in jar that match uri
|
||||
};
|
||||
|
||||
rp(options)
|
||||
.then(function (body) {
|
||||
// Request succeeded...
|
||||
})
|
||||
.catch(function (err) {
|
||||
// Request failed...
|
||||
});
|
||||
```
|
||||
|
||||
### Get the full response instead of just the body
|
||||
|
||||
``` js
|
||||
var options = {
|
||||
method: 'DELETE',
|
||||
uri: 'http://my-server/path/to/resource/1234',
|
||||
resolveWithFullResponse: true // <--- <--- <--- <---
|
||||
};
|
||||
|
||||
rp(options)
|
||||
.then(function (response) {
|
||||
console.log("DELETE succeeded with status %d", response.statusCode);
|
||||
})
|
||||
.catch(function (err) {
|
||||
// Delete failed...
|
||||
});
|
||||
```
|
||||
|
||||
### Get a rejection only if the request failed for technical reasons
|
||||
|
||||
``` js
|
||||
var options = {
|
||||
uri: 'http://www.google.com/this-page-does-not-exist.html',
|
||||
simple: false // <--- <--- <--- <---
|
||||
};
|
||||
|
||||
rp(options)
|
||||
.then(function (body) {
|
||||
// Request succeeded but might as well be a 404
|
||||
// Usually combined with resolveWithFullResponse = true to check response.statusCode
|
||||
})
|
||||
.catch(function (err) {
|
||||
// Request failed due to technical reasons...
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**For more options checkout the [Request docs](https://github.com/request/request#requestoptions-callback).**
|
||||
|
||||
---
|
||||
|
||||
## API in Detail
|
||||
|
||||
Consider Request-Promise being:
|
||||
|
||||
- A Request object
|
||||
- With an [identical API](https://github.com/request/request): `require('request-promise') == require('request')` so to say
|
||||
- However, **STREAMING THE RESPONSE** (e.g. `.pipe(...)`) is **DISCOURAGED** because Request-Promise would grow the memory footprint for large requests unnecessarily high. Use the original Request library for that. You can use both libraries in the same project.
|
||||
- Plus some methods on a request call object:
|
||||
- `rp(...).then(...)` or e.g. `rp.post(...).then(...)` which turn `rp(...)` and `rp.post(...)` into promises
|
||||
- `rp(...).catch(...)` or e.g. `rp.del(...).catch(...)` which is the same method as provided by Bluebird promises
|
||||
- Errors that the `request` library would pass to the callback are wrapped by `request-promise` and then passed to the catch handler. See [code example](https://github.com/request/request-promise#thenonfulfilled-onrejected) below.
|
||||
- `rp(...).finally(...)` or e.g. `rp.put(...).finally(...)` which is the same method as provided by Bluebird promises
|
||||
- `rp(...).cancel()` or e.g. `rp.get(...).cancel()` which cancels the request
|
||||
- `rp(...).promise()` or e.g. `rp.head(...).promise()` which returns the underlying promise so you can access the full [Bluebird API](https://github.com/petkaantonov/bluebird/blob/master/API.md)
|
||||
- Plus some additional options:
|
||||
- `simple = true` which is a boolean to set whether status codes other than 2xx should also reject the promise
|
||||
- `resolveWithFullResponse = false` which is a boolean to set whether the promise should be resolved with the full response or just the response body
|
||||
- `transform` which takes a function to transform the response into a custom value with which the promise is resolved
|
||||
- `transform2xxOnly = false` which is a boolean to set whether the transform function is applied to all responses or only to those with a 2xx status code
|
||||
|
||||
The objects returned by request calls like `rp(...)` or e.g. `rp.post(...)` are regular Promises/A+ compliant promises and can be assimilated by any compatible promise library.
|
||||
|
||||
The methods `.then(...)`, `.catch(...)`, and `.finally(...)` - which you can call on the request call objects - return a full-fledged Bluebird promise. That means you have the full [Bluebird API](https://github.com/petkaantonov/bluebird/blob/master/API.md) available for further chaining. E.g.: `rp(...).then(...).spread(...)` If, however, you need a method other than `.then(...)`, `.catch(...)`, or `.finally(...)` to be **FIRST** in the chain, use `.promise()`: `rp(...).promise().bind(...).then(...)`
|
||||
|
||||
### .then(onFulfilled, onRejected)
|
||||
|
||||
``` js
|
||||
// As a Request user you would write:
|
||||
var request = require('request');
|
||||
|
||||
request('http://google.com', function (err, response, body) {
|
||||
if (err) {
|
||||
handleError({ error: err, response: response, ... });
|
||||
} else if (!(/^2/.test('' + response.statusCode))) { // Status Codes other than 2xx
|
||||
handleError({ error: body, response: response, ... });
|
||||
} else {
|
||||
process(body);
|
||||
}
|
||||
});
|
||||
|
||||
// As a Request-Promise user you can now write the equivalent code:
|
||||
var rp = require('request-promise');
|
||||
|
||||
rp('http://google.com')
|
||||
.then(process, handleError);
|
||||
```
|
||||
|
||||
``` js
|
||||
// The same is available for all http method shortcuts:
|
||||
request.post('http://example.com/api', function (err, response, body) { ... });
|
||||
rp.post('http://example.com/api').then(...);
|
||||
```
|
||||
|
||||
### .catch(onRejected)
|
||||
|
||||
``` js
|
||||
rp('http://google.com')
|
||||
.catch(handleError);
|
||||
|
||||
// ... is syntactical sugar for:
|
||||
|
||||
rp('http://google.com')
|
||||
.then(null, handleError);
|
||||
|
||||
|
||||
// However, this:
|
||||
rp('http://google.com')
|
||||
.then(process)
|
||||
.catch(handleError);
|
||||
|
||||
// ... is safer than:
|
||||
rp('http://google.com')
|
||||
.then(process, handleError);
|
||||
```
|
||||
|
||||
For more info on `.then(process).catch(handleError)` versus `.then(process, handleError)`, see Bluebird docs on [promise anti-patterns](http://bluebirdjs.com/docs/anti-patterns.html#the-.then).
|
||||
|
||||
### .finally(onFinished)
|
||||
|
||||
``` js
|
||||
rp('http://google.com')
|
||||
.finally(function () {
|
||||
// This is called after the request finishes either successful or not successful.
|
||||
});
|
||||
```
|
||||
|
||||
### .cancel()
|
||||
|
||||
This method cancels the request using [Bluebird's cancellation feature](http://bluebirdjs.com/docs/api/cancellation.html).
|
||||
|
||||
When `.cancel()` is called:
|
||||
|
||||
- the promise will neither be resolved nor rejected and
|
||||
- the request is [aborted](https://nodejs.org/dist/latest-v6.x/docs/api/http.html#http_request_abort).
|
||||
|
||||
### .promise() - For advanced use cases
|
||||
|
||||
In order to not pollute the Request call objects with the methods of the underlying Bluebird promise, only `.then(...)`, `.catch(...)`, and `.finally(...)` were exposed to cover most use cases. The effect is that any methods of a Bluebird promise other than `.then(...)`, `.catch(...)`, or `.finally(...)` cannot be used as the **FIRST** method in the promise chain:
|
||||
|
||||
``` js
|
||||
// This works:
|
||||
rp('http://google.com').then(function () { ... });
|
||||
rp('http://google.com').catch(function () { ... });
|
||||
|
||||
// This works as well since additional methods are only used AFTER the FIRST call in the chain:
|
||||
rp('http://google.com').then(function () { ... }).spread(function () { ... });
|
||||
rp('http://google.com').catch(function () { ... }).error(function () { ... });
|
||||
|
||||
// Using additional methods as the FIRST call in the chain does not work:
|
||||
// rp('http://google.com').bind(this).then(function () { ... });
|
||||
|
||||
// Use .promise() in these cases:
|
||||
rp('http://google.com').promise().bind(this).then(function () { ... });
|
||||
```
|
||||
|
||||
### Fulfilled promises and the `resolveWithFullResponse` option
|
||||
|
||||
``` js
|
||||
// Per default the body is passed to the fulfillment handler:
|
||||
rp('http://google.com')
|
||||
.then(function (body) {
|
||||
// Process the html of the Google web page...
|
||||
});
|
||||
|
||||
// The resolveWithFullResponse options allows to pass the full response:
|
||||
rp({ uri: 'http://google.com', resolveWithFullResponse: true })
|
||||
.then(function (response) {
|
||||
// Access response.statusCode, response.body etc.
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
### Rejected promises and the `simple` option
|
||||
|
||||
``` js
|
||||
// The rejection handler is called with a reason object...
|
||||
rp('http://google.com')
|
||||
.catch(function (reason) {
|
||||
// Handle failed request...
|
||||
});
|
||||
|
||||
// ... and would be equivalent to this Request-only implementation:
|
||||
var options = { uri: 'http://google.com' };
|
||||
|
||||
request(options, function (err, response, body) {
|
||||
var reason;
|
||||
if (err) {
|
||||
reason = {
|
||||
cause: err,
|
||||
error: err,
|
||||
options: options,
|
||||
response: response
|
||||
};
|
||||
} else if (!(/^2/.test('' + response.statusCode))) { // Status Codes other than 2xx
|
||||
reason = {
|
||||
statusCode: response.statusCode,
|
||||
error: body,
|
||||
options: options,
|
||||
response: response
|
||||
};
|
||||
}
|
||||
|
||||
if (reason) {
|
||||
// Handle failed request...
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// If you pass the simple option as false...
|
||||
rp({ uri: 'http://google.com', simple: false })
|
||||
.catch(function (reason) {
|
||||
// Handle failed request...
|
||||
});
|
||||
|
||||
// ... the equivalent Request-only code would be:
|
||||
request(options, function (err, response, body) {
|
||||
if (err) {
|
||||
var reason = {
|
||||
cause: err,
|
||||
error: err,
|
||||
options: options,
|
||||
response: response
|
||||
};
|
||||
// Handle failed request...
|
||||
}
|
||||
});
|
||||
// E.g. a 404 would now fulfill the promise.
|
||||
// Combine it with resolveWithFullResponse = true to check the status code in the fulfillment handler.
|
||||
```
|
||||
|
||||
With version 0.4 the reason objects became Error objects with identical properties to ensure backwards compatibility. These new Error types allow targeted catch blocks:
|
||||
|
||||
``` js
|
||||
var errors = require('request-promise/errors');
|
||||
|
||||
rp('http://google.com')
|
||||
.catch(errors.StatusCodeError, function (reason) {
|
||||
// The server responded with a status codes other than 2xx.
|
||||
// Check reason.statusCode
|
||||
})
|
||||
.catch(errors.RequestError, function (reason) {
|
||||
// The request failed due to technical reasons.
|
||||
// reason.cause is the Error object Request would pass into a callback.
|
||||
});
|
||||
```
|
||||
|
||||
### The `transform` function
|
||||
|
||||
You can pass a function to `options.transform` to generate a custom fulfillment value when the promise gets resolved.
|
||||
|
||||
``` js
|
||||
// Just for fun you could reverse the response body:
|
||||
var options = {
|
||||
uri: 'http://google.com',
|
||||
transform: function (body, response, resolveWithFullResponse) {
|
||||
return body.split('').reverse().join('');
|
||||
}
|
||||
};
|
||||
|
||||
rp(options)
|
||||
.then(function (reversedBody) {
|
||||
// ;D
|
||||
});
|
||||
|
||||
|
||||
// However, you could also do something useful:
|
||||
var $ = require('cheerio'); // Basically jQuery for node.js
|
||||
|
||||
function autoParse(body, response, resolveWithFullResponse) {
|
||||
// FIXME: The content type string could contain additional values like the charset.
|
||||
// Consider using the `content-type` library for a robust comparison.
|
||||
if (response.headers['content-type'] === 'application/json') {
|
||||
return JSON.parse(body);
|
||||
} else if (response.headers['content-type'] === 'text/html') {
|
||||
return $.load(body);
|
||||
} else {
|
||||
return body;
|
||||
}
|
||||
}
|
||||
|
||||
options.transform = autoParse;
|
||||
|
||||
rp(options)
|
||||
.then(function (autoParsedBody) {
|
||||
// :)
|
||||
});
|
||||
|
||||
|
||||
// You can go one step further and set the transform as the default:
|
||||
var rpap = rp.defaults({ transform: autoParse });
|
||||
|
||||
rpap('http://google.com')
|
||||
.then(function (autoParsedBody) {
|
||||
// :)
|
||||
});
|
||||
|
||||
rpap('http://echojs.com')
|
||||
.then(function (autoParsedBody) {
|
||||
// =)
|
||||
});
|
||||
```
|
||||
|
||||
The third `resolveWithFullResponse` parameter of the transform function is equivalent to the option passed with the request. This allows to distinguish whether just the transformed body or the whole response shall be returned by the transform function:
|
||||
|
||||
``` js
|
||||
function reverseBody(body, response, resolveWithFullResponse) {
|
||||
response.body = response.body.split('').reverse().join('');
|
||||
return resolveWithFullResponse ? response : response.body;
|
||||
}
|
||||
```
|
||||
|
||||
As of Request-Promise v3 the transform function is ALWAYS executed for non-2xx responses. When `options.simple` is set to `true` (default) then non-2xx responses are rejected with a `StatusCodeError`. In this case the error contains the transformed response:
|
||||
|
||||
``` js
|
||||
var options = {
|
||||
uri: 'http://the-server.com/will-return/404',
|
||||
simple: true,
|
||||
transform: function (body, response, resolveWithFullResponse) { /* ... */ }
|
||||
};
|
||||
|
||||
rp(options)
|
||||
.catch(errors.StatusCodeError, function (reason) {
|
||||
// reason.response is the transformed response
|
||||
});
|
||||
```
|
||||
|
||||
You may set `options.transform2xxOnly = true` to only execute the transform function for responses with a 2xx status code. For other status codes – independent of any other settings, e.g. `options.simple` – the transform function is not executed.
|
||||
|
||||
#### Error handling
|
||||
|
||||
If the transform operation fails (throws an error) the request will be rejected with a `TransformError`:
|
||||
|
||||
``` js
|
||||
var errors = require('request-promise/errors');
|
||||
|
||||
var options = {
|
||||
uri: 'http://google.com',
|
||||
transform: function (body, response, resolveWithFullResponse) {
|
||||
throw new Error('Transform failed!');
|
||||
}
|
||||
};
|
||||
|
||||
rp(options)
|
||||
.catch(errors.TransformError, function (reason) {
|
||||
console.log(reason.cause.message); // => Transform failed!
|
||||
// reason.response is the original response for which the transform operation failed
|
||||
});
|
||||
```
|
||||
|
||||
## Experimental Support for Continuation Local Storage
|
||||
|
||||
Continuation Local Storage is no longer supported. However, you [can get back the support](https://github.com/request/request-promise/wiki/Getting-Back-Support-for-Continuation-Local-Storage) by using `request-promise-any`.
|
||||
|
||||
## Debugging
|
||||
|
||||
The ways to debug the operation of Request-Promise are the same [as described](https://github.com/request/request#debugging) for Request. These are:
|
||||
|
||||
1. Launch the node process like `NODE_DEBUG=request node script.js` (`lib,request,otherlib` works too).
|
||||
2. Set `require('request-promise').debug = true` at any time (this does the same thing as #1).
|
||||
3. Use the [request-debug module](https://github.com/nylen/request-debug) to view request and response headers and bodies. Instrument Request-Promise with `require('request-debug')(rp);`.
|
||||
|
||||
## Mocking Request-Promise
|
||||
|
||||
Usually you want to mock the whole request function which is returned by `require('request-promise')`. This is not possible by using a mocking library like [sinon.js](http://sinonjs.org) alone. What you need is a library that ties into the module loader and makes sure that your mock is returned whenever the tested code is calling `require('request-promise')`. [Mockery](https://github.com/mfncooper/mockery) is one of such libraries.
|
||||
|
||||
@florianschmidt1994 kindly shared his solution:
|
||||
```javascript
|
||||
before(function (done) {
|
||||
|
||||
var filename = "fileForResponse";
|
||||
mockery.enable({
|
||||
warnOnReplace: false,
|
||||
warnOnUnregistered: false,
|
||||
useCleanCache: true
|
||||
});
|
||||
|
||||
mockery.registerMock('request-promise', function () {
|
||||
var response = fs.readFileSync(__dirname + '/data/' + filename, 'utf8');
|
||||
return Bluebird.resolve(response.trim());
|
||||
});
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
after(function (done) {
|
||||
mockery.disable();
|
||||
mockery.deregisterAll();
|
||||
done();
|
||||
});
|
||||
|
||||
describe('custom test case', function () {
|
||||
// Test some function/module/... which uses request-promise
|
||||
// and it will always receive the predefined "fileForResponse" as data, e.g.:
|
||||
var rp = require('request-promise');
|
||||
rp(...).then(function(data) {
|
||||
// ➞ data is what is in fileForResponse
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
Based on that you may now build a more sophisticated mock. [Sinon.js](http://sinonjs.org) may be of help as well.
|
||||
|
||||
## Contributing
|
||||
|
||||
To set up your development environment:
|
||||
|
||||
1. clone the repo to your desktop,
|
||||
2. in the shell `cd` to the main folder,
|
||||
3. hit `npm install`,
|
||||
4. hit `npm install gulp -g` if you haven't installed gulp globally yet, and
|
||||
5. run `gulp dev`. (Or run `node ./node_modules/.bin/gulp dev` if you don't want to install gulp globally.)
|
||||
|
||||
`gulp dev` watches all source files and if you save some changes it will lint the code and execute all tests. The test coverage report can be viewed from `./coverage/lcov-report/index.html`.
|
||||
|
||||
If you want to debug a test you should use `gulp test-without-coverage` to run all tests without obscuring the code by the test coverage instrumentation.
|
||||
|
||||
## Change History
|
||||
|
||||
- v4.2.5 (2019-11-03)
|
||||
- Security fix: bumped `request-promise-core` which bumps `lodash` to `^4.17.15`. See [vulnerabilty reports](https://snyk.io/vuln/search?q=lodash&type=npm).
|
||||
*(Thanks to @rishabh-chowdhary for reporting this in pull request [#326](https://github.com/request/request-promise/pull/326).)*
|
||||
- v4.2.4 (2019-02-14)
|
||||
- Corrected mistakenly set `tough-cookie` version, now `^2.3.3`
|
||||
*(Thanks to @evocateur for pointing this out.)*
|
||||
- If you installed `request-promise@4.2.3` please make sure after the upgrade that `request` and `request-promise` use the same physical copy of `tough-cookie`.
|
||||
- v4.2.3 (2019-02-14)
|
||||
- Using stricter `tough-cookie@~2.3.3` to avoid installing `tough-cookie@3` which introduces breaking changes
|
||||
*(Thanks to @aomdoa for pull request [#299](https://github.com/request/request-promise/pull/299))*
|
||||
- Security fix: bumped `lodash` to `^4.17.11`, see [vulnerabilty reports](https://snyk.io/vuln/search?q=lodash&type=npm)
|
||||
- v4.2.2 (2017-09-22)
|
||||
- Upgraded `tough-cookie` to a version without regex DoS vulnerability
|
||||
*(Thanks to @rouanw for [pull request #226](https://github.com/request/request-promise/pull/226))*
|
||||
- v4.2.1 (2017-05-07)
|
||||
- Fix that allows to use `tough-cookie` for cookie creation
|
||||
*(Thanks to @ScottyMJacobson for reporting [issue #183](https://github.com/request/request-promise/issues/183))*
|
||||
- Added [cookie handling example](https://github.com/request/request-promise#include-a-cookie) to the cheat sheet
|
||||
*(Thanks to @chovy and @ProfessorTom for [asking for it](https://github.com/request/request-promise/issues/79))*
|
||||
- v4.2.0 (2017-03-16)
|
||||
- Updated `bluebird` to v3.5
|
||||
*(Thanks to @acinader for [pull request #181](https://github.com/request/request-promise/pull/181))*
|
||||
- v4.1.1 (2016-08-08)
|
||||
- Renamed internally used package `@request/promise-core` to `request-promise-core` because there where [too](https://github.com/request/request-promise/issues/137) [many](https://github.com/request/request-promise/issues/141) issues with the scoped package name
|
||||
*(Thanks to @cabrinoob, @crazy4groovy, @dsandor, @KpjComp, @lorenwest, @Reisyukaku, @tehChromic, @todd for providing helpful information.)*
|
||||
- v4.1.0 (2016-07-30)
|
||||
- Added cancellation support
|
||||
*(Thanks to @not-an-aardvark for [pull request #123](https://github.com/request/request-promise/pull/123))*
|
||||
- v4.0.2 (2016-07-18)
|
||||
- Fix for using with module bundlers like Webpack and Browserify
|
||||
- v4.0.1 (2016-07-17)
|
||||
- Fixed `@request/promise-core` version for safer versioning
|
||||
- v4.0.0 (2016-07-15)
|
||||
- **Breaking Change**: `request` is declared as a peer dependency which has to be installed separately by the user now
|
||||
- **Breaking Change**: Dropped support for Continuation Local Storage since [`request-promise-any`](https://github.com/request/request-promise-any) can be [used](https://github.com/request/request-promise/wiki/Getting-Back-Support-for-Continuation-Local-Storage) for that now
|
||||
- Introduced the `transform2xxOnly` option to ease the breaking change regarding the new `transform` handling in v3.0.0
|
||||
*(Thanks to @stevage for pointing out the effect of the breaking change in [issue #131](https://github.com/request/request-promise/issues/131))*
|
||||
- Resolved issues [#65](https://github.com/request/request-promise/issues/65) and [#71](https://github.com/request/request-promise/issues/71) by publishing nearly identical libraries to support other Promise implementations: [`request-promise-native`](https://github.com/request/request-promise-native) and [`request-promise-any`](https://github.com/request/request-promise-any)
|
||||
*(Thanks to @benjamingr, @eilgin, @gillesdemey, @hildjj, @iggycoloma, @jonathanong, @knpwrs, @MarkHerhold, @massimocode, @mikeal, @niftylettuce, @raitucarp, @sherdeadlock, @tonylukasavage, and @vgoloviznin for the valuable discussions!)*
|
||||
- Relicensed this library with the ISC license
|
||||
- v3.0.0 (2016-04-16)
|
||||
- **Breaking Change**: Overhauled the handling of the `transform` function
|
||||
*(Thanks to @Limess for explaining the need in [issue #86](https://github.com/request/request-promise/issues/86))*
|
||||
- **Breaking Change**: Updated `bluebird` to v3
|
||||
*(Thanks to @BrandonSmith for [pull request #103](https://github.com/request/request-promise/pull/103))*
|
||||
- Improved `StatusCodeError.message`
|
||||
- Updated `lodash` to v4.6
|
||||
- Improved README in regard to `.catch(...)` best practice
|
||||
*(Thanks to @RebootJeff for [pull request #98](https://github.com/request/request-promise/pull/98))*
|
||||
- v2.0.1 (2016-02-17)
|
||||
- Updated `lodash` to v4
|
||||
*(Thanks to @ratson for [pull request #94](https://github.com/request/request-promise/pull/94))*
|
||||
- v2.0.0 (2016-01-12)
|
||||
- **Breaking Change**: Removed explicit `cls-bluebird` dependency which has to be installed by the user now
|
||||
*(Thanks to @hildjj for his [pull request #75](https://github.com/request/request-promise/pull/75))*
|
||||
- `npm shrinkwrap` now works for `npm@3` users who don't use `continuation-local-storage`
|
||||
*(Thanks to @toboid and @rstacruz for reporting the issue in [issue #70](https://github.com/request/request-promise/issues/70) and [issue #82](https://github.com/request/request-promise/issues/82))*
|
||||
- v1.0.2 (2015-10-22)
|
||||
- Removed `continuation-local-storage` from peer dependencies as it was unnecessary
|
||||
*(Thanks to @mrhyde for working on a better solution discussed in [issue #70](https://github.com/request/request-promise/issues/70))*
|
||||
- v1.0.1 (2015-10-14)
|
||||
- Fixed a npm warning by marking `continuation-local-storage` as a peer dependency
|
||||
- v1.0.0 (2015-10-11)
|
||||
- **Breaking Change**: Some errors that were previously thrown synchronously - e.g. for wrong input parameters - are now passed to the rejected promise instead
|
||||
*(Thanks to @josnidhin for suggesting that in [issue #43](https://github.com/request/request-promise/issues/43))*
|
||||
- **Breaking Change**: Request-Promise does not load its own Bluebird prototype anymore. If you use Bluebird in your project and altered the prototype then Request-Promise may use your altered Bluebird prototype internally.
|
||||
- For HEAD requests the headers instead of an empty body is returned (unless `resolveWithFullResponse = true` is used)
|
||||
*(Thanks to @zcei for proposing the change in [issue #58](https://github.com/request/request-promise/issues/58))*
|
||||
- Extended `transform` function by a third `resolveWithFullResponse` parameter
|
||||
- Added experimental support for continuation local storage
|
||||
*(Thanks to @silverbp preparing this in [issue #64](https://github.com/request/request-promise/issues/64))*
|
||||
- Added node.js 4 to the Travis CI build
|
||||
- Updated the README
|
||||
*(Thanks to many people for their feedback in issues [#55](https://github.com/request/request-promise/issues/55) and [#59](https://github.com/request/request-promise/issues/59))*
|
||||
- v0.4.3 (2015-07-27)
|
||||
- Reduced overhead by just requiring used lodash functions instead of the whole lodash library
|
||||
*(Thanks to @luanmuniz for [pull request #54](https://github.com/request/request-promise/pull/54))*
|
||||
- Updated dependencies
|
||||
- v0.4.2 (2015-04-12)
|
||||
- Updated dependencies
|
||||
- v0.4.1 (2015-03-20)
|
||||
- Improved Error types to work in browsers without v8 engine
|
||||
*(Thanks to @nodiis for [pull request #40](https://github.com/request/request-promise/pull/40))*
|
||||
- v0.4.0 (2015-02-08)
|
||||
- Introduced Error types used for the reject reasons (See last part [this section](#rejected-promises-and-the-simple-option))
|
||||
*(Thanks to @jakecraige for starting the discussion in [issue #38](https://github.com/request/request-promise/issues/38))*
|
||||
- **Minor Breaking Change:** The reject reason objects became actual Error objects. However, `typeof reason === 'object'` still holds true and the error objects have the same properties as the previous reason objects. If the reject handler only accesses the properties on the reason object - which is usually the case - no migration is required.
|
||||
- Added io.js and node.js 0.12 to the Travis CI build
|
||||
- v0.3.3 (2015-01-19)
|
||||
- Fixed handling possibly unhandled rejections to work with the latest version of Bluebird
|
||||
*(Thanks to @slang800 for reporting this in [issue #36](https://github.com/request/request-promise/issues/36))*
|
||||
- v0.3.2 (2014-11-17)
|
||||
- Exposed `.finally(...)` to allow using it as the first method in the promise chain
|
||||
*(Thanks to @hjpbarcelos for his [pull request #28](https://github.com/request/request-promise/pull/28))*
|
||||
- v0.3.1 (2014-11-11)
|
||||
- Added the `.promise()` method for advanced Bluebird API usage
|
||||
*(Thanks to @devo-tox for his feedback in [issue #27](https://github.com/request/request-promise/issues/27))*
|
||||
- v0.3.0 (2014-11-10)
|
||||
- Carefully rewritten from scratch to make Request-Promise a drop-in replacement for Request
|
||||
|
||||
## License (ISC)
|
||||
|
||||
In case you never heard about the [ISC license](http://en.wikipedia.org/wiki/ISC_license) it is functionally equivalent to the MIT license.
|
||||
|
||||
See the [LICENSE file](LICENSE) for details.
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = require('request-promise-core/errors');
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
'use strict';
|
||||
|
||||
var Bluebird = require('bluebird').getNewLibraryCopy(),
|
||||
configure = require('request-promise-core/configure/request2'),
|
||||
stealthyRequire = require('stealthy-require');
|
||||
|
||||
try {
|
||||
|
||||
// Load Request freshly - so that users can require an unaltered request instance!
|
||||
var request = stealthyRequire(require.cache, function () {
|
||||
return require('@cypress/request');
|
||||
},
|
||||
function () {
|
||||
require('tough-cookie');
|
||||
}, module);
|
||||
|
||||
} catch (err) {
|
||||
/* istanbul ignore next */
|
||||
var EOL = require('os').EOL;
|
||||
/* istanbul ignore next */
|
||||
console.error(EOL + '###' + EOL + '### The "request" library is not installed automatically anymore.' + EOL + '### But is a dependency of "request-promise".' + EOL + '### Please install it with:' + EOL + '### npm install request --save' + EOL + '###' + EOL);
|
||||
/* istanbul ignore next */
|
||||
throw err;
|
||||
}
|
||||
|
||||
Bluebird.config({cancellation: true});
|
||||
|
||||
configure({
|
||||
request: request,
|
||||
PromiseImpl: Bluebird,
|
||||
expose: [
|
||||
'then',
|
||||
'catch',
|
||||
'finally',
|
||||
'cancel',
|
||||
'promise'
|
||||
// Would you like to expose more Bluebird methods? Try e.g. `rp(...).promise().tap(...)` first. `.promise()` returns the full-fledged Bluebird promise.
|
||||
],
|
||||
constructorMixin: function (resolve, reject, onCancel) {
|
||||
var self = this;
|
||||
onCancel(function () {
|
||||
self.abort();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
request.bindCLS = function RP$bindCLS() {
|
||||
throw new Error('CLS support was dropped. To get it back read: https://github.com/request/request-promise/wiki/Getting-Back-Support-for-Continuation-Local-Storage');
|
||||
};
|
||||
|
||||
|
||||
module.exports = request;
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
Copyright (c) 2015, Salesforce.com, Inc.
|
||||
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 Salesforce.com 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.
|
||||
+596
@@ -0,0 +1,596 @@
|
||||
# tough-cookie
|
||||
|
||||
[RFC 6265](https://tools.ietf.org/html/rfc6265) Cookies and CookieJar for Node.js
|
||||
|
||||
[](https://nodei.co/npm/tough-cookie/)
|
||||
|
||||
[](https://travis-ci.org/salesforce/tough-cookie)
|
||||
|
||||
## Synopsis
|
||||
|
||||
```javascript
|
||||
var tough = require("tough-cookie");
|
||||
var Cookie = tough.Cookie;
|
||||
var cookie = Cookie.parse(header);
|
||||
cookie.value = "somethingdifferent";
|
||||
header = cookie.toString();
|
||||
var cookiejar = new tough.CookieJar();
|
||||
|
||||
// Asynchronous!
|
||||
var cookie = await cookiejar.setCookie(
|
||||
cookie,
|
||||
"https://currentdomain.example.com/path"
|
||||
);
|
||||
var cookies = await cookiejar.getCookies("https://example.com/otherpath");
|
||||
|
||||
// Or with callbacks!
|
||||
cookiejar.setCookie(
|
||||
cookie,
|
||||
"https://currentdomain.example.com/path",
|
||||
function (err, cookie) {
|
||||
/* ... */
|
||||
}
|
||||
);
|
||||
cookiejar.getCookies("http://example.com/otherpath", function (err, cookies) {
|
||||
/* ... */
|
||||
});
|
||||
```
|
||||
|
||||
Why the name? NPM modules `cookie`, `cookies` and `cookiejar` were already taken.
|
||||
|
||||
## Installation
|
||||
|
||||
It's _so_ easy! Install with `npm` or your preferred package manager.
|
||||
|
||||
```sh
|
||||
npm install tough-cookie
|
||||
```
|
||||
|
||||
## Node.js Version Support
|
||||
|
||||
We follow the [node.js release schedule](https://github.com/nodejs/Release#release-schedule) and support all versions that are in Active LTS or Maintenance. We will always do a major release when dropping support for older versions of node, and we will do so in consultation with our community.
|
||||
|
||||
## API
|
||||
|
||||
### tough
|
||||
|
||||
The top-level exports from `require('tough-cookie')` can all be used as pure functions and don't need to be bound.
|
||||
|
||||
#### `parseDate(string)`
|
||||
|
||||
Parse a cookie date string into a `Date`. Parses according to [RFC 6265 Section 5.1.1](https://datatracker.ietf.org/doc/html/rfc6265#section-5.1.1), not `Date.parse()`.
|
||||
|
||||
#### `formatDate(date)`
|
||||
|
||||
Format a `Date` into an [RFC 822](https://datatracker.ietf.org/doc/html/rfc822#section-5) string (the RFC 6265 recommended format).
|
||||
|
||||
#### `canonicalDomain(str)`
|
||||
|
||||
Transforms a domain name into a canonical domain name. The canonical domain name is a domain name that has been trimmed, lowercased, stripped of leading dot, and optionally punycode-encoded ([Section 5.1.2 of RFC 6265](https://datatracker.ietf.org/doc/html/rfc6265#section-5.1.2)). For the most part, this function is idempotent (calling the function with the output from a previous call returns the same output).
|
||||
|
||||
#### `domainMatch(str, domStr[, canonicalize=true])`
|
||||
|
||||
Answers "does this real domain match the domain in a cookie?". The `str` is the "current" domain name and the `domStr` is the "cookie" domain name. Matches according to [RFC 6265 Section 5.1.3](https://datatracker.ietf.org/doc/html/rfc6265#section-5.1.3), but it helps to think of it as a "suffix match".
|
||||
|
||||
The `canonicalize` parameter toggles whether the domain parameters get normalized with `canonicalDomain` or not.
|
||||
|
||||
#### `defaultPath(path)`
|
||||
|
||||
Given a current request/response path, gives the path appropriate for storing in a cookie. This is basically the "directory" of a "file" in the path, but is specified by [Section 5.1.4 of the RFC](https://datatracker.ietf.org/doc/html/rfc6265#section-5.1.4).
|
||||
|
||||
The `path` parameter MUST be _only_ the pathname part of a URI (excluding the hostname, query, fragment, and so on). This is the `.pathname` property of node's `uri.parse()` output.
|
||||
|
||||
#### `pathMatch(reqPath, cookiePath)`
|
||||
|
||||
Answers "does the request-path path-match a given cookie-path?" as per [RFC 6265 Section 5.1.4](https://datatracker.ietf.org/doc/html/rfc6265#section-5.1.4). Returns a boolean.
|
||||
|
||||
This is essentially a prefix-match where `cookiePath` is a prefix of `reqPath`.
|
||||
|
||||
#### `parse(cookieString[, options])`
|
||||
|
||||
Alias for [`Cookie.parse(cookieString[, options])`](#cookieparsecookiestring-options).
|
||||
|
||||
#### `fromJSON(string)`
|
||||
|
||||
Alias for [`Cookie.fromJSON(string)`](#cookiefromjsonstrorobj).
|
||||
|
||||
#### `getPublicSuffix(hostname)`
|
||||
|
||||
Returns the public suffix of this hostname. The public suffix is the shortest domain name upon which a cookie can be set. Returns `null` if the hostname cannot have cookies set for it.
|
||||
|
||||
For example: `www.example.com` and `www.subdomain.example.com` both have public suffix `example.com`.
|
||||
|
||||
For further information, see the [Public Suffix List](http://publicsuffix.org/). This module derives its list from that site. This call is a wrapper around [`psl`](https://www.npmjs.com/package/psl)'s [`get` method](https://www.npmjs.com/package/psl##pslgetdomain).
|
||||
|
||||
#### `cookieCompare(a, b)`
|
||||
|
||||
For use with `.sort()`, sorts a list of cookies into the recommended order given in step 2 of ([RFC 6265 Section 5.4](https://datatracker.ietf.org/doc/html/rfc6265#section-5.4)). The sort algorithm is, in order of precedence:
|
||||
|
||||
- Longest `.path`
|
||||
- oldest `.creation` (which has a 1-ms precision, same as `Date`)
|
||||
- lowest `.creationIndex` (to get beyond the 1-ms precision)
|
||||
|
||||
```javascript
|
||||
var cookies = [
|
||||
/* unsorted array of Cookie objects */
|
||||
];
|
||||
cookies = cookies.sort(cookieCompare);
|
||||
```
|
||||
|
||||
> **Note**: Since the JavaScript `Date` is limited to a 1-ms precision, cookies within the same millisecond are entirely possible. This is especially true when using the `now` option to `.setCookie()`. The `.creationIndex` property is a per-process global counter, assigned during construction with `new Cookie()`, which preserves the spirit of the RFC sorting: older cookies go first. This works great for `MemoryCookieStore` since `Set-Cookie` headers are parsed in order, but is not so great for distributed systems. Sophisticated `Store`s may wish to set this to some other _logical clock_ so that if cookies A and B are created in the same millisecond, but cookie A is created before cookie B, then `A.creationIndex < B.creationIndex`. If you want to alter the global counter, which you probably _shouldn't_ do, it's stored in `Cookie.cookiesCreated`.
|
||||
|
||||
#### `permuteDomain(domain)`
|
||||
|
||||
Generates a list of all possible domains that `domainMatch()` the parameter. Can be handy for implementing cookie stores.
|
||||
|
||||
#### `permutePath(path)`
|
||||
|
||||
Generates a list of all possible paths that `pathMatch()` the parameter. Can be handy for implementing cookie stores.
|
||||
|
||||
### Cookie
|
||||
|
||||
Exported via `tough.Cookie`.
|
||||
|
||||
#### `Cookie.parse(cookieString[, options])`
|
||||
|
||||
Parses a single Cookie or Set-Cookie HTTP header into a `Cookie` object. Returns `undefined` if the string can't be parsed.
|
||||
|
||||
The options parameter is not required and currently has only one property:
|
||||
|
||||
- _loose_ - boolean - if `true` enable parsing of keyless cookies like `=abc` and `=`, which are not RFC-compliant.
|
||||
|
||||
If options is not an object it is ignored, which means it can be used with [`Array#map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map).
|
||||
|
||||
To process the Set-Cookie header(s) on a node HTTP/HTTPS response:
|
||||
|
||||
```javascript
|
||||
if (Array.isArray(res.headers["set-cookie"]))
|
||||
cookies = res.headers["set-cookie"].map(Cookie.parse);
|
||||
else cookies = [Cookie.parse(res.headers["set-cookie"])];
|
||||
```
|
||||
|
||||
_Note:_ In version 2.3.3, tough-cookie limited the number of spaces before the `=` to 256 characters. This limitation was removed in version 2.3.4.
|
||||
For more details, see [issue #92](https://github.com/salesforce/tough-cookie/issues/92).
|
||||
|
||||
#### Properties
|
||||
|
||||
Cookie object properties:
|
||||
|
||||
- _key_ - string - the name or key of the cookie (default `""`)
|
||||
- _value_ - string - the value of the cookie (default `""`)
|
||||
- _expires_ - `Date` - if set, the `Expires=` attribute of the cookie (defaults to the string `"Infinity"`). See `setExpires()`
|
||||
- _maxAge_ - seconds - if set, the `Max-Age=` attribute _in seconds_ of the cookie. Can also be set to strings `"Infinity"` and `"-Infinity"` for non-expiry and immediate-expiry, respectively. See `setMaxAge()`
|
||||
- _domain_ - string - the `Domain=` attribute of the cookie
|
||||
- _path_ - string - the `Path=` of the cookie
|
||||
- _secure_ - boolean - the `Secure` cookie flag
|
||||
- _httpOnly_ - boolean - the `HttpOnly` cookie flag
|
||||
- _sameSite_ - string - the `SameSite` cookie attribute (from [RFC 6265bis](#rfc-6265bis)); must be one of `none`, `lax`, or `strict`
|
||||
- _extensions_ - `Array` - any unrecognized cookie attributes as strings (even if equal-signs inside)
|
||||
- _creation_ - `Date` - when this cookie was constructed
|
||||
- _creationIndex_ - number - set at construction, used to provide greater sort precision (see `cookieCompare(a,b)` for a full explanation)
|
||||
|
||||
After a cookie has been passed through `CookieJar.setCookie()` it has the following additional attributes:
|
||||
|
||||
- _hostOnly_ - boolean - is this a host-only cookie (that is, no Domain field was set, but was instead implied).
|
||||
- _pathIsDefault_ - boolean - if true, there was no Path field on the cookie and `defaultPath()` was used to derive one.
|
||||
- _creation_ - `Date` - **modified** from construction to when the cookie was added to the jar.
|
||||
- _lastAccessed_ - `Date` - last time the cookie got accessed. Affects cookie cleaning after it is implemented. Using `cookiejar.getCookies(...)` updates this attribute.
|
||||
|
||||
#### `new Cookie([properties])`
|
||||
|
||||
Receives an options object that can contain any of the above Cookie properties. Uses the default for unspecified properties.
|
||||
|
||||
#### `.toString()`
|
||||
|
||||
Encodes to a Set-Cookie header value. The Expires cookie field is set using `formatDate()`, but is omitted entirely if `.expires` is `Infinity`.
|
||||
|
||||
#### `.cookieString()`
|
||||
|
||||
Encodes to a Cookie header value (specifically, the `.key` and `.value` properties joined with `"="`).
|
||||
|
||||
#### `.setExpires(string)`
|
||||
|
||||
Sets the expiry based on a date-string passed through `parseDate()`. If parseDate returns `null` (that is, can't parse this date string), `.expires` is set to `"Infinity"` (a string).
|
||||
|
||||
#### `.setMaxAge(number)`
|
||||
|
||||
Sets the maxAge in seconds. Coerces `-Infinity` to `"-Infinity"` and `Infinity` to `"Infinity"` so it correctly serializes to JSON.
|
||||
|
||||
#### `.expiryDate([now=Date.now()])`
|
||||
|
||||
`expiryTime()` computes the absolute unix-epoch milliseconds that this cookie expires. `expiryDate()` works similarly, except it returns a `Date` object. Note that in both cases the `now` parameter should be milliseconds.
|
||||
|
||||
Max-Age takes precedence over Expires (as per the RFC). The `.creation` attribute -- or, by default, the `now` parameter -- is used to offset the `.maxAge` attribute.
|
||||
|
||||
If Expires (`.expires`) is set, that's returned.
|
||||
|
||||
Otherwise, `expiryTime()` returns `Infinity` and `expiryDate()` returns a `Date` object for "Tue, 19 Jan 2038 03:14:07 GMT" (latest date that can be expressed by a 32-bit `time_t`; the common limit for most user-agents).
|
||||
|
||||
#### `.TTL([now=Date.now()])`
|
||||
|
||||
Computes the TTL relative to `now` (milliseconds). The same precedence rules as for `expiryTime`/`expiryDate` apply.
|
||||
|
||||
`Infinity` is returned for cookies without an explicit expiry and `0` is returned if the cookie is expired. Otherwise a time-to-live in milliseconds is returned.
|
||||
|
||||
#### `.canonicalizedDomain()`
|
||||
|
||||
#### `.cdomain()`
|
||||
|
||||
Returns the canonicalized `.domain` field. This is lower-cased and punycode ([RFC 3490](https://datatracker.ietf.org/doc/html/rfc3490)) encoded if the domain has any non-ASCII characters.
|
||||
|
||||
#### `.toJSON()`
|
||||
|
||||
For convenience in using `JSON.serialize(cookie)`. Returns a plain-old `Object` that can be JSON-serialized.
|
||||
|
||||
Any `Date` properties (such as `.expires`, `.creation`, and `.lastAccessed`) are exported in ISO format (`.toISOString()`).
|
||||
|
||||
> **NOTE**: Custom `Cookie` properties are discarded. In tough-cookie 1.x, since there was no `.toJSON` method explicitly defined, all enumerable properties were captured. If you want a property to be serialized, add the property name to the `Cookie.serializableProperties` Array.
|
||||
|
||||
#### `Cookie.fromJSON(strOrObj)`
|
||||
|
||||
Does the reverse of `cookie.toJSON()`. If passed a string, will `JSON.parse()` that first.
|
||||
|
||||
Any `Date` properties (such as `.expires`, `.creation`, and `.lastAccessed`) are parsed via [`Date.parse`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse), not tough-cookie's `parseDate`, since ISO timestamps are being handled at this layer.
|
||||
|
||||
Returns `null` upon a JSON parsing error.
|
||||
|
||||
#### `.clone()`
|
||||
|
||||
Does a deep clone of this cookie, implemented exactly as `Cookie.fromJSON(cookie.toJSON())`.
|
||||
|
||||
#### `.validate()`
|
||||
|
||||
Status: _IN PROGRESS_. Works for a few things, but is by no means comprehensive.
|
||||
|
||||
Validates cookie attributes for semantic correctness. Useful for "lint" checking any Set-Cookie headers you generate. For now, it returns a boolean, but eventually could return a reason string. Future-proof with this construct:
|
||||
|
||||
```javascript
|
||||
if (cookie.validate() === true) {
|
||||
// it's tasty
|
||||
} else {
|
||||
// yuck!
|
||||
}
|
||||
```
|
||||
|
||||
### CookieJar
|
||||
|
||||
Exported via `tough.CookieJar`.
|
||||
|
||||
#### `CookieJar([store][, options])`
|
||||
|
||||
Simply use `new CookieJar()`. If a custom store is not passed to the constructor, a [`MemoryCookieStore`](#memorycookiestore) is created and used.
|
||||
|
||||
The `options` object can be omitted and can have the following properties:
|
||||
|
||||
- _rejectPublicSuffixes_ - boolean - default `true` - reject cookies with domains like "com" and "co.uk"
|
||||
- _looseMode_ - boolean - default `false` - accept malformed cookies like `bar` and `=bar`, which have an implied empty name.
|
||||
- _prefixSecurity_ - string - default `silent` - set to `'unsafe-disabled'`, `'silent'`, or `'strict'`. See [Cookie Prefixes](#cookie-prefixes) below.
|
||||
- _allowSpecialUseDomain_ - boolean - default `true` - accepts special-use domain suffixes, such as `local`. Useful for testing purposes.
|
||||
This is not in the standard, but is used sometimes on the web and is accepted by most browsers.
|
||||
|
||||
#### `.setCookie(cookieOrString, currentUrl[, options][, callback(err, cookie)])`
|
||||
|
||||
Attempt to set the cookie in the cookie jar. The cookie has updated `.creation`, `.lastAccessed` and `.hostOnly` properties. And returns a promise if a callback is not provided.
|
||||
|
||||
The `options` object can be omitted and can have the following properties:
|
||||
|
||||
- _http_ - boolean - default `true` - indicates if this is an HTTP or non-HTTP API. Affects `HttpOnly` cookies.
|
||||
- _secure_ - boolean - autodetect from URL - indicates if this is a "Secure" API. If the currentUrl starts with `https:` or `wss:` this defaults to `true`, otherwise `false`.
|
||||
- _now_ - Date - default `new Date()` - what to use for the creation or access time of cookies.
|
||||
- _ignoreError_ - boolean - default `false` - silently ignore things like parse errors and invalid domains. `Store` errors aren't ignored by this option.
|
||||
- _sameSiteContext_ - string - default unset - set to `'none'`, `'lax'`, or `'strict'` See [SameSite Cookies](#samesite-cookies) below.
|
||||
|
||||
As per the RFC, the `.hostOnly` property is set if there was no "Domain=" parameter in the cookie string (or `.domain` was null on the Cookie object). The `.domain` property is set to the fully-qualified hostname of `currentUrl` in this case. Matching this cookie requires an exact hostname match (not a `domainMatch` as per usual).
|
||||
|
||||
#### `.setCookieSync(cookieOrString, currentUrl[, options])`
|
||||
|
||||
Synchronous version of [`setCookie`](#setcookiecookieorstring-currenturl-options-callbackerr-cookie); only works with synchronous stores (that is, the default `MemoryCookieStore`).
|
||||
|
||||
#### `.getCookies(currentUrl[, options][, callback(err, cookies)])`
|
||||
|
||||
Retrieve the list of cookies that can be sent in a Cookie header for the current URL. Returns a promise if a callback is not provided.
|
||||
|
||||
Returns an array of `Cookie` objects, sorted by default using [`cookieCompare`](#cookiecomparea-b).
|
||||
|
||||
If an error is encountered it's passed as `err` to the callback, otherwise an array of `Cookie` objects is passed. The array is sorted with `cookieCompare()` unless the `{sort:false}` option is given.
|
||||
|
||||
The `options` object can be omitted and can have the following properties:
|
||||
|
||||
- _http_ - boolean - default `true` - indicates if this is an HTTP or non-HTTP API. Affects `HttpOnly` cookies.
|
||||
- _secure_ - boolean - autodetect from URL - indicates if this is a "Secure" API. If the currentUrl starts with `https:` or `wss:` then this is defaulted to `true`, otherwise `false`.
|
||||
- _now_ - Date - default `new Date()` - what to use for the creation or access time of cookies
|
||||
- _expire_ - boolean - default `true` - perform expiry-time checking of cookies and asynchronously remove expired cookies from the store. Using `false` returns expired cookies and does **not** remove them from the store (which is potentially useful for replaying Set-Cookie headers).
|
||||
- _allPaths_ - boolean - default `false` - if `true`, do not scope cookies by path. The default uses RFC-compliant path scoping. **Note**: may not be supported by the underlying store (the default `MemoryCookieStore` supports it).
|
||||
- _sameSiteContext_ - string - default unset - Set this to `'none'`, `'lax'`, or `'strict'` to enforce SameSite cookies upon retrieval. See [SameSite Cookies](#samesite-cookies) below.
|
||||
- _sort_ - boolean - whether to sort the list of cookies.
|
||||
|
||||
The `.lastAccessed` property of the returned cookies will have been updated.
|
||||
|
||||
#### `.getCookiesSync(currentUrl, [{options}])`
|
||||
|
||||
Synchronous version of [`getCookies`](#getcookiescurrenturl-options-callbackerr-cookies); only works with synchronous stores (for example, the default `MemoryCookieStore`).
|
||||
|
||||
#### `.getCookieString(...)`
|
||||
|
||||
Accepts the same options as [`.getCookies()`](#getcookiescurrenturl-options-callbackerr-cookies) but returns a string suitable for a Cookie header rather than an Array.
|
||||
|
||||
#### `.getCookieStringSync(...)`
|
||||
|
||||
Synchronous version of [`getCookieString`](#getcookiestring); only works with synchronous stores (for example, the default `MemoryCookieStore`).
|
||||
|
||||
#### `.getSetCookieStrings(...)`
|
||||
|
||||
Returns an array of strings suitable for **Set-Cookie** headers. Accepts the same options as [`.getCookies()`](#getcookiescurrenturl-options-callbackerr-cookies). Simply maps the cookie array via `.toString()`.
|
||||
|
||||
#### `.getSetCookieStringsSync(...)`
|
||||
|
||||
Synchronous version of [`getSetCookieStrings`](#getsetcookiestrings); only works with synchronous stores (for example, the default `MemoryCookieStore`).
|
||||
|
||||
#### `.serialize([callback(err, serializedObject)])`
|
||||
|
||||
Returns a promise if a callback is not provided.
|
||||
|
||||
Serialize the Jar if the underlying store supports `.getAllCookies`.
|
||||
|
||||
> **NOTE**: Custom `Cookie` properties are discarded. If you want a property to be serialized, add the property name to the `Cookie.serializableProperties` Array.
|
||||
|
||||
See [Serialization Format](#serialization-format).
|
||||
|
||||
#### `.serializeSync()`
|
||||
|
||||
Synchronous version of [`serialize`](#serializecallbackerr-serializedobject); only works with synchronous stores (for example, the default `MemoryCookieStore`).
|
||||
|
||||
#### `.toJSON()`
|
||||
|
||||
Alias of [`.serializeSync()`](#serializesync) for the convenience of `JSON.stringify(cookiejar)`.
|
||||
|
||||
#### `CookieJar.deserialize(serialized[, store][, callback(err, object)])`
|
||||
|
||||
A new Jar is created and the serialized Cookies are added to the underlying store. Each `Cookie` is added via `store.putCookie` in the order in which they appear in the serialization. A promise is returned if a callback is not provided.
|
||||
|
||||
The `store` argument is optional, but should be an instance of `Store`. By default, a new instance of `MemoryCookieStore` is created.
|
||||
|
||||
As a convenience, if `serialized` is a string, it is passed through `JSON.parse` first.
|
||||
|
||||
#### `CookieJar.deserializeSync(serialized[, store])`
|
||||
|
||||
Sync version of [`.deserialize`](#cookiejardeserializeserialized-store-callbackerr-object); only works with synchronous stores (for example, the default `MemoryCookieStore`).
|
||||
|
||||
#### `CookieJar.fromJSON(string)`
|
||||
|
||||
Alias of [`.deserializeSync`](#cookiejardeserializesyncserialized-store) to provide consistency with [`Cookie.fromJSON()`](#cookiefromjsonstrorobj).
|
||||
|
||||
#### `.clone([store][, callback(err, cloned))`
|
||||
|
||||
Produces a deep clone of this jar. Modifications to the original do not affect the clone, and vice versa. Returns a promise if a callback is not provided.
|
||||
|
||||
The `store` argument is optional, but should be an instance of `Store`. By default, a new instance of `MemoryCookieStore` is created. Transferring between store types is supported so long as the source implements `.getAllCookies()` and the destination implements `.putCookie()`.
|
||||
|
||||
#### `.cloneSync([store])`
|
||||
|
||||
Synchronous version of [`.clone`](#clonestore-callbackerr-cloned), returning a new `CookieJar` instance.
|
||||
|
||||
The `store` argument is optional, but must be a _synchronous_ `Store` instance if specified. If not passed, a new instance of `MemoryCookieStore` is used.
|
||||
|
||||
The _source_ and _destination_ must both be synchronous `Store`s. If one or both stores are asynchronous, use `.clone` instead. Recall that `MemoryCookieStore` supports both synchronous and asynchronous API calls.
|
||||
|
||||
#### `.removeAllCookies([callback(err)])`
|
||||
|
||||
Removes all cookies from the jar. Returns a promise if a callback is not provided.
|
||||
|
||||
This is a new backwards-compatible feature of `tough-cookie` version 2.5, so not all Stores will implement it efficiently. For Stores that do not implement `removeAllCookies`, the fallback is to call `removeCookie` after `getAllCookies`. If `getAllCookies` fails or isn't implemented in the Store, that error is returned. If one or more of the `removeCookie` calls fail, only the first error is returned.
|
||||
|
||||
#### `.removeAllCookiesSync()`
|
||||
|
||||
Sync version of [`.removeAllCookies()`](#removeallcookiescallbackerr); only works with synchronous stores (for example, the default `MemoryCookieStore`).
|
||||
|
||||
### Store
|
||||
|
||||
Base class for CookieJar stores. Available as `tough.Store`.
|
||||
|
||||
### Store API
|
||||
|
||||
The storage model for each `CookieJar` instance can be replaced with a custom implementation. The default is `MemoryCookieStore` which can be found in [`lib/memstore.js`](https://github.com/salesforce/tough-cookie/blob/master/lib/memstore.js). The API uses continuation-passing-style to allow for asynchronous stores.
|
||||
|
||||
Stores should inherit from the base `Store` class, which is available as a top-level export.
|
||||
|
||||
Stores are asynchronous by default, but if `store.synchronous` is set to `true`, then the `*Sync` methods of the containing `CookieJar` can be used.
|
||||
|
||||
All `domain` parameters are normalized before calling.
|
||||
|
||||
The Cookie store must have all of the following methods. Note that asynchronous implementations **must** support callback parameters.
|
||||
|
||||
#### `store.findCookie(domain, path, key, callback(err, cookie))`
|
||||
|
||||
Retrieve a cookie with the given domain, path, and key (name). The RFC maintains that exactly one of these cookies should exist in a store. If the store is using versioning, this means that the latest or newest such cookie should be returned.
|
||||
|
||||
Callback takes an error and the resulting `Cookie` object. If no cookie is found then `null` MUST be passed instead (that is, not an error).
|
||||
|
||||
#### `store.findCookies(domain, path, allowSpecialUseDomain, callback(err, cookies))`
|
||||
|
||||
Locates cookies matching the given domain and path. This is most often called in the context of [`cookiejar.getCookies()`](#getcookiescurrenturl-options-callbackerr-cookies).
|
||||
|
||||
If no cookies are found, the callback MUST be passed an empty array.
|
||||
|
||||
The resulting list is checked for applicability to the current request according to the RFC (domain-match, path-match, http-only-flag, secure-flag, expiry, and so on), so it's OK to use an optimistic search algorithm when implementing this method. However, the search algorithm used SHOULD try to find cookies that `domainMatch()` the domain and `pathMatch()` the path in order to limit the amount of checking that needs to be done.
|
||||
|
||||
As of version 0.9.12, the `allPaths` option to `cookiejar.getCookies()` above causes the path here to be `null`. If the path is `null`, path-matching MUST NOT be performed (that is, domain-matching only).
|
||||
|
||||
#### `store.putCookie(cookie, callback(err))`
|
||||
|
||||
Adds a new cookie to the store. The implementation SHOULD replace any existing cookie with the same `.domain`, `.path`, and `.key` properties. Depending on the nature of the implementation, it's possible that between the call to `fetchCookie` and `putCookie` that a duplicate `putCookie` can occur.
|
||||
|
||||
The `cookie` object MUST NOT be modified; as the caller has already updated the `.creation` and `.lastAccessed` properties.
|
||||
|
||||
Pass an error if the cookie cannot be stored.
|
||||
|
||||
#### `store.updateCookie(oldCookie, newCookie, callback(err))`
|
||||
|
||||
Update an existing cookie. The implementation MUST update the `.value` for a cookie with the same `domain`, `.path`, and `.key`. The implementation SHOULD check that the old value in the store is equivalent to `oldCookie` - how the conflict is resolved is up to the store.
|
||||
|
||||
The `.lastAccessed` property is always different between the two objects (to the precision possible via JavaScript's clock). Both `.creation` and `.creationIndex` are guaranteed to be the same. Stores MAY ignore or defer the `.lastAccessed` change at the cost of affecting how cookies are selected for automatic deletion (for example, least-recently-used, which is up to the store to implement).
|
||||
|
||||
Stores may wish to optimize changing the `.value` of the cookie in the store versus storing a new cookie. If the implementation doesn't define this method, a stub that calls [`putCookie`](#storeputcookiecookie-callbackerr) is added to the store object.
|
||||
|
||||
The `newCookie` and `oldCookie` objects MUST NOT be modified.
|
||||
|
||||
Pass an error if the newCookie cannot be stored.
|
||||
|
||||
#### `store.removeCookie(domain, path, key, callback(err))`
|
||||
|
||||
Remove a cookie from the store (see notes on [`findCookie`](#storefindcookiedomain-path-key-callbackerr-cookie) about the uniqueness constraint).
|
||||
|
||||
The implementation MUST NOT pass an error if the cookie doesn't exist, and only pass an error due to the failure to remove an existing cookie.
|
||||
|
||||
#### `store.removeCookies(domain, path, callback(err))`
|
||||
|
||||
Removes matching cookies from the store. The `path` parameter is optional and if missing, means all paths in a domain should be removed.
|
||||
|
||||
Pass an error ONLY if removing any existing cookies failed.
|
||||
|
||||
#### `store.removeAllCookies(callback(err))`
|
||||
|
||||
_Optional_. Removes all cookies from the store.
|
||||
|
||||
Pass an error if one or more cookies can't be removed.
|
||||
|
||||
#### `store.getAllCookies(callback(err, cookies))`
|
||||
|
||||
_Optional_. Produces an `Array` of all cookies during [`jar.serialize()`](#serializecallbackerr-serializedobject). The items in the array can be true `Cookie` objects or generic `Object`s with the [Serialization Format](#serialization-format) data structure.
|
||||
|
||||
Cookies SHOULD be returned in creation order to preserve sorting via [`compareCookie()`](#cookiecomparea-b). For reference, `MemoryCookieStore` sorts by `.creationIndex` since it uses true `Cookie` objects internally. If you don't return the cookies in creation order, they'll still be sorted by creation time, but this only has a precision of 1-ms. See `cookieCompare` for more detail.
|
||||
|
||||
Pass an error if retrieval fails.
|
||||
|
||||
**Note**: Not all Stores can implement this due to technical limitations, so it is optional.
|
||||
|
||||
### MemoryCookieStore
|
||||
|
||||
Inherits from `Store`.
|
||||
|
||||
A just-in-memory CookieJar synchronous store implementation, used by default. Despite being a synchronous implementation, it's usable with both the synchronous and asynchronous forms of the `CookieJar` API. Supports serialization, `getAllCookies`, and `removeAllCookies`.
|
||||
|
||||
### Community Cookie Stores
|
||||
|
||||
These are some Store implementations authored and maintained by the community. They aren't official and we don't vouch for them but you may be interested to have a look:
|
||||
|
||||
- [`db-cookie-store`](https://github.com/JSBizon/db-cookie-store): SQL including SQLite-based databases
|
||||
- [`file-cookie-store`](https://github.com/JSBizon/file-cookie-store): Netscape cookie file format on disk
|
||||
- [`redis-cookie-store`](https://github.com/benkroeger/redis-cookie-store): Redis
|
||||
- [`tough-cookie-filestore`](https://github.com/mitsuru/tough-cookie-filestore): JSON on disk
|
||||
- [`tough-cookie-web-storage-store`](https://github.com/exponentjs/tough-cookie-web-storage-store): DOM localStorage and sessionStorage
|
||||
|
||||
## Serialization Format
|
||||
|
||||
**NOTE**: If you want to have custom `Cookie` properties serialized, add the property name to `Cookie.serializableProperties`.
|
||||
|
||||
```js
|
||||
{
|
||||
// The version of tough-cookie that serialized this jar.
|
||||
version: 'tough-cookie@1.x.y',
|
||||
|
||||
// add the store type, to make humans happy:
|
||||
storeType: 'MemoryCookieStore',
|
||||
|
||||
// CookieJar configuration:
|
||||
rejectPublicSuffixes: true,
|
||||
// ... future items go here
|
||||
|
||||
// Gets filled from jar.store.getAllCookies():
|
||||
cookies: [
|
||||
{
|
||||
key: 'string',
|
||||
value: 'string',
|
||||
// ...
|
||||
/* other Cookie.serializableProperties go here */
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## RFC 6265bis
|
||||
|
||||
Support for RFC 6265bis revision 02 is being developed. Since this is a bit of an omnibus revision to the RFC 6252, support is broken up into the functional areas.
|
||||
|
||||
### Leave Secure Cookies Alone
|
||||
|
||||
Not yet supported.
|
||||
|
||||
This change makes it so that if a cookie is sent from the server to the client with a `Secure` attribute, the channel must also be secure or the cookie is ignored.
|
||||
|
||||
### SameSite Cookies
|
||||
|
||||
Supported.
|
||||
|
||||
This change makes it possible for servers, and supporting clients, to mitigate certain types of CSRF attacks by disallowing `SameSite` cookies from being sent cross-origin.
|
||||
|
||||
On the Cookie object itself, you can get or set the `.sameSite` attribute, which is serialized into the `SameSite=` cookie attribute. When unset or `undefined`, no `SameSite=` attribute is serialized. The valid values of this attribute are `'none'`, `'lax'`, or `'strict'`. Other values are serialized as-is.
|
||||
|
||||
When parsing cookies with a `SameSite` cookie attribute, values other than `'lax'` or `'strict'` are parsed as `'none'`. For example, `SomeCookie=SomeValue; SameSite=garbage` parses so that `cookie.sameSite === 'none'`.
|
||||
|
||||
In order to support SameSite cookies, you must provide a `sameSiteContext` option to _both_ `setCookie` and `getCookies`. Valid values for this option are just like for the Cookie object, but have particular meanings:
|
||||
|
||||
1. `'strict'` mode - If the request is on the same "site for cookies" (see the RFC draft for more information), pass this option to add a layer of defense against CSRF.
|
||||
2. `'lax'` mode - If the request is from another site, _but_ is directly because of navigation by the user, such as, `<link type=prefetch>` or `<a href="...">`, pass `sameSiteContext: 'lax'`.
|
||||
3. `'none'` - Otherwise, pass `sameSiteContext: 'none'` (this indicates a cross-origin request).
|
||||
4. unset/`undefined` - SameSite **is not** be enforced! This can be a valid use-case for when CSRF isn't in the threat model of the system being built.
|
||||
|
||||
It is highly recommended that you read RFC 6265bis for fine details on SameSite cookies. In particular [Section 8.8](https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-02##section-8.8) discusses security considerations and defense in depth.
|
||||
|
||||
### Cookie Prefixes
|
||||
|
||||
Supported.
|
||||
|
||||
Cookie prefixes are a way to indicate that a given cookie was set with a set of attributes simply by inspecting the first few characters of the cookie's name.
|
||||
|
||||
Cookie prefixes are defined in [Section 4.1.3 of 6265bis](https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-03##section-4.1.3).
|
||||
|
||||
Two prefixes are defined:
|
||||
|
||||
1. `"__Secure-" Prefix`: If a cookie's name begins with a case-sensitive match for the string "\_\_Secure-", then the cookie was set with a "Secure" attribute.
|
||||
2. `"__Host-" Prefix`: If a cookie's name begins with a case-sensitive match for the string "\_\_Host-", then the cookie was set with a "Secure" attribute, a "Path" attribute with a value of "/", and no "Domain" attribute.
|
||||
|
||||
If `prefixSecurity` is enabled for `CookieJar`, then cookies that match the prefixes defined above but do not obey the attribute restrictions are not added.
|
||||
|
||||
You can define this functionality by passing in the `prefixSecurity` option to `CookieJar`. It can be one of 3 values:
|
||||
|
||||
1. `silent`: Enable cookie prefix checking but silently fail to add the cookie if conditions are not met. Default.
|
||||
2. `strict`: Enable cookie prefix checking and error out if conditions are not met.
|
||||
3. `unsafe-disabled`: Disable cookie prefix checking.
|
||||
|
||||
Note that if `ignoreError` is passed in as `true` then the error is silent regardless of the `prefixSecurity` option (assuming it's enabled).
|
||||
|
||||
## Copyright and License
|
||||
|
||||
BSD-3-Clause:
|
||||
|
||||
```text
|
||||
Copyright (c) 2015, Salesforce.com, Inc.
|
||||
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 Salesforce.com 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.
|
||||
```
|
||||
+1758
File diff suppressed because it is too large.
Load diff
+242
@@ -0,0 +1,242 @@
|
||||
/*!
|
||||
* Copyright (c) 2015, Salesforce.com, Inc.
|
||||
* 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 Salesforce.com 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.
|
||||
*/
|
||||
"use strict";
|
||||
const { fromCallback } = require("universalify");
|
||||
const Store = require("./store").Store;
|
||||
const permuteDomain = require("./permuteDomain").permuteDomain;
|
||||
const pathMatch = require("./pathMatch").pathMatch;
|
||||
const { getCustomInspectSymbol, getUtilInspect } = require("./utilHelper");
|
||||
|
||||
class MemoryCookieStore extends Store {
|
||||
constructor() {
|
||||
super();
|
||||
this.synchronous = true;
|
||||
this.idx = Object.create(null);
|
||||
const customInspectSymbol = getCustomInspectSymbol();
|
||||
if (customInspectSymbol) {
|
||||
this[customInspectSymbol] = this.inspect;
|
||||
}
|
||||
}
|
||||
|
||||
inspect() {
|
||||
const util = { inspect: getUtilInspect(inspectFallback) };
|
||||
return `{ idx: ${util.inspect(this.idx, false, 2)} }`;
|
||||
}
|
||||
|
||||
findCookie(domain, path, key, cb) {
|
||||
if (!this.idx[domain]) {
|
||||
return cb(null, undefined);
|
||||
}
|
||||
if (!this.idx[domain][path]) {
|
||||
return cb(null, undefined);
|
||||
}
|
||||
return cb(null, this.idx[domain][path][key] || null);
|
||||
}
|
||||
findCookies(domain, path, allowSpecialUseDomain, cb) {
|
||||
const results = [];
|
||||
if (typeof allowSpecialUseDomain === "function") {
|
||||
cb = allowSpecialUseDomain;
|
||||
allowSpecialUseDomain = true;
|
||||
}
|
||||
if (!domain) {
|
||||
return cb(null, []);
|
||||
}
|
||||
|
||||
let pathMatcher;
|
||||
if (!path) {
|
||||
// null means "all paths"
|
||||
pathMatcher = function matchAll(domainIndex) {
|
||||
for (const curPath in domainIndex) {
|
||||
const pathIndex = domainIndex[curPath];
|
||||
for (const key in pathIndex) {
|
||||
results.push(pathIndex[key]);
|
||||
}
|
||||
}
|
||||
};
|
||||
} else {
|
||||
pathMatcher = function matchRFC(domainIndex) {
|
||||
//NOTE: we should use path-match algorithm from S5.1.4 here
|
||||
//(see : https://github.com/ChromiumWebApps/chromium/blob/b3d3b4da8bb94c1b2e061600df106d590fda3620/net/cookies/canonical_cookie.cc#L299)
|
||||
Object.keys(domainIndex).forEach(cookiePath => {
|
||||
if (pathMatch(path, cookiePath)) {
|
||||
const pathIndex = domainIndex[cookiePath];
|
||||
for (const key in pathIndex) {
|
||||
results.push(pathIndex[key]);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
const domains = permuteDomain(domain, allowSpecialUseDomain) || [domain];
|
||||
const idx = this.idx;
|
||||
domains.forEach(curDomain => {
|
||||
const domainIndex = idx[curDomain];
|
||||
if (!domainIndex) {
|
||||
return;
|
||||
}
|
||||
pathMatcher(domainIndex);
|
||||
});
|
||||
|
||||
cb(null, results);
|
||||
}
|
||||
|
||||
putCookie(cookie, cb) {
|
||||
if (!this.idx[cookie.domain]) {
|
||||
this.idx[cookie.domain] = Object.create(null);
|
||||
}
|
||||
if (!this.idx[cookie.domain][cookie.path]) {
|
||||
this.idx[cookie.domain][cookie.path] = Object.create(null);
|
||||
}
|
||||
this.idx[cookie.domain][cookie.path][cookie.key] = cookie;
|
||||
cb(null);
|
||||
}
|
||||
updateCookie(oldCookie, newCookie, cb) {
|
||||
// updateCookie() may avoid updating cookies that are identical. For example,
|
||||
// lastAccessed may not be important to some stores and an equality
|
||||
// comparison could exclude that field.
|
||||
this.putCookie(newCookie, cb);
|
||||
}
|
||||
removeCookie(domain, path, key, cb) {
|
||||
if (
|
||||
this.idx[domain] &&
|
||||
this.idx[domain][path] &&
|
||||
this.idx[domain][path][key]
|
||||
) {
|
||||
delete this.idx[domain][path][key];
|
||||
}
|
||||
cb(null);
|
||||
}
|
||||
removeCookies(domain, path, cb) {
|
||||
if (this.idx[domain]) {
|
||||
if (path) {
|
||||
delete this.idx[domain][path];
|
||||
} else {
|
||||
delete this.idx[domain];
|
||||
}
|
||||
}
|
||||
return cb(null);
|
||||
}
|
||||
removeAllCookies(cb) {
|
||||
this.idx = Object.create(null);
|
||||
return cb(null);
|
||||
}
|
||||
getAllCookies(cb) {
|
||||
const cookies = [];
|
||||
const idx = this.idx;
|
||||
|
||||
const domains = Object.keys(idx);
|
||||
domains.forEach(domain => {
|
||||
const paths = Object.keys(idx[domain]);
|
||||
paths.forEach(path => {
|
||||
const keys = Object.keys(idx[domain][path]);
|
||||
keys.forEach(key => {
|
||||
if (key !== null) {
|
||||
cookies.push(idx[domain][path][key]);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Sort by creationIndex so deserializing retains the creation order.
|
||||
// When implementing your own store, this SHOULD retain the order too
|
||||
cookies.sort((a, b) => {
|
||||
return (a.creationIndex || 0) - (b.creationIndex || 0);
|
||||
});
|
||||
|
||||
cb(null, cookies);
|
||||
}
|
||||
}
|
||||
|
||||
[
|
||||
"findCookie",
|
||||
"findCookies",
|
||||
"putCookie",
|
||||
"updateCookie",
|
||||
"removeCookie",
|
||||
"removeCookies",
|
||||
"removeAllCookies",
|
||||
"getAllCookies"
|
||||
].forEach(name => {
|
||||
MemoryCookieStore.prototype[name] = fromCallback(
|
||||
MemoryCookieStore.prototype[name]
|
||||
);
|
||||
});
|
||||
|
||||
exports.MemoryCookieStore = MemoryCookieStore;
|
||||
|
||||
function inspectFallback(val) {
|
||||
const domains = Object.keys(val);
|
||||
if (domains.length === 0) {
|
||||
return "[Object: null prototype] {}";
|
||||
}
|
||||
let result = "[Object: null prototype] {\n";
|
||||
Object.keys(val).forEach((domain, i) => {
|
||||
result += formatDomain(domain, val[domain]);
|
||||
if (i < domains.length - 1) {
|
||||
result += ",";
|
||||
}
|
||||
result += "\n";
|
||||
});
|
||||
result += "}";
|
||||
return result;
|
||||
}
|
||||
|
||||
function formatDomain(domainName, domainValue) {
|
||||
const indent = " ";
|
||||
let result = `${indent}'${domainName}': [Object: null prototype] {\n`;
|
||||
Object.keys(domainValue).forEach((path, i, paths) => {
|
||||
result += formatPath(path, domainValue[path]);
|
||||
if (i < paths.length - 1) {
|
||||
result += ",";
|
||||
}
|
||||
result += "\n";
|
||||
});
|
||||
result += `${indent}}`;
|
||||
return result;
|
||||
}
|
||||
|
||||
function formatPath(pathName, pathValue) {
|
||||
const indent = " ";
|
||||
let result = `${indent}'${pathName}': [Object: null prototype] {\n`;
|
||||
Object.keys(pathValue).forEach((cookieName, i, cookieNames) => {
|
||||
const cookie = pathValue[cookieName];
|
||||
result += ` ${cookieName}: ${cookie.inspect()}`;
|
||||
if (i < cookieNames.length - 1) {
|
||||
result += ",";
|
||||
}
|
||||
result += "\n";
|
||||
});
|
||||
result += `${indent}}`;
|
||||
return result;
|
||||
}
|
||||
|
||||
exports.inspectFallback = inspectFallback;
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/*!
|
||||
* Copyright (c) 2015, Salesforce.com, Inc.
|
||||
* 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 Salesforce.com 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.
|
||||
*/
|
||||
"use strict";
|
||||
/*
|
||||
* "A request-path path-matches a given cookie-path if at least one of the
|
||||
* following conditions holds:"
|
||||
*/
|
||||
function pathMatch(reqPath, cookiePath) {
|
||||
// "o The cookie-path and the request-path are identical."
|
||||
if (cookiePath === reqPath) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const idx = reqPath.indexOf(cookiePath);
|
||||
if (idx === 0) {
|
||||
// "o The cookie-path is a prefix of the request-path, and the last
|
||||
// character of the cookie-path is %x2F ("/")."
|
||||
if (cookiePath.substr(-1) === "/") {
|
||||
return true;
|
||||
}
|
||||
|
||||
// " o The cookie-path is a prefix of the request-path, and the first
|
||||
// character of the request-path that is not included in the cookie- path
|
||||
// is a %x2F ("/") character."
|
||||
if (reqPath.substr(cookiePath.length, 1) === "/") {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
exports.pathMatch = pathMatch;
|
||||
Generated
Vendored
+65
@@ -0,0 +1,65 @@
|
||||
/*!
|
||||
* Copyright (c) 2015, Salesforce.com, Inc.
|
||||
* 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 Salesforce.com 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.
|
||||
*/
|
||||
"use strict";
|
||||
const pubsuffix = require("./pubsuffix-psl");
|
||||
|
||||
// Gives the permutation of all possible domainMatch()es of a given domain. The
|
||||
// array is in shortest-to-longest order. Handy for indexing.
|
||||
|
||||
function permuteDomain(domain, allowSpecialUseDomain) {
|
||||
const pubSuf = pubsuffix.getPublicSuffix(domain, {
|
||||
allowSpecialUseDomain: allowSpecialUseDomain
|
||||
});
|
||||
|
||||
if (!pubSuf) {
|
||||
return null;
|
||||
}
|
||||
if (pubSuf == domain) {
|
||||
return [domain];
|
||||
}
|
||||
|
||||
// Nuke trailing dot
|
||||
if (domain.slice(-1) == ".") {
|
||||
domain = domain.slice(0, -1);
|
||||
}
|
||||
|
||||
const prefix = domain.slice(0, -(pubSuf.length + 1)); // ".example.com"
|
||||
const parts = prefix.split(".").reverse();
|
||||
let cur = pubSuf;
|
||||
const permutations = [cur];
|
||||
while (parts.length) {
|
||||
cur = `${parts.shift()}.${cur}`;
|
||||
permutations.push(cur);
|
||||
}
|
||||
return permutations;
|
||||
}
|
||||
|
||||
exports.permuteDomain = permuteDomain;
|
||||
Generated
Vendored
+73
@@ -0,0 +1,73 @@
|
||||
/*!
|
||||
* Copyright (c) 2018, Salesforce.com, Inc.
|
||||
* 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 Salesforce.com 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.
|
||||
*/
|
||||
"use strict";
|
||||
const psl = require("psl");
|
||||
|
||||
// RFC 6761
|
||||
const SPECIAL_USE_DOMAINS = [
|
||||
"local",
|
||||
"example",
|
||||
"invalid",
|
||||
"localhost",
|
||||
"test"
|
||||
];
|
||||
|
||||
const SPECIAL_TREATMENT_DOMAINS = ["localhost", "invalid"];
|
||||
|
||||
function getPublicSuffix(domain, options = {}) {
|
||||
const domainParts = domain.split(".");
|
||||
const topLevelDomain = domainParts[domainParts.length - 1];
|
||||
const allowSpecialUseDomain = !!options.allowSpecialUseDomain;
|
||||
const ignoreError = !!options.ignoreError;
|
||||
|
||||
if (allowSpecialUseDomain && SPECIAL_USE_DOMAINS.includes(topLevelDomain)) {
|
||||
if (domainParts.length > 1) {
|
||||
const secondLevelDomain = domainParts[domainParts.length - 2];
|
||||
// In aforementioned example, the eTLD/pubSuf will be apple.localhost
|
||||
return `${secondLevelDomain}.${topLevelDomain}`;
|
||||
} else if (SPECIAL_TREATMENT_DOMAINS.includes(topLevelDomain)) {
|
||||
// For a single word special use domain, e.g. 'localhost' or 'invalid', per RFC 6761,
|
||||
// "Application software MAY recognize {localhost/invalid} names as special, or
|
||||
// MAY pass them to name resolution APIs as they would for other domain names."
|
||||
return `${topLevelDomain}`;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ignoreError && SPECIAL_USE_DOMAINS.includes(topLevelDomain)) {
|
||||
throw new Error(
|
||||
`Cookie has domain set to the public suffix "${topLevelDomain}" which is a special use domain. To allow this, configure your CookieJar with {allowSpecialUseDomain:true, rejectPublicSuffixes: false}.`
|
||||
);
|
||||
}
|
||||
|
||||
return psl.get(domain);
|
||||
}
|
||||
|
||||
exports.getPublicSuffix = getPublicSuffix;
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
/*!
|
||||
* Copyright (c) 2015, Salesforce.com, Inc.
|
||||
* 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 Salesforce.com 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.
|
||||
*/
|
||||
"use strict";
|
||||
/*jshint unused:false */
|
||||
|
||||
class Store {
|
||||
constructor() {
|
||||
this.synchronous = false;
|
||||
}
|
||||
|
||||
findCookie(domain, path, key, cb) {
|
||||
throw new Error("findCookie is not implemented");
|
||||
}
|
||||
|
||||
findCookies(domain, path, allowSpecialUseDomain, cb) {
|
||||
throw new Error("findCookies is not implemented");
|
||||
}
|
||||
|
||||
putCookie(cookie, cb) {
|
||||
throw new Error("putCookie is not implemented");
|
||||
}
|
||||
|
||||
updateCookie(oldCookie, newCookie, cb) {
|
||||
// recommended default implementation:
|
||||
// return this.putCookie(newCookie, cb);
|
||||
throw new Error("updateCookie is not implemented");
|
||||
}
|
||||
|
||||
removeCookie(domain, path, key, cb) {
|
||||
throw new Error("removeCookie is not implemented");
|
||||
}
|
||||
|
||||
removeCookies(domain, path, cb) {
|
||||
throw new Error("removeCookies is not implemented");
|
||||
}
|
||||
|
||||
removeAllCookies(cb) {
|
||||
throw new Error("removeAllCookies is not implemented");
|
||||
}
|
||||
|
||||
getAllCookies(cb) {
|
||||
throw new Error(
|
||||
"getAllCookies is not implemented (therefore jar cannot be serialized)"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
exports.Store = Store;
|
||||
Generated
Vendored
+39
@@ -0,0 +1,39 @@
|
||||
function requireUtil() {
|
||||
try {
|
||||
// eslint-disable-next-line no-restricted-modules
|
||||
return require("util");
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// for v10.12.0+
|
||||
function lookupCustomInspectSymbol() {
|
||||
return Symbol.for("nodejs.util.inspect.custom");
|
||||
}
|
||||
|
||||
// for older node environments
|
||||
function tryReadingCustomSymbolFromUtilInspect(options) {
|
||||
const _requireUtil = options.requireUtil || requireUtil;
|
||||
const util = _requireUtil();
|
||||
return util ? util.inspect.custom : null;
|
||||
}
|
||||
|
||||
exports.getUtilInspect = function getUtilInspect(fallback, options = {}) {
|
||||
const _requireUtil = options.requireUtil || requireUtil;
|
||||
const util = _requireUtil();
|
||||
return function inspect(value, showHidden, depth) {
|
||||
return util ? util.inspect(value, showHidden, depth) : fallback(value);
|
||||
};
|
||||
};
|
||||
|
||||
exports.getCustomInspectSymbol = function getCustomInspectSymbol(options = {}) {
|
||||
const _lookupCustomInspectSymbol =
|
||||
options.lookupCustomInspectSymbol || lookupCustomInspectSymbol;
|
||||
|
||||
// get custom inspect symbol for node environments
|
||||
return (
|
||||
_lookupCustomInspectSymbol() ||
|
||||
tryReadingCustomSymbolFromUtilInspect(options)
|
||||
);
|
||||
};
|
||||
Generated
Vendored
+110
@@ -0,0 +1,110 @@
|
||||
/* ************************************************************************************
|
||||
Extracted from check-types.js
|
||||
https://gitlab.com/philbooth/check-types.js
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Phil Booth
|
||||
|
||||
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.
|
||||
|
||||
************************************************************************************ */
|
||||
"use strict";
|
||||
|
||||
/* Validation functions copied from check-types package - https://www.npmjs.com/package/check-types */
|
||||
|
||||
const toString = Object.prototype.toString;
|
||||
|
||||
function isFunction(data) {
|
||||
return typeof data === "function";
|
||||
}
|
||||
|
||||
function isNonEmptyString(data) {
|
||||
return isString(data) && data !== "";
|
||||
}
|
||||
|
||||
function isDate(data) {
|
||||
return isInstanceStrict(data, Date) && isInteger(data.getTime());
|
||||
}
|
||||
|
||||
function isEmptyString(data) {
|
||||
return data === "" || (data instanceof String && data.toString() === "");
|
||||
}
|
||||
|
||||
function isString(data) {
|
||||
return typeof data === "string" || data instanceof String;
|
||||
}
|
||||
|
||||
function isObject(data) {
|
||||
return toString.call(data) === "[object Object]";
|
||||
}
|
||||
function isInstanceStrict(data, prototype) {
|
||||
try {
|
||||
return data instanceof prototype;
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function isUrlStringOrObject(data) {
|
||||
return (
|
||||
isNonEmptyString(data) ||
|
||||
(isObject(data) &&
|
||||
"hostname" in data &&
|
||||
"pathname" in data &&
|
||||
"protocol" in data) ||
|
||||
isInstanceStrict(data, URL)
|
||||
);
|
||||
}
|
||||
|
||||
function isInteger(data) {
|
||||
return typeof data === "number" && data % 1 === 0;
|
||||
}
|
||||
/* End validation functions */
|
||||
|
||||
function validate(bool, cb, options) {
|
||||
if (!isFunction(cb)) {
|
||||
options = cb;
|
||||
cb = null;
|
||||
}
|
||||
if (!isObject(options)) options = { Error: "Failed Check" };
|
||||
if (!bool) {
|
||||
if (cb) {
|
||||
cb(new ParameterError(options));
|
||||
} else {
|
||||
throw new ParameterError(options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ParameterError extends Error {
|
||||
constructor(...params) {
|
||||
super(...params);
|
||||
}
|
||||
}
|
||||
|
||||
exports.ParameterError = ParameterError;
|
||||
exports.isFunction = isFunction;
|
||||
exports.isNonEmptyString = isNonEmptyString;
|
||||
exports.isDate = isDate;
|
||||
exports.isEmptyString = isEmptyString;
|
||||
exports.isString = isString;
|
||||
exports.isObject = isObject;
|
||||
exports.isUrlStringOrObject = isUrlStringOrObject;
|
||||
exports.validate = validate;
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
// generated by genversion
|
||||
module.exports = '4.1.4'
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
{
|
||||
"author": {
|
||||
"name": "Jeremy Stashewsky",
|
||||
"email": "jstash@gmail.com",
|
||||
"website": "https://github.com/stash"
|
||||
},
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Ivan Nikulin",
|
||||
"website": "https://github.com/inikulin"
|
||||
},
|
||||
{
|
||||
"name": "Shivan Kaul Sahib",
|
||||
"website": "https://github.com/ShivanKaul"
|
||||
},
|
||||
{
|
||||
"name": "Clint Ruoho",
|
||||
"website": "https://github.com/ruoho"
|
||||
},
|
||||
{
|
||||
"name": "Ian Livingstone",
|
||||
"website": "https://github.com/ianlivingstone"
|
||||
},
|
||||
{
|
||||
"name": "Andrew Waterman",
|
||||
"website": "https://github.com/awaterma"
|
||||
},
|
||||
{
|
||||
"name": "Michael de Libero ",
|
||||
"website": "https://github.com/medelibero-sfdc"
|
||||
},
|
||||
{
|
||||
"name": "Jonathan Stewmon",
|
||||
"website": "https://github.com/jstewmon"
|
||||
},
|
||||
{
|
||||
"name": "Miguel Roncancio",
|
||||
"website": "https://github.com/miggs125"
|
||||
},
|
||||
{
|
||||
"name": "Sebastian Mayr",
|
||||
"website": "https://github.com/Sebmaster"
|
||||
},
|
||||
{
|
||||
"name": "Alexander Savin",
|
||||
"website": "https://github.com/apsavin"
|
||||
},
|
||||
{
|
||||
"name": "Lalit Kapoor",
|
||||
"website": "https://github.com/lalitkapoor"
|
||||
},
|
||||
{
|
||||
"name": "Sam Thompson",
|
||||
"website": "https://github.com/sambthompson"
|
||||
}
|
||||
],
|
||||
"license": "BSD-3-Clause",
|
||||
"name": "tough-cookie",
|
||||
"description": "RFC6265 Cookies and Cookie Jar for node.js",
|
||||
"keywords": [
|
||||
"HTTP",
|
||||
"cookie",
|
||||
"cookies",
|
||||
"set-cookie",
|
||||
"cookiejar",
|
||||
"jar",
|
||||
"RFC6265",
|
||||
"RFC2965"
|
||||
],
|
||||
"version": "4.1.4",
|
||||
"homepage": "https://github.com/salesforce/tough-cookie",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/salesforce/tough-cookie.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/salesforce/tough-cookie/issues"
|
||||
},
|
||||
"main": "./lib/cookie",
|
||||
"files": [
|
||||
"lib"
|
||||
],
|
||||
"scripts": {
|
||||
"version": "genversion lib/version.js && git add lib/version.js",
|
||||
"test": "vows test/*_test.js && npm run eslint",
|
||||
"cover": "nyc --reporter=lcov --reporter=html vows test/*_test.js",
|
||||
"eslint": "eslint --env node --ext .js .",
|
||||
"prettier": "prettier '**/*.{json,ts,yaml,md}'",
|
||||
"format": "npm run eslint -- --fix"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"async": "^2.6.2",
|
||||
"eslint": "^5.16.0",
|
||||
"eslint-config-prettier": "^4.2.0",
|
||||
"eslint-plugin-prettier": "^3.0.1",
|
||||
"genversion": "^2.1.0",
|
||||
"nyc": "^14.0.0",
|
||||
"prettier": "^1.17.0",
|
||||
"vows": "^0.8.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"psl": "^1.1.33",
|
||||
"punycode": "^2.1.1",
|
||||
"universalify": "^0.2.0",
|
||||
"url-parse": "^1.5.3"
|
||||
}
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
{
|
||||
"name": "@cypress/request-promise",
|
||||
"version": "5.0.0",
|
||||
"description": "Cypress's fork of the simplified HTTP request client 'request' with Promise support. Powered by Bluebird.",
|
||||
"keywords": [
|
||||
"xhr",
|
||||
"http",
|
||||
"https",
|
||||
"promise",
|
||||
"request",
|
||||
"then",
|
||||
"thenable",
|
||||
"bluebird"
|
||||
],
|
||||
"main": "./lib/rp.js",
|
||||
"scripts": {
|
||||
"test": "./node_modules/.bin/gulp ci",
|
||||
"test-publish": "./node_modules/.bin/gulp ci-no-cov",
|
||||
"publish-please": "publish-please"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/cypress-io/request-promise.git"
|
||||
},
|
||||
"author": "Nicolai Kamenzky (https://github.com/analog-nico)",
|
||||
"license": "ISC",
|
||||
"bugs": {
|
||||
"url": "https://github.com/cypress-io/request-promise/issues"
|
||||
},
|
||||
"homepage": "https://github.com/cypress-io/request-promise#readme",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"request-promise-core": "1.1.3",
|
||||
"bluebird": "^3.5.0",
|
||||
"stealthy-require": "^1.1.1",
|
||||
"tough-cookie": "^4.1.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@cypress/request": "^3.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"body-parser": "~1.15.2",
|
||||
"chai": "~3.5.0",
|
||||
"chalk": "~1.1.3",
|
||||
"gulp": "~3.9.1",
|
||||
"gulp-coveralls": "~0.1.4",
|
||||
"gulp-eslint": "~2.1.0",
|
||||
"gulp-istanbul": "~1.0.0",
|
||||
"gulp-mocha": "~2.2.0",
|
||||
"lodash": "~4.13.1",
|
||||
"publish-please": "~2.1.4",
|
||||
"@cypress/request": "^3.0.0",
|
||||
"rimraf": "~2.5.3",
|
||||
"run-sequence": "~1.2.2"
|
||||
},
|
||||
"resolutions": {
|
||||
"chalk": "~1.1.3"
|
||||
}
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
Apache License
|
||||
|
||||
Version 2.0, January 2004
|
||||
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
|
||||
|
||||
You must give any other recipients of the Work or Derivative Works a copy of this License; and
|
||||
|
||||
You must cause any modified files to carry prominent notices stating that You changed the files; and
|
||||
|
||||
You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
|
||||
|
||||
If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
+1032
File diff suppressed because it is too large.
Load diff
+155
@@ -0,0 +1,155 @@
|
||||
// Copyright 2010-2012 Mikeal Rogers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
'use strict'
|
||||
|
||||
var extend = require('extend')
|
||||
var cookies = require('./lib/cookies')
|
||||
var helpers = require('./lib/helpers')
|
||||
|
||||
var paramsHaveRequestBody = helpers.paramsHaveRequestBody
|
||||
|
||||
// organize params for patch, post, put, head, del
|
||||
function initParams (uri, options, callback) {
|
||||
if (typeof options === 'function') {
|
||||
callback = options
|
||||
}
|
||||
|
||||
var params = {}
|
||||
if (options !== null && typeof options === 'object') {
|
||||
extend(params, options, {uri: uri})
|
||||
} else if (typeof uri === 'string') {
|
||||
extend(params, {uri: uri})
|
||||
} else {
|
||||
extend(params, uri)
|
||||
}
|
||||
|
||||
params.callback = callback || params.callback
|
||||
return params
|
||||
}
|
||||
|
||||
function request (uri, options, callback) {
|
||||
if (typeof uri === 'undefined') {
|
||||
throw new Error('undefined is not a valid uri or options object.')
|
||||
}
|
||||
|
||||
var params = initParams(uri, options, callback)
|
||||
|
||||
if (params.method === 'HEAD' && paramsHaveRequestBody(params)) {
|
||||
throw new Error('HTTP HEAD requests MUST NOT include a request body.')
|
||||
}
|
||||
|
||||
return new request.Request(params)
|
||||
}
|
||||
|
||||
function verbFunc (verb) {
|
||||
var method = verb.toUpperCase()
|
||||
return function (uri, options, callback) {
|
||||
var params = initParams(uri, options, callback)
|
||||
params.method = method
|
||||
return request(params, params.callback)
|
||||
}
|
||||
}
|
||||
|
||||
// define like this to please codeintel/intellisense IDEs
|
||||
request.get = verbFunc('get')
|
||||
request.head = verbFunc('head')
|
||||
request.options = verbFunc('options')
|
||||
request.post = verbFunc('post')
|
||||
request.put = verbFunc('put')
|
||||
request.patch = verbFunc('patch')
|
||||
request.del = verbFunc('delete')
|
||||
request['delete'] = verbFunc('delete')
|
||||
|
||||
request.jar = function (store) {
|
||||
return cookies.jar(store)
|
||||
}
|
||||
|
||||
request.cookie = function (str) {
|
||||
return cookies.parse(str)
|
||||
}
|
||||
|
||||
function wrapRequestMethod (method, options, requester, verb) {
|
||||
return function (uri, opts, callback) {
|
||||
var params = initParams(uri, opts, callback)
|
||||
|
||||
var target = {}
|
||||
extend(true, target, options, params)
|
||||
|
||||
target.pool = params.pool || options.pool
|
||||
|
||||
if (verb) {
|
||||
target.method = verb.toUpperCase()
|
||||
}
|
||||
|
||||
if (typeof requester === 'function') {
|
||||
method = requester
|
||||
}
|
||||
|
||||
return method(target, target.callback)
|
||||
}
|
||||
}
|
||||
|
||||
request.defaults = function (options, requester) {
|
||||
var self = this
|
||||
|
||||
options = options || {}
|
||||
|
||||
if (typeof options === 'function') {
|
||||
requester = options
|
||||
options = {}
|
||||
}
|
||||
|
||||
var defaults = wrapRequestMethod(self, options, requester)
|
||||
|
||||
var verbs = ['get', 'head', 'post', 'put', 'patch', 'del', 'delete']
|
||||
verbs.forEach(function (verb) {
|
||||
defaults[verb] = wrapRequestMethod(self[verb], options, requester, verb)
|
||||
})
|
||||
|
||||
defaults.cookie = wrapRequestMethod(self.cookie, options, requester)
|
||||
defaults.jar = self.jar
|
||||
defaults.defaults = self.defaults
|
||||
return defaults
|
||||
}
|
||||
|
||||
request.forever = function (agentOptions, optionsArg) {
|
||||
var options = {}
|
||||
if (optionsArg) {
|
||||
extend(options, optionsArg)
|
||||
}
|
||||
if (agentOptions) {
|
||||
options.agentOptions = agentOptions
|
||||
}
|
||||
|
||||
options.forever = true
|
||||
return request.defaults(options)
|
||||
}
|
||||
|
||||
// Exports
|
||||
|
||||
module.exports = request
|
||||
request.Request = require('./request')
|
||||
request.initParams = initParams
|
||||
|
||||
// Backwards compatibility for request.debug
|
||||
Object.defineProperty(request, 'debug', {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return request.Request.debug
|
||||
},
|
||||
set: function (debug) {
|
||||
request.Request.debug = debug
|
||||
}
|
||||
})
|
||||
+167
@@ -0,0 +1,167 @@
|
||||
'use strict'
|
||||
|
||||
var caseless = require('caseless')
|
||||
var { v4: uuid } = require('uuid')
|
||||
var helpers = require('./helpers')
|
||||
|
||||
var md5 = helpers.md5
|
||||
var toBase64 = helpers.toBase64
|
||||
|
||||
function Auth (request) {
|
||||
// define all public properties here
|
||||
this.request = request
|
||||
this.hasAuth = false
|
||||
this.sentAuth = false
|
||||
this.bearerToken = null
|
||||
this.user = null
|
||||
this.pass = null
|
||||
}
|
||||
|
||||
Auth.prototype.basic = function (user, pass, sendImmediately) {
|
||||
var self = this
|
||||
if (typeof user !== 'string' || (pass !== undefined && typeof pass !== 'string')) {
|
||||
self.request.emit('error', new Error('auth() received invalid user or password'))
|
||||
}
|
||||
self.user = user
|
||||
self.pass = pass
|
||||
self.hasAuth = true
|
||||
var header = user + ':' + (pass || '')
|
||||
if (sendImmediately || typeof sendImmediately === 'undefined') {
|
||||
var authHeader = 'Basic ' + toBase64(header)
|
||||
self.sentAuth = true
|
||||
return authHeader
|
||||
}
|
||||
}
|
||||
|
||||
Auth.prototype.bearer = function (bearer, sendImmediately) {
|
||||
var self = this
|
||||
self.bearerToken = bearer
|
||||
self.hasAuth = true
|
||||
if (sendImmediately || typeof sendImmediately === 'undefined') {
|
||||
if (typeof bearer === 'function') {
|
||||
bearer = bearer()
|
||||
}
|
||||
var authHeader = 'Bearer ' + (bearer || '')
|
||||
self.sentAuth = true
|
||||
return authHeader
|
||||
}
|
||||
}
|
||||
|
||||
Auth.prototype.digest = function (method, path, authHeader) {
|
||||
// TODO: More complete implementation of RFC 2617.
|
||||
// - handle challenge.domain
|
||||
// - support qop="auth-int" only
|
||||
// - handle Authentication-Info (not necessarily?)
|
||||
// - check challenge.stale (not necessarily?)
|
||||
// - increase nc (not necessarily?)
|
||||
// For reference:
|
||||
// http://tools.ietf.org/html/rfc2617#section-3
|
||||
// https://github.com/bagder/curl/blob/master/lib/http_digest.c
|
||||
|
||||
var self = this
|
||||
|
||||
var challenge = {}
|
||||
var re = /([a-z0-9_-]+)=(?:"([^"]+)"|([a-z0-9_-]+))/gi
|
||||
while (true) {
|
||||
var match = re.exec(authHeader)
|
||||
if (!match) {
|
||||
break
|
||||
}
|
||||
challenge[match[1]] = match[2] || match[3]
|
||||
}
|
||||
|
||||
/**
|
||||
* RFC 2617: handle both MD5 and MD5-sess algorithms.
|
||||
*
|
||||
* If the algorithm directive's value is "MD5" or unspecified, then HA1 is
|
||||
* HA1=MD5(username:realm:password)
|
||||
* If the algorithm directive's value is "MD5-sess", then HA1 is
|
||||
* HA1=MD5(MD5(username:realm:password):nonce:cnonce)
|
||||
*/
|
||||
var ha1Compute = function (algorithm, user, realm, pass, nonce, cnonce) {
|
||||
var ha1 = md5(user + ':' + realm + ':' + pass)
|
||||
if (algorithm && algorithm.toLowerCase() === 'md5-sess') {
|
||||
return md5(ha1 + ':' + nonce + ':' + cnonce)
|
||||
} else {
|
||||
return ha1
|
||||
}
|
||||
}
|
||||
|
||||
var qop = /(^|,)\s*auth\s*($|,)/.test(challenge.qop) && 'auth'
|
||||
var nc = qop && '00000001'
|
||||
var cnonce = qop && uuid().replace(/-/g, '')
|
||||
var ha1 = ha1Compute(challenge.algorithm, self.user, challenge.realm, self.pass, challenge.nonce, cnonce)
|
||||
var ha2 = md5(method + ':' + path)
|
||||
var digestResponse = qop
|
||||
? md5(ha1 + ':' + challenge.nonce + ':' + nc + ':' + cnonce + ':' + qop + ':' + ha2)
|
||||
: md5(ha1 + ':' + challenge.nonce + ':' + ha2)
|
||||
var authValues = {
|
||||
username: self.user,
|
||||
realm: challenge.realm,
|
||||
nonce: challenge.nonce,
|
||||
uri: path,
|
||||
qop: qop,
|
||||
response: digestResponse,
|
||||
nc: nc,
|
||||
cnonce: cnonce,
|
||||
algorithm: challenge.algorithm,
|
||||
opaque: challenge.opaque
|
||||
}
|
||||
|
||||
authHeader = []
|
||||
for (var k in authValues) {
|
||||
if (authValues[k]) {
|
||||
if (k === 'qop' || k === 'nc' || k === 'algorithm') {
|
||||
authHeader.push(k + '=' + authValues[k])
|
||||
} else {
|
||||
authHeader.push(k + '="' + authValues[k] + '"')
|
||||
}
|
||||
}
|
||||
}
|
||||
authHeader = 'Digest ' + authHeader.join(', ')
|
||||
self.sentAuth = true
|
||||
return authHeader
|
||||
}
|
||||
|
||||
Auth.prototype.onRequest = function (user, pass, sendImmediately, bearer) {
|
||||
var self = this
|
||||
var request = self.request
|
||||
|
||||
var authHeader
|
||||
if (bearer === undefined && user === undefined) {
|
||||
self.request.emit('error', new Error('no auth mechanism defined'))
|
||||
} else if (bearer !== undefined) {
|
||||
authHeader = self.bearer(bearer, sendImmediately)
|
||||
} else {
|
||||
authHeader = self.basic(user, pass, sendImmediately)
|
||||
}
|
||||
if (authHeader) {
|
||||
request.setHeader('authorization', authHeader)
|
||||
}
|
||||
}
|
||||
|
||||
Auth.prototype.onResponse = function (response) {
|
||||
var self = this
|
||||
var request = self.request
|
||||
|
||||
if (!self.hasAuth || self.sentAuth) { return null }
|
||||
|
||||
var c = caseless(response.headers)
|
||||
|
||||
var authHeader = c.get('www-authenticate')
|
||||
var authVerb = authHeader && authHeader.split(' ')[0].toLowerCase()
|
||||
request.debug('reauth', authVerb)
|
||||
|
||||
switch (authVerb) {
|
||||
case 'basic':
|
||||
return self.basic(self.user, self.pass, true)
|
||||
|
||||
case 'bearer':
|
||||
return self.bearer(self.bearerToken, true)
|
||||
|
||||
case 'digest':
|
||||
return self.digest(request.method, request.path, authHeader)
|
||||
}
|
||||
}
|
||||
|
||||
exports.Auth = Auth
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
'use strict'
|
||||
|
||||
var tough = require('tough-cookie')
|
||||
|
||||
var Cookie = tough.Cookie
|
||||
var CookieJar = tough.CookieJar
|
||||
|
||||
exports.parse = function (str) {
|
||||
if (str && str.uri) {
|
||||
str = str.uri
|
||||
}
|
||||
if (typeof str !== 'string') {
|
||||
throw new Error('The cookie function only accepts STRING as param')
|
||||
}
|
||||
return Cookie.parse(str, {loose: true})
|
||||
}
|
||||
|
||||
// Adapt the sometimes-Async api of tough.CookieJar to our requirements
|
||||
function RequestJar (store) {
|
||||
var self = this
|
||||
self._jar = new CookieJar(store, {looseMode: true})
|
||||
}
|
||||
RequestJar.prototype.setCookie = function (cookieOrStr, uri, options) {
|
||||
var self = this
|
||||
return self._jar.setCookieSync(cookieOrStr, uri, options || {})
|
||||
}
|
||||
RequestJar.prototype.getCookieString = function (uri) {
|
||||
var self = this
|
||||
return self._jar.getCookieStringSync(uri)
|
||||
}
|
||||
RequestJar.prototype.getCookies = function (uri) {
|
||||
var self = this
|
||||
return self._jar.getCookiesSync(uri)
|
||||
}
|
||||
|
||||
exports.jar = function (store) {
|
||||
return new RequestJar(store)
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
'use strict'
|
||||
|
||||
function formatHostname (hostname) {
|
||||
// canonicalize the hostname, so that 'oogle.com' won't match 'google.com'
|
||||
return hostname.replace(/^\.*/, '.').toLowerCase()
|
||||
}
|
||||
|
||||
function parseNoProxyZone (zone) {
|
||||
zone = zone.trim().toLowerCase()
|
||||
|
||||
var zoneParts = zone.split(':', 2)
|
||||
var zoneHost = formatHostname(zoneParts[0])
|
||||
var zonePort = zoneParts[1]
|
||||
var hasPort = zone.indexOf(':') > -1
|
||||
|
||||
return {hostname: zoneHost, port: zonePort, hasPort: hasPort}
|
||||
}
|
||||
|
||||
function uriInNoProxy (uri, noProxy) {
|
||||
var port = uri.port || (uri.protocol === 'https:' ? '443' : '80')
|
||||
var hostname = formatHostname(uri.hostname)
|
||||
var noProxyList = noProxy.split(',')
|
||||
|
||||
// iterate through the noProxyList until it finds a match.
|
||||
return noProxyList.map(parseNoProxyZone).some(function (noProxyZone) {
|
||||
var isMatchedAt = hostname.indexOf(noProxyZone.hostname)
|
||||
var hostnameMatched = (
|
||||
isMatchedAt > -1 &&
|
||||
(isMatchedAt === hostname.length - noProxyZone.hostname.length)
|
||||
)
|
||||
|
||||
if (noProxyZone.hasPort) {
|
||||
return (port === noProxyZone.port) && hostnameMatched
|
||||
}
|
||||
|
||||
return hostnameMatched
|
||||
})
|
||||
}
|
||||
|
||||
function getProxyFromURI (uri) {
|
||||
// Decide the proper request proxy to use based on the request URI object and the
|
||||
// environmental variables (NO_PROXY, HTTP_PROXY, etc.)
|
||||
// respect NO_PROXY environment variables (see: https://lynx.invisible-island.net/lynx2.8.7/breakout/lynx_help/keystrokes/environments.html)
|
||||
|
||||
var noProxy = process.env.NO_PROXY || process.env.no_proxy || ''
|
||||
|
||||
// if the noProxy is a wildcard then return null
|
||||
|
||||
if (noProxy === '*') {
|
||||
return null
|
||||
}
|
||||
|
||||
// if the noProxy is not empty and the uri is found return null
|
||||
|
||||
if (noProxy !== '' && uriInNoProxy(uri, noProxy)) {
|
||||
return null
|
||||
}
|
||||
|
||||
// Check for HTTP or HTTPS Proxy in environment Else default to null
|
||||
|
||||
if (uri.protocol === 'http:') {
|
||||
return process.env.HTTP_PROXY ||
|
||||
process.env.http_proxy || null
|
||||
}
|
||||
|
||||
if (uri.protocol === 'https:') {
|
||||
return process.env.HTTPS_PROXY ||
|
||||
process.env.https_proxy ||
|
||||
process.env.HTTP_PROXY ||
|
||||
process.env.http_proxy || null
|
||||
}
|
||||
|
||||
// if none of that works, return null
|
||||
// (What uri protocol are you using then?)
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
module.exports = getProxyFromURI
|
||||
+200
@@ -0,0 +1,200 @@
|
||||
'use strict'
|
||||
|
||||
var fs = require('fs')
|
||||
var qs = require('querystring')
|
||||
var extend = require('extend')
|
||||
|
||||
function Har (request) {
|
||||
this.request = request
|
||||
}
|
||||
|
||||
Har.prototype.reducer = function (obj, pair) {
|
||||
// new property ?
|
||||
if (obj[pair.name] === undefined) {
|
||||
obj[pair.name] = pair.value
|
||||
return obj
|
||||
}
|
||||
|
||||
// existing? convert to array
|
||||
var arr = [
|
||||
obj[pair.name],
|
||||
pair.value
|
||||
]
|
||||
|
||||
obj[pair.name] = arr
|
||||
|
||||
return obj
|
||||
}
|
||||
|
||||
Har.prototype.prep = function (data) {
|
||||
// construct utility properties
|
||||
data.queryObj = {}
|
||||
data.headersObj = {}
|
||||
data.postData.jsonObj = false
|
||||
data.postData.paramsObj = false
|
||||
|
||||
// construct query objects
|
||||
if (data.queryString && data.queryString.length) {
|
||||
data.queryObj = data.queryString.reduce(this.reducer, {})
|
||||
}
|
||||
|
||||
// construct headers objects
|
||||
if (data.headers && data.headers.length) {
|
||||
// loweCase header keys
|
||||
data.headersObj = data.headers.reduceRight(function (headers, header) {
|
||||
headers[header.name] = header.value
|
||||
return headers
|
||||
}, {})
|
||||
}
|
||||
|
||||
// construct Cookie header
|
||||
if (data.cookies && data.cookies.length) {
|
||||
var cookies = data.cookies.map(function (cookie) {
|
||||
return cookie.name + '=' + cookie.value
|
||||
})
|
||||
|
||||
if (cookies.length) {
|
||||
data.headersObj.cookie = cookies.join('; ')
|
||||
}
|
||||
}
|
||||
|
||||
// prep body
|
||||
function some (arr) {
|
||||
return arr.some(function (type) {
|
||||
return data.postData.mimeType.indexOf(type) === 0
|
||||
})
|
||||
}
|
||||
|
||||
if (some([
|
||||
'multipart/mixed',
|
||||
'multipart/related',
|
||||
'multipart/form-data',
|
||||
'multipart/alternative'])) {
|
||||
// reset values
|
||||
data.postData.mimeType = 'multipart/form-data'
|
||||
} else if (some([
|
||||
'application/x-www-form-urlencoded'])) {
|
||||
if (!data.postData.params) {
|
||||
data.postData.text = ''
|
||||
} else {
|
||||
data.postData.paramsObj = data.postData.params.reduce(this.reducer, {})
|
||||
|
||||
// always overwrite
|
||||
data.postData.text = qs.stringify(data.postData.paramsObj)
|
||||
}
|
||||
} else if (some([
|
||||
'text/json',
|
||||
'text/x-json',
|
||||
'application/json',
|
||||
'application/x-json'])) {
|
||||
data.postData.mimeType = 'application/json'
|
||||
|
||||
if (data.postData.text) {
|
||||
try {
|
||||
data.postData.jsonObj = JSON.parse(data.postData.text)
|
||||
} catch (e) {
|
||||
this.request.debug(e)
|
||||
|
||||
// force back to text/plain
|
||||
data.postData.mimeType = 'text/plain'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
Har.prototype.options = function (options) {
|
||||
// skip if no har property defined
|
||||
if (!options.har) {
|
||||
return options
|
||||
}
|
||||
|
||||
var har = {}
|
||||
extend(har, options.har)
|
||||
|
||||
// only process the first entry
|
||||
if (har.log && har.log.entries) {
|
||||
har = har.log.entries[0]
|
||||
}
|
||||
|
||||
// add optional properties to make validation successful
|
||||
har.url = har.url || options.url || options.uri || options.baseUrl || '/'
|
||||
har.httpVersion = har.httpVersion || 'HTTP/1.1'
|
||||
har.queryString = har.queryString || []
|
||||
har.headers = har.headers || []
|
||||
har.cookies = har.cookies || []
|
||||
har.postData = har.postData || {}
|
||||
har.postData.mimeType = har.postData.mimeType || 'application/octet-stream'
|
||||
|
||||
har.bodySize = 0
|
||||
har.headersSize = 0
|
||||
har.postData.size = 0
|
||||
|
||||
// clean up and get some utility properties
|
||||
var req = this.prep(har)
|
||||
|
||||
// construct new options
|
||||
if (req.url) {
|
||||
options.url = req.url
|
||||
}
|
||||
|
||||
if (req.method) {
|
||||
options.method = req.method
|
||||
}
|
||||
|
||||
if (Object.keys(req.queryObj).length) {
|
||||
options.qs = req.queryObj
|
||||
}
|
||||
|
||||
if (Object.keys(req.headersObj).length) {
|
||||
options.headers = req.headersObj
|
||||
}
|
||||
|
||||
function test (type) {
|
||||
return req.postData.mimeType.indexOf(type) === 0
|
||||
}
|
||||
if (test('application/x-www-form-urlencoded')) {
|
||||
options.form = req.postData.paramsObj
|
||||
} else if (test('application/json')) {
|
||||
if (req.postData.jsonObj) {
|
||||
options.body = req.postData.jsonObj
|
||||
options.json = true
|
||||
}
|
||||
} else if (test('multipart/form-data')) {
|
||||
options.formData = {}
|
||||
|
||||
req.postData.params.forEach(function (param) {
|
||||
var attachment = {}
|
||||
|
||||
if (!param.fileName && !param.contentType) {
|
||||
options.formData[param.name] = param.value
|
||||
return
|
||||
}
|
||||
|
||||
// attempt to read from disk!
|
||||
if (param.fileName && !param.value) {
|
||||
attachment.value = fs.createReadStream(param.fileName)
|
||||
} else if (param.value) {
|
||||
attachment.value = param.value
|
||||
}
|
||||
|
||||
if (param.fileName) {
|
||||
attachment.options = {
|
||||
filename: param.fileName,
|
||||
contentType: param.contentType ? param.contentType : null
|
||||
}
|
||||
}
|
||||
|
||||
options.formData[param.name] = attachment
|
||||
})
|
||||
} else {
|
||||
if (req.postData.text) {
|
||||
options.body = req.postData.text
|
||||
}
|
||||
}
|
||||
|
||||
return options
|
||||
}
|
||||
|
||||
exports.Har = Har
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
'use strict'
|
||||
|
||||
var crypto = require('crypto')
|
||||
|
||||
function randomString (size) {
|
||||
var bits = (size + 1) * 6
|
||||
var buffer = crypto.randomBytes(Math.ceil(bits / 8))
|
||||
var string = buffer.toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '')
|
||||
return string.slice(0, size)
|
||||
}
|
||||
|
||||
function calculatePayloadHash (payload, algorithm, contentType) {
|
||||
var hash = crypto.createHash(algorithm)
|
||||
hash.update('hawk.1.payload\n')
|
||||
hash.update((contentType ? contentType.split(';')[0].trim().toLowerCase() : '') + '\n')
|
||||
hash.update(payload || '')
|
||||
hash.update('\n')
|
||||
return hash.digest('base64')
|
||||
}
|
||||
|
||||
exports.calculateMac = function (credentials, opts) {
|
||||
var normalized = 'hawk.1.header\n' +
|
||||
opts.ts + '\n' +
|
||||
opts.nonce + '\n' +
|
||||
(opts.method || '').toUpperCase() + '\n' +
|
||||
opts.resource + '\n' +
|
||||
opts.host.toLowerCase() + '\n' +
|
||||
opts.port + '\n' +
|
||||
(opts.hash || '') + '\n'
|
||||
|
||||
if (opts.ext) {
|
||||
normalized = normalized + opts.ext.replace('\\', '\\\\').replace('\n', '\\n')
|
||||
}
|
||||
|
||||
normalized = normalized + '\n'
|
||||
|
||||
if (opts.app) {
|
||||
normalized = normalized + opts.app + '\n' + (opts.dlg || '') + '\n'
|
||||
}
|
||||
|
||||
var hmac = crypto.createHmac(credentials.algorithm, credentials.key).update(normalized)
|
||||
var digest = hmac.digest('base64')
|
||||
return digest
|
||||
}
|
||||
|
||||
exports.header = function (uri, method, opts) {
|
||||
var timestamp = opts.timestamp || Math.floor((Date.now() + (opts.localtimeOffsetMsec || 0)) / 1000)
|
||||
var credentials = opts.credentials
|
||||
if (!credentials || !credentials.id || !credentials.key || !credentials.algorithm) {
|
||||
return ''
|
||||
}
|
||||
|
||||
if (['sha1', 'sha256'].indexOf(credentials.algorithm) === -1) {
|
||||
return ''
|
||||
}
|
||||
|
||||
var artifacts = {
|
||||
ts: timestamp,
|
||||
nonce: opts.nonce || randomString(6),
|
||||
method: method,
|
||||
resource: uri.pathname + (uri.search || ''),
|
||||
host: uri.hostname,
|
||||
port: uri.port || (uri.protocol === 'http:' ? 80 : 443),
|
||||
hash: opts.hash,
|
||||
ext: opts.ext,
|
||||
app: opts.app,
|
||||
dlg: opts.dlg
|
||||
}
|
||||
|
||||
if (!artifacts.hash && (opts.payload || opts.payload === '')) {
|
||||
artifacts.hash = calculatePayloadHash(opts.payload, credentials.algorithm, opts.contentType)
|
||||
}
|
||||
|
||||
var mac = exports.calculateMac(credentials, artifacts)
|
||||
|
||||
var hasExt = artifacts.ext !== null && artifacts.ext !== undefined && artifacts.ext !== ''
|
||||
var header = 'Hawk id="' + credentials.id +
|
||||
'", ts="' + artifacts.ts +
|
||||
'", nonce="' + artifacts.nonce +
|
||||
(artifacts.hash ? '", hash="' + artifacts.hash : '') +
|
||||
(hasExt ? '", ext="' + artifacts.ext.replace(/\\/g, '\\\\').replace(/"/g, '\\"') : '') +
|
||||
'", mac="' + mac + '"'
|
||||
|
||||
if (artifacts.app) {
|
||||
header = header + ', app="' + artifacts.app + (artifacts.dlg ? '", dlg="' + artifacts.dlg : '') + '"'
|
||||
}
|
||||
|
||||
return header
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
'use strict'
|
||||
|
||||
var jsonSafeStringify = require('json-stringify-safe')
|
||||
var crypto = require('crypto')
|
||||
var Buffer = require('safe-buffer').Buffer
|
||||
|
||||
var defer = typeof setImmediate === 'undefined'
|
||||
? process.nextTick
|
||||
: setImmediate
|
||||
|
||||
function paramsHaveRequestBody (params) {
|
||||
return (
|
||||
params.body ||
|
||||
params.requestBodyStream ||
|
||||
(params.json && typeof params.json !== 'boolean') ||
|
||||
params.multipart
|
||||
)
|
||||
}
|
||||
|
||||
function safeStringify (obj, replacer) {
|
||||
var ret
|
||||
try {
|
||||
ret = JSON.stringify(obj, replacer)
|
||||
} catch (e) {
|
||||
ret = jsonSafeStringify(obj, replacer)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
function md5 (str) {
|
||||
return crypto.createHash('md5').update(str).digest('hex')
|
||||
}
|
||||
|
||||
function isReadStream (rs) {
|
||||
return rs.readable && rs.path && rs.mode
|
||||
}
|
||||
|
||||
function toBase64 (str) {
|
||||
return Buffer.from(str || '', 'utf8').toString('base64')
|
||||
}
|
||||
|
||||
function copy (obj) {
|
||||
var o = {}
|
||||
Object.keys(obj).forEach(function (i) {
|
||||
o[i] = obj[i]
|
||||
})
|
||||
return o
|
||||
}
|
||||
|
||||
function version () {
|
||||
var numbers = process.version.replace('v', '').split('.')
|
||||
return {
|
||||
major: parseInt(numbers[0], 10),
|
||||
minor: parseInt(numbers[1], 10),
|
||||
patch: parseInt(numbers[2], 10)
|
||||
}
|
||||
}
|
||||
|
||||
exports.paramsHaveRequestBody = paramsHaveRequestBody
|
||||
exports.safeStringify = safeStringify
|
||||
exports.md5 = md5
|
||||
exports.isReadStream = isReadStream
|
||||
exports.toBase64 = toBase64
|
||||
exports.copy = copy
|
||||
exports.version = version
|
||||
exports.defer = defer
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
'use strict'
|
||||
|
||||
var { v4: uuid } = require('uuid')
|
||||
var CombinedStream = require('combined-stream')
|
||||
var isstream = require('isstream')
|
||||
var Buffer = require('safe-buffer').Buffer
|
||||
|
||||
function Multipart (request) {
|
||||
this.request = request
|
||||
this.boundary = uuid()
|
||||
this.chunked = false
|
||||
this.body = null
|
||||
}
|
||||
|
||||
Multipart.prototype.isChunked = function (options) {
|
||||
var self = this
|
||||
var chunked = false
|
||||
var parts = options.data || options
|
||||
|
||||
if (!parts.forEach) {
|
||||
self.request.emit('error', new Error('Argument error, options.multipart.'))
|
||||
}
|
||||
|
||||
if (options.chunked !== undefined) {
|
||||
chunked = options.chunked
|
||||
}
|
||||
|
||||
if (self.request.getHeader('transfer-encoding') === 'chunked') {
|
||||
chunked = true
|
||||
}
|
||||
|
||||
if (!chunked) {
|
||||
parts.forEach(function (part) {
|
||||
if (typeof part.body === 'undefined') {
|
||||
self.request.emit('error', new Error('Body attribute missing in multipart.'))
|
||||
}
|
||||
if (isstream(part.body)) {
|
||||
chunked = true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return chunked
|
||||
}
|
||||
|
||||
Multipart.prototype.setHeaders = function (chunked) {
|
||||
var self = this
|
||||
|
||||
if (chunked && !self.request.hasHeader('transfer-encoding')) {
|
||||
self.request.setHeader('transfer-encoding', 'chunked')
|
||||
}
|
||||
|
||||
var header = self.request.getHeader('content-type')
|
||||
|
||||
if (!header || header.indexOf('multipart') === -1) {
|
||||
self.request.setHeader('content-type', 'multipart/related; boundary=' + self.boundary)
|
||||
} else {
|
||||
if (header.indexOf('boundary') !== -1) {
|
||||
self.boundary = header.replace(/.*boundary=([^\s;]+).*/, '$1')
|
||||
} else {
|
||||
self.request.setHeader('content-type', header + '; boundary=' + self.boundary)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Multipart.prototype.build = function (parts, chunked) {
|
||||
var self = this
|
||||
var body = chunked ? new CombinedStream() : []
|
||||
|
||||
function add (part) {
|
||||
if (typeof part === 'number') {
|
||||
part = part.toString()
|
||||
}
|
||||
return chunked ? body.append(part) : body.push(Buffer.from(part))
|
||||
}
|
||||
|
||||
if (self.request.preambleCRLF) {
|
||||
add('\r\n')
|
||||
}
|
||||
|
||||
parts.forEach(function (part) {
|
||||
var preamble = '--' + self.boundary + '\r\n'
|
||||
Object.keys(part).forEach(function (key) {
|
||||
if (key === 'body') { return }
|
||||
preamble += key + ': ' + part[key] + '\r\n'
|
||||
})
|
||||
preamble += '\r\n'
|
||||
add(preamble)
|
||||
add(part.body)
|
||||
add('\r\n')
|
||||
})
|
||||
add('--' + self.boundary + '--')
|
||||
|
||||
if (self.request.postambleCRLF) {
|
||||
add('\r\n')
|
||||
}
|
||||
|
||||
return body
|
||||
}
|
||||
|
||||
Multipart.prototype.onRequest = function (options) {
|
||||
var self = this
|
||||
|
||||
var chunked = self.isChunked(options)
|
||||
var parts = options.data || options
|
||||
|
||||
self.setHeaders(chunked)
|
||||
self.chunked = chunked
|
||||
self.body = self.build(parts, chunked)
|
||||
}
|
||||
|
||||
exports.Multipart = Multipart
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
'use strict'
|
||||
|
||||
var qs = require('qs')
|
||||
var querystring = require('querystring')
|
||||
|
||||
function Querystring (request) {
|
||||
this.request = request
|
||||
this.lib = null
|
||||
this.useQuerystring = null
|
||||
this.parseOptions = null
|
||||
this.stringifyOptions = null
|
||||
}
|
||||
|
||||
Querystring.prototype.init = function (options) {
|
||||
if (this.lib) { return }
|
||||
|
||||
this.useQuerystring = options.useQuerystring
|
||||
this.lib = (this.useQuerystring ? querystring : qs)
|
||||
|
||||
this.parseOptions = options.qsParseOptions || {}
|
||||
this.stringifyOptions = options.qsStringifyOptions || {}
|
||||
}
|
||||
|
||||
Querystring.prototype.stringify = function (obj) {
|
||||
return (this.useQuerystring)
|
||||
? this.rfc3986(this.lib.stringify(obj,
|
||||
this.stringifyOptions.sep || null,
|
||||
this.stringifyOptions.eq || null,
|
||||
this.stringifyOptions))
|
||||
: this.lib.stringify(obj, this.stringifyOptions)
|
||||
}
|
||||
|
||||
Querystring.prototype.parse = function (str) {
|
||||
return (this.useQuerystring)
|
||||
? this.lib.parse(str,
|
||||
this.parseOptions.sep || null,
|
||||
this.parseOptions.eq || null,
|
||||
this.parseOptions)
|
||||
: this.lib.parse(str, this.parseOptions)
|
||||
}
|
||||
|
||||
Querystring.prototype.rfc3986 = function (str) {
|
||||
return str.replace(/[!'()*]/g, function (c) {
|
||||
return '%' + c.charCodeAt(0).toString(16).toUpperCase()
|
||||
})
|
||||
}
|
||||
|
||||
Querystring.prototype.unescape = querystring.unescape
|
||||
|
||||
exports.Querystring = Querystring
|
||||
+179
@@ -0,0 +1,179 @@
|
||||
'use strict'
|
||||
|
||||
var url = require('url')
|
||||
var isUrl = /^https?:/
|
||||
|
||||
function Redirect (request) {
|
||||
this.request = request
|
||||
this.followRedirect = true
|
||||
this.followRedirects = true
|
||||
this.followAllRedirects = false
|
||||
this.followOriginalHttpMethod = false
|
||||
this.allowRedirect = function () { return true }
|
||||
this.maxRedirects = 10
|
||||
this.redirects = []
|
||||
this.redirectsFollowed = 0
|
||||
this.removeRefererHeader = false
|
||||
this.allowInsecureRedirect = false
|
||||
}
|
||||
|
||||
Redirect.prototype.onRequest = function (options) {
|
||||
var self = this
|
||||
|
||||
if (options.maxRedirects !== undefined) {
|
||||
self.maxRedirects = options.maxRedirects
|
||||
}
|
||||
if (typeof options.followRedirect === 'function') {
|
||||
self.allowRedirect = options.followRedirect
|
||||
}
|
||||
if (options.followRedirect !== undefined) {
|
||||
self.followRedirects = !!options.followRedirect
|
||||
}
|
||||
if (options.followAllRedirects !== undefined) {
|
||||
self.followAllRedirects = options.followAllRedirects
|
||||
}
|
||||
if (self.followRedirects || self.followAllRedirects) {
|
||||
self.redirects = self.redirects || []
|
||||
}
|
||||
if (options.removeRefererHeader !== undefined) {
|
||||
self.removeRefererHeader = options.removeRefererHeader
|
||||
}
|
||||
if (options.followOriginalHttpMethod !== undefined) {
|
||||
self.followOriginalHttpMethod = options.followOriginalHttpMethod
|
||||
}
|
||||
if (options.allowInsecureRedirect !== undefined) {
|
||||
self.allowInsecureRedirect = options.allowInsecureRedirect
|
||||
}
|
||||
}
|
||||
|
||||
Redirect.prototype.redirectTo = function (response) {
|
||||
var self = this
|
||||
var request = self.request
|
||||
|
||||
var redirectTo = null
|
||||
if (response.statusCode >= 300 && response.statusCode < 400 && response.caseless.has('location')) {
|
||||
var location = response.caseless.get('location')
|
||||
request.debug('redirect', location)
|
||||
|
||||
if (self.followAllRedirects) {
|
||||
redirectTo = location
|
||||
} else if (self.followRedirects) {
|
||||
switch (request.method) {
|
||||
case 'PATCH':
|
||||
case 'PUT':
|
||||
case 'POST':
|
||||
case 'DELETE':
|
||||
// Do not follow redirects
|
||||
break
|
||||
default:
|
||||
redirectTo = location
|
||||
break
|
||||
}
|
||||
}
|
||||
} else if (response.statusCode === 401) {
|
||||
var authHeader = request._auth.onResponse(response)
|
||||
if (authHeader) {
|
||||
request.setHeader('authorization', authHeader)
|
||||
redirectTo = request.uri
|
||||
}
|
||||
}
|
||||
return redirectTo
|
||||
}
|
||||
|
||||
Redirect.prototype.onResponse = function (response, callback) {
|
||||
var self = this
|
||||
var request = self.request
|
||||
|
||||
var redirectTo = self.redirectTo(response)
|
||||
if (!redirectTo) return callback(null, false)
|
||||
|
||||
function processRedirect (shouldRedirect) {
|
||||
if (!shouldRedirect) return callback(null, false)
|
||||
if (typeof shouldRedirect === 'string') {
|
||||
// overridden redirect url
|
||||
request.debug('redirect overridden', redirectTo)
|
||||
redirectTo = shouldRedirect
|
||||
}
|
||||
|
||||
request.debug('redirect to', redirectTo)
|
||||
|
||||
// ignore any potential response body. it cannot possibly be useful
|
||||
// to us at this point.
|
||||
// response.resume should be defined, but check anyway before calling. Workaround for browserify.
|
||||
if (response.resume) {
|
||||
response.resume()
|
||||
}
|
||||
|
||||
if (self.redirectsFollowed >= self.maxRedirects) {
|
||||
return callback(new Error('Exceeded maxRedirects. Probably stuck in a redirect loop ' + request.uri.href))
|
||||
}
|
||||
self.redirectsFollowed += 1
|
||||
|
||||
if (!isUrl.test(redirectTo)) {
|
||||
redirectTo = url.resolve(request.uri.href, redirectTo)
|
||||
}
|
||||
|
||||
var uriPrev = request.uri
|
||||
request.uri = url.parse(redirectTo)
|
||||
|
||||
// handle the case where we change protocol from https to http or vice versa
|
||||
if (request.uri.protocol !== uriPrev.protocol && self.allowInsecureRedirect) {
|
||||
delete request.agent
|
||||
}
|
||||
|
||||
self.redirects.push({ statusCode: response.statusCode, redirectUri: redirectTo })
|
||||
|
||||
if (self.followAllRedirects && request.method !== 'HEAD' &&
|
||||
response.statusCode !== 401 && response.statusCode !== 307) {
|
||||
request.method = self.followOriginalHttpMethod ? request.method : 'GET'
|
||||
}
|
||||
// request.method = 'GET' // Force all redirects to use GET || commented out fixes #215
|
||||
delete request.src
|
||||
delete request.req
|
||||
delete request._started
|
||||
if (response.statusCode !== 401 && response.statusCode !== 307) {
|
||||
// Remove parameters from the previous response, unless this is the second request
|
||||
// for a server that requires digest authentication.
|
||||
delete request.body
|
||||
delete request._form
|
||||
if (request.headers) {
|
||||
request.removeHeader('host')
|
||||
request.removeHeader('content-type')
|
||||
request.removeHeader('content-length')
|
||||
if (request.uri.hostname !== request.originalHost.split(':')[0]) {
|
||||
// Remove authorization if changing hostnames (but not if just
|
||||
// changing ports or protocols). This matches the behavior of curl:
|
||||
// https://github.com/bagder/curl/blob/6beb0eee/lib/http.c#L710
|
||||
request.removeHeader('authorization')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!self.removeRefererHeader) {
|
||||
request.setHeader('referer', uriPrev.href)
|
||||
}
|
||||
|
||||
request.emit('redirect')
|
||||
request.init()
|
||||
callback(null, true)
|
||||
}
|
||||
|
||||
// test allowRedirect arity; if has more than one argument,
|
||||
// assume it's asynchronous via a callback
|
||||
if (self.allowRedirect.length > 1) {
|
||||
return self.allowRedirect.call(request, response, function (err, result) {
|
||||
if (err) return callback(err)
|
||||
processRedirect(result)
|
||||
})
|
||||
}
|
||||
|
||||
var allowsRedirect = self.allowRedirect.call(request, response)
|
||||
if (allowsRedirect && allowsRedirect.then) {
|
||||
return allowsRedirect.then(processRedirect, callback)
|
||||
}
|
||||
|
||||
// treat as a regular boolean
|
||||
processRedirect(allowsRedirect)
|
||||
}
|
||||
|
||||
exports.Redirect = Redirect
|
||||
+175
@@ -0,0 +1,175 @@
|
||||
'use strict'
|
||||
|
||||
var url = require('url')
|
||||
var tunnel = require('tunnel-agent')
|
||||
|
||||
var defaultProxyHeaderWhiteList = [
|
||||
'accept',
|
||||
'accept-charset',
|
||||
'accept-encoding',
|
||||
'accept-language',
|
||||
'accept-ranges',
|
||||
'cache-control',
|
||||
'content-encoding',
|
||||
'content-language',
|
||||
'content-location',
|
||||
'content-md5',
|
||||
'content-range',
|
||||
'content-type',
|
||||
'connection',
|
||||
'date',
|
||||
'expect',
|
||||
'max-forwards',
|
||||
'pragma',
|
||||
'referer',
|
||||
'te',
|
||||
'user-agent',
|
||||
'via'
|
||||
]
|
||||
|
||||
var defaultProxyHeaderExclusiveList = [
|
||||
'proxy-authorization'
|
||||
]
|
||||
|
||||
function constructProxyHost (uriObject) {
|
||||
var port = uriObject.port
|
||||
var protocol = uriObject.protocol
|
||||
var proxyHost = uriObject.hostname + ':'
|
||||
|
||||
if (port) {
|
||||
proxyHost += port
|
||||
} else if (protocol === 'https:') {
|
||||
proxyHost += '443'
|
||||
} else {
|
||||
proxyHost += '80'
|
||||
}
|
||||
|
||||
return proxyHost
|
||||
}
|
||||
|
||||
function constructProxyHeaderWhiteList (headers, proxyHeaderWhiteList) {
|
||||
var whiteList = proxyHeaderWhiteList
|
||||
.reduce(function (set, header) {
|
||||
set[header.toLowerCase()] = true
|
||||
return set
|
||||
}, {})
|
||||
|
||||
return Object.keys(headers)
|
||||
.filter(function (header) {
|
||||
return whiteList[header.toLowerCase()]
|
||||
})
|
||||
.reduce(function (set, header) {
|
||||
set[header] = headers[header]
|
||||
return set
|
||||
}, {})
|
||||
}
|
||||
|
||||
function constructTunnelOptions (request, proxyHeaders) {
|
||||
var proxy = request.proxy
|
||||
|
||||
var tunnelOptions = {
|
||||
proxy: {
|
||||
host: proxy.hostname,
|
||||
port: +proxy.port,
|
||||
proxyAuth: proxy.auth,
|
||||
headers: proxyHeaders
|
||||
},
|
||||
headers: request.headers,
|
||||
ca: request.ca,
|
||||
cert: request.cert,
|
||||
key: request.key,
|
||||
passphrase: request.passphrase,
|
||||
pfx: request.pfx,
|
||||
ciphers: request.ciphers,
|
||||
rejectUnauthorized: request.rejectUnauthorized,
|
||||
secureOptions: request.secureOptions,
|
||||
secureProtocol: request.secureProtocol
|
||||
}
|
||||
|
||||
return tunnelOptions
|
||||
}
|
||||
|
||||
function constructTunnelFnName (uri, proxy) {
|
||||
var uriProtocol = (uri.protocol === 'https:' ? 'https' : 'http')
|
||||
var proxyProtocol = (proxy.protocol === 'https:' ? 'Https' : 'Http')
|
||||
return [uriProtocol, proxyProtocol].join('Over')
|
||||
}
|
||||
|
||||
function getTunnelFn (request) {
|
||||
var uri = request.uri
|
||||
var proxy = request.proxy
|
||||
var tunnelFnName = constructTunnelFnName(uri, proxy)
|
||||
return tunnel[tunnelFnName]
|
||||
}
|
||||
|
||||
function Tunnel (request) {
|
||||
this.request = request
|
||||
this.proxyHeaderWhiteList = defaultProxyHeaderWhiteList
|
||||
this.proxyHeaderExclusiveList = []
|
||||
if (typeof request.tunnel !== 'undefined') {
|
||||
this.tunnelOverride = request.tunnel
|
||||
}
|
||||
}
|
||||
|
||||
Tunnel.prototype.isEnabled = function () {
|
||||
var self = this
|
||||
var request = self.request
|
||||
// Tunnel HTTPS by default. Allow the user to override this setting.
|
||||
|
||||
// If self.tunnelOverride is set (the user specified a value), use it.
|
||||
if (typeof self.tunnelOverride !== 'undefined') {
|
||||
return self.tunnelOverride
|
||||
}
|
||||
|
||||
// If the destination is HTTPS, tunnel.
|
||||
if (request.uri.protocol === 'https:') {
|
||||
return true
|
||||
}
|
||||
|
||||
// Otherwise, do not use tunnel.
|
||||
return false
|
||||
}
|
||||
|
||||
Tunnel.prototype.setup = function (options) {
|
||||
var self = this
|
||||
var request = self.request
|
||||
|
||||
options = options || {}
|
||||
|
||||
if (typeof request.proxy === 'string') {
|
||||
request.proxy = url.parse(request.proxy)
|
||||
}
|
||||
|
||||
if (!request.proxy || !request.tunnel) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Setup Proxy Header Exclusive List and White List
|
||||
if (options.proxyHeaderWhiteList) {
|
||||
self.proxyHeaderWhiteList = options.proxyHeaderWhiteList
|
||||
}
|
||||
if (options.proxyHeaderExclusiveList) {
|
||||
self.proxyHeaderExclusiveList = options.proxyHeaderExclusiveList
|
||||
}
|
||||
|
||||
var proxyHeaderExclusiveList = self.proxyHeaderExclusiveList.concat(defaultProxyHeaderExclusiveList)
|
||||
var proxyHeaderWhiteList = self.proxyHeaderWhiteList.concat(proxyHeaderExclusiveList)
|
||||
|
||||
// Setup Proxy Headers and Proxy Headers Host
|
||||
// Only send the Proxy White Listed Header names
|
||||
var proxyHeaders = constructProxyHeaderWhiteList(request.headers, proxyHeaderWhiteList)
|
||||
proxyHeaders.host = constructProxyHost(request.uri)
|
||||
|
||||
proxyHeaderExclusiveList.forEach(request.removeHeader, request)
|
||||
|
||||
// Set Agent from Tunnel Data
|
||||
var tunnelFn = getTunnelFn(request)
|
||||
var tunnelOptions = constructTunnelOptions(request, proxyHeaders)
|
||||
request.agent = tunnelFn(tunnelOptions)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
Tunnel.defaultProxyHeaderWhiteList = defaultProxyHeaderWhiteList
|
||||
Tunnel.defaultProxyHeaderExclusiveList = defaultProxyHeaderExclusiveList
|
||||
exports.Tunnel = Tunnel
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
{
|
||||
"name": "@cypress/request",
|
||||
"description": "Cypress's fork of a simplified HTTP request client.",
|
||||
"keywords": [
|
||||
"http",
|
||||
"simple",
|
||||
"util",
|
||||
"utility"
|
||||
],
|
||||
"version": "3.0.6",
|
||||
"author": "Mikeal Rogers <mikeal.rogers@gmail.com>",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/cypress-io/request.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "http://github.com/cypress-io/request/issues"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
},
|
||||
"main": "index.js",
|
||||
"files": [
|
||||
"lib/",
|
||||
"index.js",
|
||||
"request.js"
|
||||
],
|
||||
"dependencies": {
|
||||
"aws-sign2": "~0.7.0",
|
||||
"aws4": "^1.8.0",
|
||||
"caseless": "~0.12.0",
|
||||
"combined-stream": "~1.0.6",
|
||||
"extend": "~3.0.2",
|
||||
"forever-agent": "~0.6.1",
|
||||
"form-data": "~4.0.0",
|
||||
"http-signature": "~1.4.0",
|
||||
"is-typedarray": "~1.0.0",
|
||||
"isstream": "~0.1.2",
|
||||
"json-stringify-safe": "~5.0.1",
|
||||
"mime-types": "~2.1.19",
|
||||
"performance-now": "^2.1.0",
|
||||
"qs": "6.13.0",
|
||||
"safe-buffer": "^5.1.2",
|
||||
"tough-cookie": "^5.0.0",
|
||||
"tunnel-agent": "^0.6.0",
|
||||
"uuid": "^8.3.2"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "npm run lint && npm run test-ci && npm run test-browser",
|
||||
"test-ci": "tap --no-check-coverage tests/test-*.js",
|
||||
"test-cov": "nyc --reporter=lcov tape tests/test-*.js",
|
||||
"test-browser": "echo 'Skipping browser tests.' || node tests/browser/start.js",
|
||||
"lint": "standard"
|
||||
},
|
||||
"devDependencies": {
|
||||
"bluebird": "^3.2.1",
|
||||
"browserify": "^13.0.1",
|
||||
"browserify-istanbul": "^2.0.0",
|
||||
"buffer-equal": "^1.0.0",
|
||||
"codecov": "^3.0.4",
|
||||
"coveralls": "^3.0.2",
|
||||
"function-bind": "^1.0.2",
|
||||
"karma": "^3.0.0",
|
||||
"karma-browserify": "^5.0.1",
|
||||
"karma-cli": "^2.0.0",
|
||||
"karma-coverage": "^2.0.3",
|
||||
"karma-phantomjs-launcher": "^1.0.0",
|
||||
"karma-tap": "^4.2.0",
|
||||
"nyc": "^17.0.0",
|
||||
"phantomjs-prebuilt": "^2.1.3",
|
||||
"rimraf": "^2.2.8",
|
||||
"server-destroy": "^1.0.1",
|
||||
"standard": "^9.0.0",
|
||||
"tap": "^15.1.5",
|
||||
"tape": "^4.6.0"
|
||||
},
|
||||
"greenkeeper": {
|
||||
"ignore": [
|
||||
"hawk",
|
||||
"har-validator"
|
||||
]
|
||||
}
|
||||
}
|
||||
+1548
File diff suppressed because it is too large.
Load diff
+20
@@ -0,0 +1,20 @@
|
||||
var Ajv = require('ajv');
|
||||
var ajv = new Ajv({allErrors: true});
|
||||
|
||||
var schema = {
|
||||
"properties": {
|
||||
"foo": { "type": "string" },
|
||||
"bar": { "type": "number", "maximum": 3 }
|
||||
}
|
||||
};
|
||||
|
||||
var validate = ajv.compile(schema);
|
||||
|
||||
test({"foo": "abc", "bar": 2});
|
||||
test({"foo": 2, "bar": 4});
|
||||
|
||||
function test(data) {
|
||||
var valid = validate(data);
|
||||
if (valid) console.log('Valid!');
|
||||
else console.log('Invalid: ' + ajv.errorsText(validate.errors));
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015-2017 Evgeny Poberezkin
|
||||
|
||||
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.
|
||||
|
||||
+1497
File diff suppressed because it is too large.
Load diff
+7189
File diff suppressed because it is too large.
Load diff
+3
@@ -0,0 +1,3 @@
|
||||
/* ajv 6.12.6: Another JSON Schema Validator */
|
||||
!function(e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).Ajv=e()}(function(){return function o(i,n,l){function c(r,e){if(!n[r]){if(!i[r]){var t="function"==typeof require&&require;if(!e&&t)return t(r,!0);if(u)return u(r,!0);var a=new Error("Cannot find module '"+r+"'");throw a.code="MODULE_NOT_FOUND",a}var s=n[r]={exports:{}};i[r][0].call(s.exports,function(e){return c(i[r][1][e]||e)},s,s.exports,o,i,n,l)}return n[r].exports}for(var u="function"==typeof require&&require,e=0;e<l.length;e++)c(l[e]);return c}({1:[function(e,r,t){"use strict";var a=r.exports=function(){this._cache={}};a.prototype.put=function(e,r){this._cache[e]=r},a.prototype.get=function(e){return this._cache[e]},a.prototype.del=function(e){delete this._cache[e]},a.prototype.clear=function(){this._cache={}}},{}],2:[function(e,r,t){"use strict";var a=e("./error_classes").MissingRef;function s(r,n,t){var l=this;if("function"!=typeof this._opts.loadSchema)throw new Error("options.loadSchema should be a function");"function"==typeof n&&(t=n,n=void 0);var e=c(r).then(function(){var e=l._addSchema(r,void 0,n);return e.validate||function o(i){try{return l._compile(i)}catch(e){if(e instanceof a)return r(e);throw e}function r(e){var r=e.missingSchema;if(s(r))throw new Error("Schema "+r+" is loaded but "+e.missingRef+" cannot be resolved");var t=l._loadingSchemas[r];return t||(t=l._loadingSchemas[r]=l._opts.loadSchema(r)).then(a,a),t.then(function(e){if(!s(r))return c(e).then(function(){s(r)||l.addSchema(e,r,void 0,n)})}).then(function(){return o(i)});function a(){delete l._loadingSchemas[r]}function s(e){return l._refs[e]||l._schemas[e]}}}(e)});return t&&e.then(function(e){t(null,e)},t),e;function c(e){var r=e.$schema;return r&&!l.getSchema(r)?s.call(l,{$ref:r},!0):Promise.resolve()}}r.exports=s},{"./error_classes":3}],3:[function(e,r,t){"use strict";var a=e("./resolve");function s(e,r,t){this.message=t||s.message(e,r),this.missingRef=a.url(e,r),this.missingSchema=a.normalizeId(a.fullPath(this.missingRef))}function o(e){return e.prototype=Object.create(Error.prototype),e.prototype.constructor=e}r.exports={Validation:o(function(e){this.message="validation failed",this.errors=e,this.ajv=this.validation=!0}),MissingRef:o(s)},s.message=function(e,r){return"can't resolve reference "+r+" from id "+e}},{"./resolve":6}],4:[function(e,r,t){"use strict";var a=e("./util"),o=/^(\d\d\d\d)-(\d\d)-(\d\d)$/,i=[0,31,28,31,30,31,30,31,31,30,31,30,31],n=/^(\d\d):(\d\d):(\d\d)(\.\d+)?(z|[+-]\d\d(?::?\d\d)?)?$/i,s=/^(?=.{1,253}\.?$)[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[-0-9a-z]{0,61}[0-9a-z])?)*\.?$/i,l=/^(?:[a-z][a-z0-9+\-.]*:)(?:\/?\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|[Vv][0-9a-f]+\.[a-z0-9\-._~!$&'()*+,;=:]+)\]|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)|(?:[a-z0-9\-._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\d*)?(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?|(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)(?:\?(?:[a-z0-9\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$/i,c=/^(?:(?:[^\x00-\x20"'<>%\\^`{|}]|%[0-9a-f]{2})|\{[+#./;?&=,!@|]?(?:[a-z0-9_]|%[0-9a-f]{2})+(?::[1-9][0-9]{0,3}|\*)?(?:,(?:[a-z0-9_]|%[0-9a-f]{2})+(?::[1-9][0-9]{0,3}|\*)?)*\})*$/i,u=/^(?:(?:http[s\u017F]?|ftp):\/\/)(?:(?:[\0-\x08\x0E-\x1F!-\x9F\xA1-\u167F\u1681-\u1FFF\u200B-\u2027\u202A-\u202E\u2030-\u205E\u2060-\u2FFF\u3001-\uD7FF\uE000-\uFEFE\uFF00-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])+(?::(?:[\0-\x08\x0E-\x1F!-\x9F\xA1-\u167F\u1681-\u1FFF\u200B-\u2027\u202A-\u202E\u2030-\u205E\u2060-\u2FFF\u3001-\uD7FF\uE000-\uFEFE\uFF00-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])*)?@)?(?:(?!10(?:\.[0-9]{1,3}){3})(?!127(?:\.[0-9]{1,3}){3})(?!169\.254(?:\.[0-9]{1,3}){2})(?!192\.168(?:\.[0-9]{1,3}){2})(?!172\.(?:1[6-9]|2[0-9]|3[01])(?:\.[0-9]{1,3}){2})(?:[1-9][0-9]?|1[0-9][0-9]|2[01][0-9]|22[0-3])(?:\.(?:1?[0-9]{1,2}|2[0-4][0-9]|25[0-5])){2}(?:\.(?:[1-9][0-9]?|1[0-9][0-9]|2[0-4][0-9]|25[0-4]))|(?:(?:(?:[0-9a-z\xA1-\uD7FFLine truncated
|
||||
//# sourceMappingURL=ajv.min.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"ajv.min.js","sources":["0"],"names":["f","exports","module","define","amd","window","global","self","this","Ajv","r","e","n","t","o","i","c","require","u","a","Error","code","p","call","length","1","Cache","_cache","prototype","put","key","value","get","del","clear","2","MissingRefError","MissingRef","compileAsync","schema","meta","callback","_opts","loadSchema","undefined","loadMetaSchemaOf","then","schemaObj","_addSchema","validate","_compileAsync","_compile","loadMissingSchema","ref","missingSchema","added","missingRef","schemaPromise","_loadingSchemas","removePromise","sch","addSchema","_refs","_schemas","v","$schema","getSchema","$ref","Promise","resolve","./error_classes","3","baseId","message","url","normalizeId","fullPath","errorSubclass","Subclass","Object","create","constructor","Validation","errors","ajv","validation","./resolve","4","util","DATE","DAYS","TIME","HOSTNAME","URI","URITEMPLATE","URL","UUID","JSON_POINTER","JSON_POINTER_URI_FRAGMENT","RELATIVE_JSON_POINTER","formats","mode","copy","date","str","matches","match","year","month","day","time","full","hour","minute","second","fast","date-time","uri","uri-reference","uri-template","email","hostname","ipv4","ipv6","regex","uuid","json-pointer","json-pointer-uri-fragment","relative-json-pointer","dateTime","split","DATE_TIME_SEPARATOR","NOT_URI_FRAGMENT","test","Z_ANCHOR","RegExp","./util","5","errorClasses","stableStringify","validateGenerator","ucs2length","equal","ValidationError","compile","root","localRefs","opts","refVal","refs","patterns","patternsHash","defaults","defaultsHash","customRules","index","compIndex","compiling","_compilations","compilation","callValidate","_formats","RULES","localCompile","cv","$async","sourceCode","source","splice","result","apply","arguments","_schema","_root","isRoot","isTop","schemaPath","errSchemaPath","errorPath","resolveRef","usePattern","useDefault","useCustomRule","logger","vars","refValCode","patternCode","defaultCode","customRuleCode","processCode","Function","makeValidate","error","_refVal","refCode","refIndex","resolvedRef","rootRefId","addLocalRef","localSchema","inlineRef","inlineRefs","refId","inline","regexStr","toQuotedString","valueStr","rule","parentSchema","it","validateSchema","deps","definition","dependencies","every","keyword","hasOwnProperty","join","errorsText","macro","arr","statement","../dotjs/validate","fast-deep-equal","fast-json-stable-stringify","6","SchemaObject","traverse","res","resolveSchema","parse","refPath","_getFullPath","getFullPath","_getId","keys","id","parsedRef","resolveUrl","getJsonPointer","ids","schemaId","baseIds","","fullPaths","allKeys","jsonPtr","rootSchema","parentJsonPtr","parentKeyword","keyIndex","escapeFragment","PREVENT_SCOPE_CHANGE","toHash","fragment","slice","parts","part","unescapeFragment","SIMPLE_INLINED","limit","checkNoRef","item","Array","isArray","countKeys","count","Infinity","normalize","serialize","TRAILING_SLASH_HASH","replace","./schema_obj","json-schema-traverse","uri-js","7","ruleModules","type","rules","maximum","minimum","properties","ALL","all","types","forEach","group","map","implKeywords","k","push","implements","$comment","keywords","concat","custom","../dotjs","8","obj","9","len","pos","charCodeAt","10","checkDataType","dataType","data","strictNumbers","negate","EQUAL","AND","OK","NOT","to","checkDataTypes","dataTypes","array","object","null","number","integer","coerceToTypes","optionCoerceTypes","COERCE_TO_TYPES","getProperty","escapeQuotes","varOccurences","dataVar","varReplace","expr","schemaHasRules","schemaHasRulesExcept","exceptKeyword","schemaUnknownRules","getPathExpr","currentPath","jsonPointers","isNumber","joinPaths","getPath","prop","path","escapeJsonPointer","getData","$data","lvl","paths","up","jsonPointer","segments","segment","unescapeJsonPointer","decodeURIComponent","encodeURIComponent","hash","IDENTIFIER","SINGLE_QUOTE","b","./ucs2length","11","KEYWORDS","metaSchema","keywordsJsonPointers","JSON","stringify","j","anyOf","12","$id","definitions","simpleTypes","statements","valid","not","required","items","modifying","async","const","./refs/json-schema-draft-07.json","13","$keyword","$schemaValueExcl","$exclusive","$exclType","$exclIsNumber","$opStr","$opExpr","$$outStack","out","$lvl","level","$dataLvl","dataLevel","$schemaPath","$errSchemaPath","$breakOnError","allErrors","$isData","$schemaValue","dataPathArr","$isMax","$exclusiveKeyword","$schemaExcl","$isDataExcl","$op","$notOp","$errorKeyword","createErrors","messages","verbose","__err","pop","compositeRule","Math","14","15","unicode","16","17","$it","$closingBraces","$nextValid","$currentBaseId","$allSchemasEmpty","arr1","$sch","$i","l1","strictKeywords","18","$valid","$errs","$wasComposite","19","20","21","$passData","$code","$idx","$dataNxt","$nextData","$nonEmptySchema","22","$compile","$inline","$macro","$ruleValidate","$validateCode","$rule","$definition","$rDef","$validateSchema","$parentData","$parentDataProperty","def_calLine truncated
|
||||
+397
@@ -0,0 +1,397 @@
|
||||
declare var ajv: {
|
||||
(options?: ajv.Options): ajv.Ajv;
|
||||
new(options?: ajv.Options): ajv.Ajv;
|
||||
ValidationError: typeof AjvErrors.ValidationError;
|
||||
MissingRefError: typeof AjvErrors.MissingRefError;
|
||||
$dataMetaSchema: object;
|
||||
}
|
||||
|
||||
declare namespace AjvErrors {
|
||||
class ValidationError extends Error {
|
||||
constructor(errors: Array<ajv.ErrorObject>);
|
||||
|
||||
message: string;
|
||||
errors: Array<ajv.ErrorObject>;
|
||||
ajv: true;
|
||||
validation: true;
|
||||
}
|
||||
|
||||
class MissingRefError extends Error {
|
||||
constructor(baseId: string, ref: string, message?: string);
|
||||
static message: (baseId: string, ref: string) => string;
|
||||
|
||||
message: string;
|
||||
missingRef: string;
|
||||
missingSchema: string;
|
||||
}
|
||||
}
|
||||
|
||||
declare namespace ajv {
|
||||
type ValidationError = AjvErrors.ValidationError;
|
||||
|
||||
type MissingRefError = AjvErrors.MissingRefError;
|
||||
|
||||
interface Ajv {
|
||||
/**
|
||||
* Validate data using schema
|
||||
* Schema will be compiled and cached (using serialized JSON as key, [fast-json-stable-stringify](https://github.com/epoberezkin/fast-json-stable-stringify) is used to serialize by default).
|
||||
* @param {string|object|Boolean} schemaKeyRef key, ref or schema object
|
||||
* @param {Any} data to be validated
|
||||
* @return {Boolean} validation result. Errors from the last validation will be available in `ajv.errors` (and also in compiled schema: `schema.errors`).
|
||||
*/
|
||||
validate(schemaKeyRef: object | string | boolean, data: any): boolean | PromiseLike<any>;
|
||||
/**
|
||||
* Create validating function for passed schema.
|
||||
* @param {object|Boolean} schema schema object
|
||||
* @return {Function} validating function
|
||||
*/
|
||||
compile(schema: object | boolean): ValidateFunction;
|
||||
/**
|
||||
* Creates validating function for passed schema with asynchronous loading of missing schemas.
|
||||
* `loadSchema` option should be a function that accepts schema uri and node-style callback.
|
||||
* @this Ajv
|
||||
* @param {object|Boolean} schema schema object
|
||||
* @param {Boolean} meta optional true to compile meta-schema; this parameter can be skipped
|
||||
* @param {Function} callback optional node-style callback, it is always called with 2 parameters: error (or null) and validating function.
|
||||
* @return {PromiseLike<ValidateFunction>} validating function
|
||||
*/
|
||||
compileAsync(schema: object | boolean, meta?: Boolean, callback?: (err: Error, validate: ValidateFunction) => any): PromiseLike<ValidateFunction>;
|
||||
/**
|
||||
* Adds schema to the instance.
|
||||
* @param {object|Array} schema schema or array of schemas. If array is passed, `key` and other parameters will be ignored.
|
||||
* @param {string} key Optional schema key. Can be passed to `validate` method instead of schema object or id/ref. One schema per instance can have empty `id` and `key`.
|
||||
* @return {Ajv} this for method chaining
|
||||
*/
|
||||
addSchema(schema: Array<object> | object, key?: string): Ajv;
|
||||
/**
|
||||
* Add schema that will be used to validate other schemas
|
||||
* options in META_IGNORE_OPTIONS are alway set to false
|
||||
* @param {object} schema schema object
|
||||
* @param {string} key optional schema key
|
||||
* @return {Ajv} this for method chaining
|
||||
*/
|
||||
addMetaSchema(schema: object, key?: string): Ajv;
|
||||
/**
|
||||
* Validate schema
|
||||
* @param {object|Boolean} schema schema to validate
|
||||
* @return {Boolean} true if schema is valid
|
||||
*/
|
||||
validateSchema(schema: object | boolean): boolean;
|
||||
/**
|
||||
* Get compiled schema from the instance by `key` or `ref`.
|
||||
* @param {string} keyRef `key` that was passed to `addSchema` or full schema reference (`schema.id` or resolved id).
|
||||
* @return {Function} schema validating function (with property `schema`). Returns undefined if keyRef can't be resolved to an existing schema.
|
||||
*/
|
||||
getSchema(keyRef: string): ValidateFunction | undefined;
|
||||
/**
|
||||
* Remove cached schema(s).
|
||||
* If no parameter is passed all schemas but meta-schemas are removed.
|
||||
* If RegExp is passed all schemas with key/id matching pattern but meta-schemas are removed.
|
||||
* Even if schema is referenced by other schemas it still can be removed as other schemas have local references.
|
||||
* @param {string|object|RegExp|Boolean} schemaKeyRef key, ref, pattern to match key/ref or schema object
|
||||
* @return {Ajv} this for method chaining
|
||||
*/
|
||||
removeSchema(schemaKeyRef?: object | string | RegExp | boolean): Ajv;
|
||||
/**
|
||||
* Add custom format
|
||||
* @param {string} name format name
|
||||
* @param {string|RegExp|Function} format string is converted to RegExp; function should return boolean (true when valid)
|
||||
* @return {Ajv} this for method chaining
|
||||
*/
|
||||
addFormat(name: string, format: FormatValidator | FormatDefinition): Ajv;
|
||||
/**
|
||||
* Define custom keyword
|
||||
* @this Ajv
|
||||
* @param {string} keyword custom keyword, should be a valid identifier, should be different from all standard, custom and macro keywords.
|
||||
* @param {object} definition keyword definition object with properties `type` (type(s) which the keyword applies to), `validate` or `compile`.
|
||||
* @return {Ajv} this for method chaining
|
||||
*/
|
||||
addKeyword(keyword: string, definition: KeywordDefinition): Ajv;
|
||||
/**
|
||||
* Get keyword definition
|
||||
* @this Ajv
|
||||
* @param {string} keyword pre-defined or custom keyword.
|
||||
* @return {object|Boolean} custom keyword definition, `true` if it is a predefined keyword, `false` otherwise.
|
||||
*/
|
||||
getKeyword(keyword: string): object | boolean;
|
||||
/**
|
||||
* Remove keyword
|
||||
* @this Ajv
|
||||
* @param {string} keyword pre-defined or custom keyword.
|
||||
* @return {Ajv} this for method chaining
|
||||
*/
|
||||
removeKeyword(keyword: string): Ajv;
|
||||
/**
|
||||
* Validate keyword
|
||||
* @this Ajv
|
||||
* @param {object} definition keyword definition object
|
||||
* @param {boolean} throwError true to throw exception if definition is invalid
|
||||
* @return {boolean} validation result
|
||||
*/
|
||||
validateKeyword(definition: KeywordDefinition, throwError: boolean): boolean;
|
||||
/**
|
||||
* Convert array of error message objects to string
|
||||
* @param {Array<object>} errors optional array of validation errors, if not passed errors from the instance are used.
|
||||
* @param {object} options optional options with properties `separator` and `dataVar`.
|
||||
* @return {string} human readable string with all errors descriptions
|
||||
*/
|
||||
errorsText(errors?: Array<ErrorObject> | null, options?: ErrorsTextOptions): string;
|
||||
errors?: Array<ErrorObject> | null;
|
||||
_opts: Options;
|
||||
}
|
||||
|
||||
interface CustomLogger {
|
||||
log(...args: any[]): any;
|
||||
warn(...args: any[]): any;
|
||||
error(...args: any[]): any;
|
||||
}
|
||||
|
||||
interface ValidateFunction {
|
||||
(
|
||||
data: any,
|
||||
dataPath?: string,
|
||||
parentData?: object | Array<any>,
|
||||
parentDataProperty?: string | number,
|
||||
rootData?: object | Array<any>
|
||||
): boolean | PromiseLike<any>;
|
||||
schema?: object | boolean;
|
||||
errors?: null | Array<ErrorObject>;
|
||||
refs?: object;
|
||||
refVal?: Array<any>;
|
||||
root?: ValidateFunction | object;
|
||||
$async?: true;
|
||||
source?: object;
|
||||
}
|
||||
|
||||
interface Options {
|
||||
$data?: boolean;
|
||||
allErrors?: boolean;
|
||||
verbose?: boolean;
|
||||
jsonPointers?: boolean;
|
||||
uniqueItems?: boolean;
|
||||
unicode?: boolean;
|
||||
format?: false | string;
|
||||
formats?: object;
|
||||
keywords?: object;
|
||||
unknownFormats?: true | string[] | 'ignore';
|
||||
schemas?: Array<object> | object;
|
||||
schemaId?: '$id' | 'id' | 'auto';
|
||||
missingRefs?: true | 'ignore' | 'fail';
|
||||
extendRefs?: true | 'ignore' | 'fail';
|
||||
loadSchema?: (uri: string, cb?: (err: Error, schema: object) => void) => PromiseLike<object | boolean>;
|
||||
removeAdditional?: boolean | 'all' | 'failing';
|
||||
useDefaults?: boolean | 'empty' | 'shared';
|
||||
coerceTypes?: boolean | 'array';
|
||||
strictDefaults?: boolean | 'log';
|
||||
strictKeywords?: boolean | 'log';
|
||||
strictNumbers?: boolean;
|
||||
async?: boolean | string;
|
||||
transpile?: string | ((code: string) => string);
|
||||
meta?: boolean | object;
|
||||
validateSchema?: boolean | 'log';
|
||||
addUsedSchema?: boolean;
|
||||
inlineRefs?: boolean | number;
|
||||
passContext?: boolean;
|
||||
loopRequired?: number;
|
||||
ownProperties?: boolean;
|
||||
multipleOfPrecision?: boolean | number;
|
||||
errorDataPath?: string,
|
||||
messages?: boolean;
|
||||
sourceCode?: boolean;
|
||||
processCode?: (code: string, schema: object) => string;
|
||||
cache?: object;
|
||||
logger?: CustomLogger | false;
|
||||
nullable?: boolean;
|
||||
serialize?: ((schema: object | boolean) => any) | false;
|
||||
}
|
||||
|
||||
type FormatValidator = string | RegExp | ((data: string) => boolean | PromiseLike<any>);
|
||||
type NumberFormatValidator = ((data: number) => boolean | PromiseLike<any>);
|
||||
|
||||
interface NumberFormatDefinition {
|
||||
type: "number",
|
||||
validate: NumberFormatValidator;
|
||||
compare?: (data1: number, data2: number) => number;
|
||||
async?: boolean;
|
||||
}
|
||||
|
||||
interface StringFormatDefinition {
|
||||
type?: "string",
|
||||
validate: FormatValidator;
|
||||
compare?: (data1: string, data2: string) => number;
|
||||
async?: boolean;
|
||||
}
|
||||
|
||||
type FormatDefinition = NumberFormatDefinition | StringFormatDefinition;
|
||||
|
||||
interface KeywordDefinition {
|
||||
type?: string | Array<string>;
|
||||
async?: boolean;
|
||||
$data?: boolean;
|
||||
errors?: boolean | string;
|
||||
metaSchema?: object;
|
||||
// schema: false makes validate not to expect schema (ValidateFunction)
|
||||
schema?: boolean;
|
||||
statements?: boolean;
|
||||
dependencies?: Array<string>;
|
||||
modifying?: boolean;
|
||||
valid?: boolean;
|
||||
// one and only one of the following properties should be present
|
||||
validate?: SchemaValidateFunction | ValidateFunction;
|
||||
compile?: (schema: any, parentSchema: object, it: CompilationContext) => ValidateFunction;
|
||||
macro?: (schema: any, parentSchema: object, it: CompilationContext) => object | boolean;
|
||||
inline?: (it: CompilationContext, keyword: string, schema: any, parentSchema: object) => string;
|
||||
}
|
||||
|
||||
interface CompilationContext {
|
||||
level: number;
|
||||
dataLevel: number;
|
||||
dataPathArr: string[];
|
||||
schema: any;
|
||||
schemaPath: string;
|
||||
baseId: string;
|
||||
async: boolean;
|
||||
opts: Options;
|
||||
formats: {
|
||||
[index: string]: FormatDefinition | undefined;
|
||||
};
|
||||
keywords: {
|
||||
[index: string]: KeywordDefinition | undefined;
|
||||
};
|
||||
compositeRule: boolean;
|
||||
validate: (schema: object) => boolean;
|
||||
util: {
|
||||
copy(obj: any, target?: any): any;
|
||||
toHash(source: string[]): { [index: string]: true | undefined };
|
||||
equal(obj: any, target: any): boolean;
|
||||
getProperty(str: string): string;
|
||||
schemaHasRules(schema: object, rules: any): string;
|
||||
escapeQuotes(str: string): string;
|
||||
toQuotedString(str: string): string;
|
||||
getData(jsonPointer: string, dataLevel: number, paths: string[]): string;
|
||||
escapeJsonPointer(str: string): string;
|
||||
unescapeJsonPointer(str: string): string;
|
||||
escapeFragment(str: string): string;
|
||||
unescapeFragment(str: string): string;
|
||||
};
|
||||
self: Ajv;
|
||||
}
|
||||
|
||||
interface SchemaValidateFunction {
|
||||
(
|
||||
schema: any,
|
||||
data: any,
|
||||
parentSchema?: object,
|
||||
dataPath?: string,
|
||||
parentData?: object | Array<any>,
|
||||
parentDataProperty?: string | number,
|
||||
rootData?: object | Array<any>
|
||||
): boolean | PromiseLike<any>;
|
||||
errors?: Array<ErrorObject>;
|
||||
}
|
||||
|
||||
interface ErrorsTextOptions {
|
||||
separator?: string;
|
||||
dataVar?: string;
|
||||
}
|
||||
|
||||
interface ErrorObject {
|
||||
keyword: string;
|
||||
dataPath: string;
|
||||
schemaPath: string;
|
||||
params: ErrorParameters;
|
||||
// Added to validation errors of propertyNames keyword schema
|
||||
propertyName?: string;
|
||||
// Excluded if messages set to false.
|
||||
message?: string;
|
||||
// These are added with the `verbose` option.
|
||||
schema?: any;
|
||||
parentSchema?: object;
|
||||
data?: any;
|
||||
}
|
||||
|
||||
type ErrorParameters = RefParams | LimitParams | AdditionalPropertiesParams |
|
||||
DependenciesParams | FormatParams | ComparisonParams |
|
||||
MultipleOfParams | PatternParams | RequiredParams |
|
||||
TypeParams | UniqueItemsParams | CustomParams |
|
||||
PatternRequiredParams | PropertyNamesParams |
|
||||
IfParams | SwitchParams | NoParams | EnumParams;
|
||||
|
||||
interface RefParams {
|
||||
ref: string;
|
||||
}
|
||||
|
||||
interface LimitParams {
|
||||
limit: number;
|
||||
}
|
||||
|
||||
interface AdditionalPropertiesParams {
|
||||
additionalProperty: string;
|
||||
}
|
||||
|
||||
interface DependenciesParams {
|
||||
property: string;
|
||||
missingProperty: string;
|
||||
depsCount: number;
|
||||
deps: string;
|
||||
}
|
||||
|
||||
interface FormatParams {
|
||||
format: string
|
||||
}
|
||||
|
||||
interface ComparisonParams {
|
||||
comparison: string;
|
||||
limit: number | string;
|
||||
exclusive: boolean;
|
||||
}
|
||||
|
||||
interface MultipleOfParams {
|
||||
multipleOf: number;
|
||||
}
|
||||
|
||||
interface PatternParams {
|
||||
pattern: string;
|
||||
}
|
||||
|
||||
interface RequiredParams {
|
||||
missingProperty: string;
|
||||
}
|
||||
|
||||
interface TypeParams {
|
||||
type: string;
|
||||
}
|
||||
|
||||
interface UniqueItemsParams {
|
||||
i: number;
|
||||
j: number;
|
||||
}
|
||||
|
||||
interface CustomParams {
|
||||
keyword: string;
|
||||
}
|
||||
|
||||
interface PatternRequiredParams {
|
||||
missingPattern: string;
|
||||
}
|
||||
|
||||
interface PropertyNamesParams {
|
||||
propertyName: string;
|
||||
}
|
||||
|
||||
interface IfParams {
|
||||
failingKeyword: string;
|
||||
}
|
||||
|
||||
interface SwitchParams {
|
||||
caseIndex: number;
|
||||
}
|
||||
|
||||
interface NoParams { }
|
||||
|
||||
interface EnumParams {
|
||||
allowedValues: Array<any>;
|
||||
}
|
||||
}
|
||||
|
||||
export = ajv;
|
||||
+506
@@ -0,0 +1,506 @@
|
||||
'use strict';
|
||||
|
||||
var compileSchema = require('./compile')
|
||||
, resolve = require('./compile/resolve')
|
||||
, Cache = require('./cache')
|
||||
, SchemaObject = require('./compile/schema_obj')
|
||||
, stableStringify = require('fast-json-stable-stringify')
|
||||
, formats = require('./compile/formats')
|
||||
, rules = require('./compile/rules')
|
||||
, $dataMetaSchema = require('./data')
|
||||
, util = require('./compile/util');
|
||||
|
||||
module.exports = Ajv;
|
||||
|
||||
Ajv.prototype.validate = validate;
|
||||
Ajv.prototype.compile = compile;
|
||||
Ajv.prototype.addSchema = addSchema;
|
||||
Ajv.prototype.addMetaSchema = addMetaSchema;
|
||||
Ajv.prototype.validateSchema = validateSchema;
|
||||
Ajv.prototype.getSchema = getSchema;
|
||||
Ajv.prototype.removeSchema = removeSchema;
|
||||
Ajv.prototype.addFormat = addFormat;
|
||||
Ajv.prototype.errorsText = errorsText;
|
||||
|
||||
Ajv.prototype._addSchema = _addSchema;
|
||||
Ajv.prototype._compile = _compile;
|
||||
|
||||
Ajv.prototype.compileAsync = require('./compile/async');
|
||||
var customKeyword = require('./keyword');
|
||||
Ajv.prototype.addKeyword = customKeyword.add;
|
||||
Ajv.prototype.getKeyword = customKeyword.get;
|
||||
Ajv.prototype.removeKeyword = customKeyword.remove;
|
||||
Ajv.prototype.validateKeyword = customKeyword.validate;
|
||||
|
||||
var errorClasses = require('./compile/error_classes');
|
||||
Ajv.ValidationError = errorClasses.Validation;
|
||||
Ajv.MissingRefError = errorClasses.MissingRef;
|
||||
Ajv.$dataMetaSchema = $dataMetaSchema;
|
||||
|
||||
var META_SCHEMA_ID = 'http://json-schema.org/draft-07/schema';
|
||||
|
||||
var META_IGNORE_OPTIONS = [ 'removeAdditional', 'useDefaults', 'coerceTypes', 'strictDefaults' ];
|
||||
var META_SUPPORT_DATA = ['/properties'];
|
||||
|
||||
/**
|
||||
* Creates validator instance.
|
||||
* Usage: `Ajv(opts)`
|
||||
* @param {Object} opts optional options
|
||||
* @return {Object} ajv instance
|
||||
*/
|
||||
function Ajv(opts) {
|
||||
if (!(this instanceof Ajv)) return new Ajv(opts);
|
||||
opts = this._opts = util.copy(opts) || {};
|
||||
setLogger(this);
|
||||
this._schemas = {};
|
||||
this._refs = {};
|
||||
this._fragments = {};
|
||||
this._formats = formats(opts.format);
|
||||
|
||||
this._cache = opts.cache || new Cache;
|
||||
this._loadingSchemas = {};
|
||||
this._compilations = [];
|
||||
this.RULES = rules();
|
||||
this._getId = chooseGetId(opts);
|
||||
|
||||
opts.loopRequired = opts.loopRequired || Infinity;
|
||||
if (opts.errorDataPath == 'property') opts._errorDataPathProperty = true;
|
||||
if (opts.serialize === undefined) opts.serialize = stableStringify;
|
||||
this._metaOpts = getMetaSchemaOptions(this);
|
||||
|
||||
if (opts.formats) addInitialFormats(this);
|
||||
if (opts.keywords) addInitialKeywords(this);
|
||||
addDefaultMetaSchema(this);
|
||||
if (typeof opts.meta == 'object') this.addMetaSchema(opts.meta);
|
||||
if (opts.nullable) this.addKeyword('nullable', {metaSchema: {type: 'boolean'}});
|
||||
addInitialSchemas(this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Validate data using schema
|
||||
* Schema will be compiled and cached (using serialized JSON as key. [fast-json-stable-stringify](https://github.com/epoberezkin/fast-json-stable-stringify) is used to serialize.
|
||||
* @this Ajv
|
||||
* @param {String|Object} schemaKeyRef key, ref or schema object
|
||||
* @param {Any} data to be validated
|
||||
* @return {Boolean} validation result. Errors from the last validation will be available in `ajv.errors` (and also in compiled schema: `schema.errors`).
|
||||
*/
|
||||
function validate(schemaKeyRef, data) {
|
||||
var v;
|
||||
if (typeof schemaKeyRef == 'string') {
|
||||
v = this.getSchema(schemaKeyRef);
|
||||
if (!v) throw new Error('no schema with key or ref "' + schemaKeyRef + '"');
|
||||
} else {
|
||||
var schemaObj = this._addSchema(schemaKeyRef);
|
||||
v = schemaObj.validate || this._compile(schemaObj);
|
||||
}
|
||||
|
||||
var valid = v(data);
|
||||
if (v.$async !== true) this.errors = v.errors;
|
||||
return valid;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create validating function for passed schema.
|
||||
* @this Ajv
|
||||
* @param {Object} schema schema object
|
||||
* @param {Boolean} _meta true if schema is a meta-schema. Used internally to compile meta schemas of custom keywords.
|
||||
* @return {Function} validating function
|
||||
*/
|
||||
function compile(schema, _meta) {
|
||||
var schemaObj = this._addSchema(schema, undefined, _meta);
|
||||
return schemaObj.validate || this._compile(schemaObj);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds schema to the instance.
|
||||
* @this Ajv
|
||||
* @param {Object|Array} schema schema or array of schemas. If array is passed, `key` and other parameters will be ignored.
|
||||
* @param {String} key Optional schema key. Can be passed to `validate` method instead of schema object or id/ref. One schema per instance can have empty `id` and `key`.
|
||||
* @param {Boolean} _skipValidation true to skip schema validation. Used internally, option validateSchema should be used instead.
|
||||
* @param {Boolean} _meta true if schema is a meta-schema. Used internally, addMetaSchema should be used instead.
|
||||
* @return {Ajv} this for method chaining
|
||||
*/
|
||||
function addSchema(schema, key, _skipValidation, _meta) {
|
||||
if (Array.isArray(schema)){
|
||||
for (var i=0; i<schema.length; i++) this.addSchema(schema[i], undefined, _skipValidation, _meta);
|
||||
return this;
|
||||
}
|
||||
var id = this._getId(schema);
|
||||
if (id !== undefined && typeof id != 'string')
|
||||
throw new Error('schema id must be string');
|
||||
key = resolve.normalizeId(key || id);
|
||||
checkUnique(this, key);
|
||||
this._schemas[key] = this._addSchema(schema, _skipValidation, _meta, true);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add schema that will be used to validate other schemas
|
||||
* options in META_IGNORE_OPTIONS are alway set to false
|
||||
* @this Ajv
|
||||
* @param {Object} schema schema object
|
||||
* @param {String} key optional schema key
|
||||
* @param {Boolean} skipValidation true to skip schema validation, can be used to override validateSchema option for meta-schema
|
||||
* @return {Ajv} this for method chaining
|
||||
*/
|
||||
function addMetaSchema(schema, key, skipValidation) {
|
||||
this.addSchema(schema, key, skipValidation, true);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Validate schema
|
||||
* @this Ajv
|
||||
* @param {Object} schema schema to validate
|
||||
* @param {Boolean} throwOrLogError pass true to throw (or log) an error if invalid
|
||||
* @return {Boolean} true if schema is valid
|
||||
*/
|
||||
function validateSchema(schema, throwOrLogError) {
|
||||
var $schema = schema.$schema;
|
||||
if ($schema !== undefined && typeof $schema != 'string')
|
||||
throw new Error('$schema must be a string');
|
||||
$schema = $schema || this._opts.defaultMeta || defaultMeta(this);
|
||||
if (!$schema) {
|
||||
this.logger.warn('meta-schema not available');
|
||||
this.errors = null;
|
||||
return true;
|
||||
}
|
||||
var valid = this.validate($schema, schema);
|
||||
if (!valid && throwOrLogError) {
|
||||
var message = 'schema is invalid: ' + this.errorsText();
|
||||
if (this._opts.validateSchema == 'log') this.logger.error(message);
|
||||
else throw new Error(message);
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
|
||||
function defaultMeta(self) {
|
||||
var meta = self._opts.meta;
|
||||
self._opts.defaultMeta = typeof meta == 'object'
|
||||
? self._getId(meta) || meta
|
||||
: self.getSchema(META_SCHEMA_ID)
|
||||
? META_SCHEMA_ID
|
||||
: undefined;
|
||||
return self._opts.defaultMeta;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get compiled schema from the instance by `key` or `ref`.
|
||||
* @this Ajv
|
||||
* @param {String} keyRef `key` that was passed to `addSchema` or full schema reference (`schema.id` or resolved id).
|
||||
* @return {Function} schema validating function (with property `schema`).
|
||||
*/
|
||||
function getSchema(keyRef) {
|
||||
var schemaObj = _getSchemaObj(this, keyRef);
|
||||
switch (typeof schemaObj) {
|
||||
case 'object': return schemaObj.validate || this._compile(schemaObj);
|
||||
case 'string': return this.getSchema(schemaObj);
|
||||
case 'undefined': return _getSchemaFragment(this, keyRef);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function _getSchemaFragment(self, ref) {
|
||||
var res = resolve.schema.call(self, { schema: {} }, ref);
|
||||
if (res) {
|
||||
var schema = res.schema
|
||||
, root = res.root
|
||||
, baseId = res.baseId;
|
||||
var v = compileSchema.call(self, schema, root, undefined, baseId);
|
||||
self._fragments[ref] = new SchemaObject({
|
||||
ref: ref,
|
||||
fragment: true,
|
||||
schema: schema,
|
||||
root: root,
|
||||
baseId: baseId,
|
||||
validate: v
|
||||
});
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function _getSchemaObj(self, keyRef) {
|
||||
keyRef = resolve.normalizeId(keyRef);
|
||||
return self._schemas[keyRef] || self._refs[keyRef] || self._fragments[keyRef];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove cached schema(s).
|
||||
* If no parameter is passed all schemas but meta-schemas are removed.
|
||||
* If RegExp is passed all schemas with key/id matching pattern but meta-schemas are removed.
|
||||
* Even if schema is referenced by other schemas it still can be removed as other schemas have local references.
|
||||
* @this Ajv
|
||||
* @param {String|Object|RegExp} schemaKeyRef key, ref, pattern to match key/ref or schema object
|
||||
* @return {Ajv} this for method chaining
|
||||
*/
|
||||
function removeSchema(schemaKeyRef) {
|
||||
if (schemaKeyRef instanceof RegExp) {
|
||||
_removeAllSchemas(this, this._schemas, schemaKeyRef);
|
||||
_removeAllSchemas(this, this._refs, schemaKeyRef);
|
||||
return this;
|
||||
}
|
||||
switch (typeof schemaKeyRef) {
|
||||
case 'undefined':
|
||||
_removeAllSchemas(this, this._schemas);
|
||||
_removeAllSchemas(this, this._refs);
|
||||
this._cache.clear();
|
||||
return this;
|
||||
case 'string':
|
||||
var schemaObj = _getSchemaObj(this, schemaKeyRef);
|
||||
if (schemaObj) this._cache.del(schemaObj.cacheKey);
|
||||
delete this._schemas[schemaKeyRef];
|
||||
delete this._refs[schemaKeyRef];
|
||||
return this;
|
||||
case 'object':
|
||||
var serialize = this._opts.serialize;
|
||||
var cacheKey = serialize ? serialize(schemaKeyRef) : schemaKeyRef;
|
||||
this._cache.del(cacheKey);
|
||||
var id = this._getId(schemaKeyRef);
|
||||
if (id) {
|
||||
id = resolve.normalizeId(id);
|
||||
delete this._schemas[id];
|
||||
delete this._refs[id];
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
function _removeAllSchemas(self, schemas, regex) {
|
||||
for (var keyRef in schemas) {
|
||||
var schemaObj = schemas[keyRef];
|
||||
if (!schemaObj.meta && (!regex || regex.test(keyRef))) {
|
||||
self._cache.del(schemaObj.cacheKey);
|
||||
delete schemas[keyRef];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* @this Ajv */
|
||||
function _addSchema(schema, skipValidation, meta, shouldAddSchema) {
|
||||
if (typeof schema != 'object' && typeof schema != 'boolean')
|
||||
throw new Error('schema should be object or boolean');
|
||||
var serialize = this._opts.serialize;
|
||||
var cacheKey = serialize ? serialize(schema) : schema;
|
||||
var cached = this._cache.get(cacheKey);
|
||||
if (cached) return cached;
|
||||
|
||||
shouldAddSchema = shouldAddSchema || this._opts.addUsedSchema !== false;
|
||||
|
||||
var id = resolve.normalizeId(this._getId(schema));
|
||||
if (id && shouldAddSchema) checkUnique(this, id);
|
||||
|
||||
var willValidate = this._opts.validateSchema !== false && !skipValidation;
|
||||
var recursiveMeta;
|
||||
if (willValidate && !(recursiveMeta = id && id == resolve.normalizeId(schema.$schema)))
|
||||
this.validateSchema(schema, true);
|
||||
|
||||
var localRefs = resolve.ids.call(this, schema);
|
||||
|
||||
var schemaObj = new SchemaObject({
|
||||
id: id,
|
||||
schema: schema,
|
||||
localRefs: localRefs,
|
||||
cacheKey: cacheKey,
|
||||
meta: meta
|
||||
});
|
||||
|
||||
if (id[0] != '#' && shouldAddSchema) this._refs[id] = schemaObj;
|
||||
this._cache.put(cacheKey, schemaObj);
|
||||
|
||||
if (willValidate && recursiveMeta) this.validateSchema(schema, true);
|
||||
|
||||
return schemaObj;
|
||||
}
|
||||
|
||||
|
||||
/* @this Ajv */
|
||||
function _compile(schemaObj, root) {
|
||||
if (schemaObj.compiling) {
|
||||
schemaObj.validate = callValidate;
|
||||
callValidate.schema = schemaObj.schema;
|
||||
callValidate.errors = null;
|
||||
callValidate.root = root ? root : callValidate;
|
||||
if (schemaObj.schema.$async === true)
|
||||
callValidate.$async = true;
|
||||
return callValidate;
|
||||
}
|
||||
schemaObj.compiling = true;
|
||||
|
||||
var currentOpts;
|
||||
if (schemaObj.meta) {
|
||||
currentOpts = this._opts;
|
||||
this._opts = this._metaOpts;
|
||||
}
|
||||
|
||||
var v;
|
||||
try { v = compileSchema.call(this, schemaObj.schema, root, schemaObj.localRefs); }
|
||||
catch(e) {
|
||||
delete schemaObj.validate;
|
||||
throw e;
|
||||
}
|
||||
finally {
|
||||
schemaObj.compiling = false;
|
||||
if (schemaObj.meta) this._opts = currentOpts;
|
||||
}
|
||||
|
||||
schemaObj.validate = v;
|
||||
schemaObj.refs = v.refs;
|
||||
schemaObj.refVal = v.refVal;
|
||||
schemaObj.root = v.root;
|
||||
return v;
|
||||
|
||||
|
||||
/* @this {*} - custom context, see passContext option */
|
||||
function callValidate() {
|
||||
/* jshint validthis: true */
|
||||
var _validate = schemaObj.validate;
|
||||
var result = _validate.apply(this, arguments);
|
||||
callValidate.errors = _validate.errors;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function chooseGetId(opts) {
|
||||
switch (opts.schemaId) {
|
||||
case 'auto': return _get$IdOrId;
|
||||
case 'id': return _getId;
|
||||
default: return _get$Id;
|
||||
}
|
||||
}
|
||||
|
||||
/* @this Ajv */
|
||||
function _getId(schema) {
|
||||
if (schema.$id) this.logger.warn('schema $id ignored', schema.$id);
|
||||
return schema.id;
|
||||
}
|
||||
|
||||
/* @this Ajv */
|
||||
function _get$Id(schema) {
|
||||
if (schema.id) this.logger.warn('schema id ignored', schema.id);
|
||||
return schema.$id;
|
||||
}
|
||||
|
||||
|
||||
function _get$IdOrId(schema) {
|
||||
if (schema.$id && schema.id && schema.$id != schema.id)
|
||||
throw new Error('schema $id is different from id');
|
||||
return schema.$id || schema.id;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert array of error message objects to string
|
||||
* @this Ajv
|
||||
* @param {Array<Object>} errors optional array of validation errors, if not passed errors from the instance are used.
|
||||
* @param {Object} options optional options with properties `separator` and `dataVar`.
|
||||
* @return {String} human readable string with all errors descriptions
|
||||
*/
|
||||
function errorsText(errors, options) {
|
||||
errors = errors || this.errors;
|
||||
if (!errors) return 'No errors';
|
||||
options = options || {};
|
||||
var separator = options.separator === undefined ? ', ' : options.separator;
|
||||
var dataVar = options.dataVar === undefined ? 'data' : options.dataVar;
|
||||
|
||||
var text = '';
|
||||
for (var i=0; i<errors.length; i++) {
|
||||
var e = errors[i];
|
||||
if (e) text += dataVar + e.dataPath + ' ' + e.message + separator;
|
||||
}
|
||||
return text.slice(0, -separator.length);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add custom format
|
||||
* @this Ajv
|
||||
* @param {String} name format name
|
||||
* @param {String|RegExp|Function} format string is converted to RegExp; function should return boolean (true when valid)
|
||||
* @return {Ajv} this for method chaining
|
||||
*/
|
||||
function addFormat(name, format) {
|
||||
if (typeof format == 'string') format = new RegExp(format);
|
||||
this._formats[name] = format;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
function addDefaultMetaSchema(self) {
|
||||
var $dataSchema;
|
||||
if (self._opts.$data) {
|
||||
$dataSchema = require('./refs/data.json');
|
||||
self.addMetaSchema($dataSchema, $dataSchema.$id, true);
|
||||
}
|
||||
if (self._opts.meta === false) return;
|
||||
var metaSchema = require('./refs/json-schema-draft-07.json');
|
||||
if (self._opts.$data) metaSchema = $dataMetaSchema(metaSchema, META_SUPPORT_DATA);
|
||||
self.addMetaSchema(metaSchema, META_SCHEMA_ID, true);
|
||||
self._refs['http://json-schema.org/schema'] = META_SCHEMA_ID;
|
||||
}
|
||||
|
||||
|
||||
function addInitialSchemas(self) {
|
||||
var optsSchemas = self._opts.schemas;
|
||||
if (!optsSchemas) return;
|
||||
if (Array.isArray(optsSchemas)) self.addSchema(optsSchemas);
|
||||
else for (var key in optsSchemas) self.addSchema(optsSchemas[key], key);
|
||||
}
|
||||
|
||||
|
||||
function addInitialFormats(self) {
|
||||
for (var name in self._opts.formats) {
|
||||
var format = self._opts.formats[name];
|
||||
self.addFormat(name, format);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function addInitialKeywords(self) {
|
||||
for (var name in self._opts.keywords) {
|
||||
var keyword = self._opts.keywords[name];
|
||||
self.addKeyword(name, keyword);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function checkUnique(self, id) {
|
||||
if (self._schemas[id] || self._refs[id])
|
||||
throw new Error('schema with key or id "' + id + '" already exists');
|
||||
}
|
||||
|
||||
|
||||
function getMetaSchemaOptions(self) {
|
||||
var metaOpts = util.copy(self._opts);
|
||||
for (var i=0; i<META_IGNORE_OPTIONS.length; i++)
|
||||
delete metaOpts[META_IGNORE_OPTIONS[i]];
|
||||
return metaOpts;
|
||||
}
|
||||
|
||||
|
||||
function setLogger(self) {
|
||||
var logger = self._opts.logger;
|
||||
if (logger === false) {
|
||||
self.logger = {log: noop, warn: noop, error: noop};
|
||||
} else {
|
||||
if (logger === undefined) logger = console;
|
||||
if (!(typeof logger == 'object' && logger.log && logger.warn && logger.error))
|
||||
throw new Error('logger must implement log, warn and error methods');
|
||||
self.logger = logger;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function noop() {}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
'use strict';
|
||||
|
||||
|
||||
var Cache = module.exports = function Cache() {
|
||||
this._cache = {};
|
||||
};
|
||||
|
||||
|
||||
Cache.prototype.put = function Cache_put(key, value) {
|
||||
this._cache[key] = value;
|
||||
};
|
||||
|
||||
|
||||
Cache.prototype.get = function Cache_get(key) {
|
||||
return this._cache[key];
|
||||
};
|
||||
|
||||
|
||||
Cache.prototype.del = function Cache_del(key) {
|
||||
delete this._cache[key];
|
||||
};
|
||||
|
||||
|
||||
Cache.prototype.clear = function Cache_clear() {
|
||||
this._cache = {};
|
||||
};
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
'use strict';
|
||||
|
||||
var MissingRefError = require('./error_classes').MissingRef;
|
||||
|
||||
module.exports = compileAsync;
|
||||
|
||||
|
||||
/**
|
||||
* Creates validating function for passed schema with asynchronous loading of missing schemas.
|
||||
* `loadSchema` option should be a function that accepts schema uri and returns promise that resolves with the schema.
|
||||
* @this Ajv
|
||||
* @param {Object} schema schema object
|
||||
* @param {Boolean} meta optional true to compile meta-schema; this parameter can be skipped
|
||||
* @param {Function} callback an optional node-style callback, it is called with 2 parameters: error (or null) and validating function.
|
||||
* @return {Promise} promise that resolves with a validating function.
|
||||
*/
|
||||
function compileAsync(schema, meta, callback) {
|
||||
/* eslint no-shadow: 0 */
|
||||
/* global Promise */
|
||||
/* jshint validthis: true */
|
||||
var self = this;
|
||||
if (typeof this._opts.loadSchema != 'function')
|
||||
throw new Error('options.loadSchema should be a function');
|
||||
|
||||
if (typeof meta == 'function') {
|
||||
callback = meta;
|
||||
meta = undefined;
|
||||
}
|
||||
|
||||
var p = loadMetaSchemaOf(schema).then(function () {
|
||||
var schemaObj = self._addSchema(schema, undefined, meta);
|
||||
return schemaObj.validate || _compileAsync(schemaObj);
|
||||
});
|
||||
|
||||
if (callback) {
|
||||
p.then(
|
||||
function(v) { callback(null, v); },
|
||||
callback
|
||||
);
|
||||
}
|
||||
|
||||
return p;
|
||||
|
||||
|
||||
function loadMetaSchemaOf(sch) {
|
||||
var $schema = sch.$schema;
|
||||
return $schema && !self.getSchema($schema)
|
||||
? compileAsync.call(self, { $ref: $schema }, true)
|
||||
: Promise.resolve();
|
||||
}
|
||||
|
||||
|
||||
function _compileAsync(schemaObj) {
|
||||
try { return self._compile(schemaObj); }
|
||||
catch(e) {
|
||||
if (e instanceof MissingRefError) return loadMissingSchema(e);
|
||||
throw e;
|
||||
}
|
||||
|
||||
|
||||
function loadMissingSchema(e) {
|
||||
var ref = e.missingSchema;
|
||||
if (added(ref)) throw new Error('Schema ' + ref + ' is loaded but ' + e.missingRef + ' cannot be resolved');
|
||||
|
||||
var schemaPromise = self._loadingSchemas[ref];
|
||||
if (!schemaPromise) {
|
||||
schemaPromise = self._loadingSchemas[ref] = self._opts.loadSchema(ref);
|
||||
schemaPromise.then(removePromise, removePromise);
|
||||
}
|
||||
|
||||
return schemaPromise.then(function (sch) {
|
||||
if (!added(ref)) {
|
||||
return loadMetaSchemaOf(sch).then(function () {
|
||||
if (!added(ref)) self.addSchema(sch, ref, undefined, meta);
|
||||
});
|
||||
}
|
||||
}).then(function() {
|
||||
return _compileAsync(schemaObj);
|
||||
});
|
||||
|
||||
function removePromise() {
|
||||
delete self._loadingSchemas[ref];
|
||||
}
|
||||
|
||||
function added(ref) {
|
||||
return self._refs[ref] || self._schemas[ref];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
// do NOT remove this file - it would break pre-compiled schemas
|
||||
// https://github.com/ajv-validator/ajv/issues/889
|
||||
module.exports = require('fast-deep-equal');
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
'use strict';
|
||||
|
||||
var resolve = require('./resolve');
|
||||
|
||||
module.exports = {
|
||||
Validation: errorSubclass(ValidationError),
|
||||
MissingRef: errorSubclass(MissingRefError)
|
||||
};
|
||||
|
||||
|
||||
function ValidationError(errors) {
|
||||
this.message = 'validation failed';
|
||||
this.errors = errors;
|
||||
this.ajv = this.validation = true;
|
||||
}
|
||||
|
||||
|
||||
MissingRefError.message = function (baseId, ref) {
|
||||
return 'can\'t resolve reference ' + ref + ' from id ' + baseId;
|
||||
};
|
||||
|
||||
|
||||
function MissingRefError(baseId, ref, message) {
|
||||
this.message = message || MissingRefError.message(baseId, ref);
|
||||
this.missingRef = resolve.url(baseId, ref);
|
||||
this.missingSchema = resolve.normalizeId(resolve.fullPath(this.missingRef));
|
||||
}
|
||||
|
||||
|
||||
function errorSubclass(Subclass) {
|
||||
Subclass.prototype = Object.create(Error.prototype);
|
||||
Subclass.prototype.constructor = Subclass;
|
||||
return Subclass;
|
||||
}
|
||||
+142
@@ -0,0 +1,142 @@
|
||||
'use strict';
|
||||
|
||||
var util = require('./util');
|
||||
|
||||
var DATE = /^(\d\d\d\d)-(\d\d)-(\d\d)$/;
|
||||
var DAYS = [0,31,28,31,30,31,30,31,31,30,31,30,31];
|
||||
var TIME = /^(\d\d):(\d\d):(\d\d)(\.\d+)?(z|[+-]\d\d(?::?\d\d)?)?$/i;
|
||||
var HOSTNAME = /^(?=.{1,253}\.?$)[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[-0-9a-z]{0,61}[0-9a-z])?)*\.?$/i;
|
||||
var URI = /^(?:[a-z][a-z0-9+\-.]*:)(?:\/?\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|[Vv][0-9a-f]+\.[a-z0-9\-._~!$&'()*+,;=:]+)\]|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)|(?:[a-z0-9\-._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\d*)?(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?|(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)(?:\?(?:[a-z0-9\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$/i;
|
||||
var URIREF = /^(?:[a-z][a-z0-9+\-.]*:)?(?:\/?\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|[Vv][0-9a-f]+\.[a-z0-9\-._~!$&'()*+,;=:]+)\]|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)|(?:[a-z0-9\-._~!$&'"()*+,;=]|%[0-9a-f]{2})*)(?::\d*)?(?:\/(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})*)*|\/(?:(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})*)*)?|(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})*)*)?(?:\?(?:[a-z0-9\-._~!$&'"()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\-._~!$&'"()*+,;=:@/?]|%[0-9a-f]{2})*)?$/i;
|
||||
// uri-template: https://tools.ietf.org/html/rfc6570
|
||||
var URITEMPLATE = /^(?:(?:[^\x00-\x20"'<>%\\^`{|}]|%[0-9a-f]{2})|\{[+#./;?&=,!@|]?(?:[a-z0-9_]|%[0-9a-f]{2})+(?::[1-9][0-9]{0,3}|\*)?(?:,(?:[a-z0-9_]|%[0-9a-f]{2})+(?::[1-9][0-9]{0,3}|\*)?)*\})*$/i;
|
||||
// For the source: https://gist.github.com/dperini/729294
|
||||
// For test cases: https://mathiasbynens.be/demo/url-regex
|
||||
// @todo Delete current URL in favour of the commented out URL rule when this issue is fixed https://github.com/eslint/eslint/issues/7983.
|
||||
// var URL = /^(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?@)?(?:(?!10(?:\.\d{1,3}){3})(?!127(?:\.\d{1,3}){3})(?!169\.254(?:\.\d{1,3}){2})(?!192\.168(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u{00a1}-\u{ffff}0-9]+-)*[a-z\u{00a1}-\u{ffff}0-9]+)(?:\.(?:[a-z\u{00a1}-\u{ffff}0-9]+-)*[a-z\u{00a1}-\u{ffff}0-9]+)*(?:\.(?:[a-z\u{00a1}-\u{ffff}]{2,})))(?::\d{2,5})?(?:\/[^\s]*)?$/iu;
|
||||
var URL = /^(?:(?:http[s\u017F]?|ftp):\/\/)(?:(?:[\0-\x08\x0E-\x1F!-\x9F\xA1-\u167F\u1681-\u1FFF\u200B-\u2027\u202A-\u202E\u2030-\u205E\u2060-\u2FFF\u3001-\uD7FF\uE000-\uFEFE\uFF00-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])+(?::(?:[\0-\x08\x0E-\x1F!-\x9F\xA1-\u167F\u1681-\u1FFF\u200B-\u2027\u202A-\u202E\u2030-\u205E\u2060-\u2FFF\u3001-\uD7FF\uE000-\uFEFE\uFF00-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])*)?@)?(?:(?!10(?:\.[0-9]{1,3}){3})(?!127(?:\.[0-9]{1,3}){3})(?!169\.254(?:\.[0-9]{1,3}){2})(?!192\.168(?:\.[0-9]{1,3}){2})(?!172\.(?:1[6-9]|2[0-9]|3[01])(?:\.[0-9]{1,3}){2})(?:[1-9][0-9]?|1[0-9][0-9]|2[01][0-9]|22[0-3])(?:\.(?:1?[0-9]{1,2}|2[0-4][0-9]|25[0-5])){2}(?:\.(?:[1-9][0-9]?|1[0-9][0-9]|2[0-4][0-9]|25[0-4]))|(?:(?:(?:[0-9a-z\xA1-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])+-)*(?:[0-9a-z\xA1-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])+)(?:\.(?:(?:[0-9a-z\xA1-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])+-)*(?:[0-9a-z\xA1-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])+)*(?:\.(?:(?:[a-z\xA1-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]){2,})))(?::[0-9]{2,5})?(?:\/(?:[\0-\x08\x0E-\x1F!-\x9F\xA1-\u167F\u1681-\u1FFF\u200B-\u2027\u202A-\u202E\u2030-\u205E\u2060-\u2FFF\u3001-\uD7FF\uE000-\uFEFE\uFF00-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])*)?$/i;
|
||||
var UUID = /^(?:urn:uuid:)?[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}$/i;
|
||||
var JSON_POINTER = /^(?:\/(?:[^~/]|~0|~1)*)*$/;
|
||||
var JSON_POINTER_URI_FRAGMENT = /^#(?:\/(?:[a-z0-9_\-.!$&'()*+,;:=@]|%[0-9a-f]{2}|~0|~1)*)*$/i;
|
||||
var RELATIVE_JSON_POINTER = /^(?:0|[1-9][0-9]*)(?:#|(?:\/(?:[^~/]|~0|~1)*)*)$/;
|
||||
|
||||
|
||||
module.exports = formats;
|
||||
|
||||
function formats(mode) {
|
||||
mode = mode == 'full' ? 'full' : 'fast';
|
||||
return util.copy(formats[mode]);
|
||||
}
|
||||
|
||||
|
||||
formats.fast = {
|
||||
// date: http://tools.ietf.org/html/rfc3339#section-5.6
|
||||
date: /^\d\d\d\d-[0-1]\d-[0-3]\d$/,
|
||||
// date-time: http://tools.ietf.org/html/rfc3339#section-5.6
|
||||
time: /^(?:[0-2]\d:[0-5]\d:[0-5]\d|23:59:60)(?:\.\d+)?(?:z|[+-]\d\d(?::?\d\d)?)?$/i,
|
||||
'date-time': /^\d\d\d\d-[0-1]\d-[0-3]\d[t\s](?:[0-2]\d:[0-5]\d:[0-5]\d|23:59:60)(?:\.\d+)?(?:z|[+-]\d\d(?::?\d\d)?)$/i,
|
||||
// uri: https://github.com/mafintosh/is-my-json-valid/blob/master/formats.js
|
||||
uri: /^(?:[a-z][a-z0-9+\-.]*:)(?:\/?\/)?[^\s]*$/i,
|
||||
'uri-reference': /^(?:(?:[a-z][a-z0-9+\-.]*:)?\/?\/)?(?:[^\\\s#][^\s#]*)?(?:#[^\\\s]*)?$/i,
|
||||
'uri-template': URITEMPLATE,
|
||||
url: URL,
|
||||
// email (sources from jsen validator):
|
||||
// http://stackoverflow.com/questions/201323/using-a-regular-expression-to-validate-an-email-address#answer-8829363
|
||||
// http://www.w3.org/TR/html5/forms.html#valid-e-mail-address (search for 'willful violation')
|
||||
email: /^[a-z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*$/i,
|
||||
hostname: HOSTNAME,
|
||||
// optimized https://www.safaribooksonline.com/library/view/regular-expressions-cookbook/9780596802837/ch07s16.html
|
||||
ipv4: /^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$/,
|
||||
// optimized http://stackoverflow.com/questions/53497/regular-expression-that-matches-valid-ipv6-addresses
|
||||
ipv6: /^\s*(?:(?:(?:[0-9a-f]{1,4}:){7}(?:[0-9a-f]{1,4}|:))|(?:(?:[0-9a-f]{1,4}:){6}(?::[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9a-f]{1,4}:){5}(?:(?:(?::[0-9a-f]{1,4}){1,2})|:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9a-f]{1,4}:){4}(?:(?:(?::[0-9a-f]{1,4}){1,3})|(?:(?::[0-9a-f]{1,4})?:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){3}(?:(?:(?::[0-9a-f]{1,4}){1,4})|(?:(?::[0-9a-f]{1,4}){0,2}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){2}(?:(?:(?::[0-9a-f]{1,4}){1,5})|(?:(?::[0-9a-f]{1,4}){0,3}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){1}(?:(?:(?::[0-9a-f]{1,4}){1,6})|(?:(?::[0-9a-f]{1,4}){0,4}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?::(?:(?:(?::[0-9a-f]{1,4}){1,7})|(?:(?::[0-9a-f]{1,4}){0,5}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(?:%.+)?\s*$/i,
|
||||
regex: regex,
|
||||
// uuid: http://tools.ietf.org/html/rfc4122
|
||||
uuid: UUID,
|
||||
// JSON-pointer: https://tools.ietf.org/html/rfc6901
|
||||
// uri fragment: https://tools.ietf.org/html/rfc3986#appendix-A
|
||||
'json-pointer': JSON_POINTER,
|
||||
'json-pointer-uri-fragment': JSON_POINTER_URI_FRAGMENT,
|
||||
// relative JSON-pointer: http://tools.ietf.org/html/draft-luff-relative-json-pointer-00
|
||||
'relative-json-pointer': RELATIVE_JSON_POINTER
|
||||
};
|
||||
|
||||
|
||||
formats.full = {
|
||||
date: date,
|
||||
time: time,
|
||||
'date-time': date_time,
|
||||
uri: uri,
|
||||
'uri-reference': URIREF,
|
||||
'uri-template': URITEMPLATE,
|
||||
url: URL,
|
||||
email: /^[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i,
|
||||
hostname: HOSTNAME,
|
||||
ipv4: /^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$/,
|
||||
ipv6: /^\s*(?:(?:(?:[0-9a-f]{1,4}:){7}(?:[0-9a-f]{1,4}|:))|(?:(?:[0-9a-f]{1,4}:){6}(?::[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9a-f]{1,4}:){5}(?:(?:(?::[0-9a-f]{1,4}){1,2})|:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9a-f]{1,4}:){4}(?:(?:(?::[0-9a-f]{1,4}){1,3})|(?:(?::[0-9a-f]{1,4})?:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){3}(?:(?:(?::[0-9a-f]{1,4}){1,4})|(?:(?::[0-9a-f]{1,4}){0,2}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){2}(?:(?:(?::[0-9a-f]{1,4}){1,5})|(?:(?::[0-9a-f]{1,4}){0,3}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){1}(?:(?:(?::[0-9a-f]{1,4}){1,6})|(?:(?::[0-9a-f]{1,4}){0,4}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?::(?:(?:(?::[0-9a-f]{1,4}){1,7})|(?:(?::[0-9a-f]{1,4}){0,5}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(?:%.+)?\s*$/i,
|
||||
regex: regex,
|
||||
uuid: UUID,
|
||||
'json-pointer': JSON_POINTER,
|
||||
'json-pointer-uri-fragment': JSON_POINTER_URI_FRAGMENT,
|
||||
'relative-json-pointer': RELATIVE_JSON_POINTER
|
||||
};
|
||||
|
||||
|
||||
function isLeapYear(year) {
|
||||
// https://tools.ietf.org/html/rfc3339#appendix-C
|
||||
return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
|
||||
}
|
||||
|
||||
|
||||
function date(str) {
|
||||
// full-date from http://tools.ietf.org/html/rfc3339#section-5.6
|
||||
var matches = str.match(DATE);
|
||||
if (!matches) return false;
|
||||
|
||||
var year = +matches[1];
|
||||
var month = +matches[2];
|
||||
var day = +matches[3];
|
||||
|
||||
return month >= 1 && month <= 12 && day >= 1 &&
|
||||
day <= (month == 2 && isLeapYear(year) ? 29 : DAYS[month]);
|
||||
}
|
||||
|
||||
|
||||
function time(str, full) {
|
||||
var matches = str.match(TIME);
|
||||
if (!matches) return false;
|
||||
|
||||
var hour = matches[1];
|
||||
var minute = matches[2];
|
||||
var second = matches[3];
|
||||
var timeZone = matches[5];
|
||||
return ((hour <= 23 && minute <= 59 && second <= 59) ||
|
||||
(hour == 23 && minute == 59 && second == 60)) &&
|
||||
(!full || timeZone);
|
||||
}
|
||||
|
||||
|
||||
var DATE_TIME_SEPARATOR = /t|\s/i;
|
||||
function date_time(str) {
|
||||
// http://tools.ietf.org/html/rfc3339#section-5.6
|
||||
var dateTime = str.split(DATE_TIME_SEPARATOR);
|
||||
return dateTime.length == 2 && date(dateTime[0]) && time(dateTime[1], true);
|
||||
}
|
||||
|
||||
|
||||
var NOT_URI_FRAGMENT = /\/|:/;
|
||||
function uri(str) {
|
||||
// http://jmrware.com/articles/2009/uri_regexp/URI_regex.html + optional protocol + required "."
|
||||
return NOT_URI_FRAGMENT.test(str) && URI.test(str);
|
||||
}
|
||||
|
||||
|
||||
var Z_ANCHOR = /[^\\]\\Z/;
|
||||
function regex(str) {
|
||||
if (Z_ANCHOR.test(str)) return false;
|
||||
try {
|
||||
new RegExp(str);
|
||||
return true;
|
||||
} catch(e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+387
@@ -0,0 +1,387 @@
|
||||
'use strict';
|
||||
|
||||
var resolve = require('./resolve')
|
||||
, util = require('./util')
|
||||
, errorClasses = require('./error_classes')
|
||||
, stableStringify = require('fast-json-stable-stringify');
|
||||
|
||||
var validateGenerator = require('../dotjs/validate');
|
||||
|
||||
/**
|
||||
* Functions below are used inside compiled validations function
|
||||
*/
|
||||
|
||||
var ucs2length = util.ucs2length;
|
||||
var equal = require('fast-deep-equal');
|
||||
|
||||
// this error is thrown by async schemas to return validation errors via exception
|
||||
var ValidationError = errorClasses.Validation;
|
||||
|
||||
module.exports = compile;
|
||||
|
||||
|
||||
/**
|
||||
* Compiles schema to validation function
|
||||
* @this Ajv
|
||||
* @param {Object} schema schema object
|
||||
* @param {Object} root object with information about the root schema for this schema
|
||||
* @param {Object} localRefs the hash of local references inside the schema (created by resolve.id), used for inline resolution
|
||||
* @param {String} baseId base ID for IDs in the schema
|
||||
* @return {Function} validation function
|
||||
*/
|
||||
function compile(schema, root, localRefs, baseId) {
|
||||
/* jshint validthis: true, evil: true */
|
||||
/* eslint no-shadow: 0 */
|
||||
var self = this
|
||||
, opts = this._opts
|
||||
, refVal = [ undefined ]
|
||||
, refs = {}
|
||||
, patterns = []
|
||||
, patternsHash = {}
|
||||
, defaults = []
|
||||
, defaultsHash = {}
|
||||
, customRules = [];
|
||||
|
||||
root = root || { schema: schema, refVal: refVal, refs: refs };
|
||||
|
||||
var c = checkCompiling.call(this, schema, root, baseId);
|
||||
var compilation = this._compilations[c.index];
|
||||
if (c.compiling) return (compilation.callValidate = callValidate);
|
||||
|
||||
var formats = this._formats;
|
||||
var RULES = this.RULES;
|
||||
|
||||
try {
|
||||
var v = localCompile(schema, root, localRefs, baseId);
|
||||
compilation.validate = v;
|
||||
var cv = compilation.callValidate;
|
||||
if (cv) {
|
||||
cv.schema = v.schema;
|
||||
cv.errors = null;
|
||||
cv.refs = v.refs;
|
||||
cv.refVal = v.refVal;
|
||||
cv.root = v.root;
|
||||
cv.$async = v.$async;
|
||||
if (opts.sourceCode) cv.source = v.source;
|
||||
}
|
||||
return v;
|
||||
} finally {
|
||||
endCompiling.call(this, schema, root, baseId);
|
||||
}
|
||||
|
||||
/* @this {*} - custom context, see passContext option */
|
||||
function callValidate() {
|
||||
/* jshint validthis: true */
|
||||
var validate = compilation.validate;
|
||||
var result = validate.apply(this, arguments);
|
||||
callValidate.errors = validate.errors;
|
||||
return result;
|
||||
}
|
||||
|
||||
function localCompile(_schema, _root, localRefs, baseId) {
|
||||
var isRoot = !_root || (_root && _root.schema == _schema);
|
||||
if (_root.schema != root.schema)
|
||||
return compile.call(self, _schema, _root, localRefs, baseId);
|
||||
|
||||
var $async = _schema.$async === true;
|
||||
|
||||
var sourceCode = validateGenerator({
|
||||
isTop: true,
|
||||
schema: _schema,
|
||||
isRoot: isRoot,
|
||||
baseId: baseId,
|
||||
root: _root,
|
||||
schemaPath: '',
|
||||
errSchemaPath: '#',
|
||||
errorPath: '""',
|
||||
MissingRefError: errorClasses.MissingRef,
|
||||
RULES: RULES,
|
||||
validate: validateGenerator,
|
||||
util: util,
|
||||
resolve: resolve,
|
||||
resolveRef: resolveRef,
|
||||
usePattern: usePattern,
|
||||
useDefault: useDefault,
|
||||
useCustomRule: useCustomRule,
|
||||
opts: opts,
|
||||
formats: formats,
|
||||
logger: self.logger,
|
||||
self: self
|
||||
});
|
||||
|
||||
sourceCode = vars(refVal, refValCode) + vars(patterns, patternCode)
|
||||
+ vars(defaults, defaultCode) + vars(customRules, customRuleCode)
|
||||
+ sourceCode;
|
||||
|
||||
if (opts.processCode) sourceCode = opts.processCode(sourceCode, _schema);
|
||||
// console.log('\n\n\n *** \n', JSON.stringify(sourceCode));
|
||||
var validate;
|
||||
try {
|
||||
var makeValidate = new Function(
|
||||
'self',
|
||||
'RULES',
|
||||
'formats',
|
||||
'root',
|
||||
'refVal',
|
||||
'defaults',
|
||||
'customRules',
|
||||
'equal',
|
||||
'ucs2length',
|
||||
'ValidationError',
|
||||
sourceCode
|
||||
);
|
||||
|
||||
validate = makeValidate(
|
||||
self,
|
||||
RULES,
|
||||
formats,
|
||||
root,
|
||||
refVal,
|
||||
defaults,
|
||||
customRules,
|
||||
equal,
|
||||
ucs2length,
|
||||
ValidationError
|
||||
);
|
||||
|
||||
refVal[0] = validate;
|
||||
} catch(e) {
|
||||
self.logger.error('Error compiling schema, function code:', sourceCode);
|
||||
throw e;
|
||||
}
|
||||
|
||||
validate.schema = _schema;
|
||||
validate.errors = null;
|
||||
validate.refs = refs;
|
||||
validate.refVal = refVal;
|
||||
validate.root = isRoot ? validate : _root;
|
||||
if ($async) validate.$async = true;
|
||||
if (opts.sourceCode === true) {
|
||||
validate.source = {
|
||||
code: sourceCode,
|
||||
patterns: patterns,
|
||||
defaults: defaults
|
||||
};
|
||||
}
|
||||
|
||||
return validate;
|
||||
}
|
||||
|
||||
function resolveRef(baseId, ref, isRoot) {
|
||||
ref = resolve.url(baseId, ref);
|
||||
var refIndex = refs[ref];
|
||||
var _refVal, refCode;
|
||||
if (refIndex !== undefined) {
|
||||
_refVal = refVal[refIndex];
|
||||
refCode = 'refVal[' + refIndex + ']';
|
||||
return resolvedRef(_refVal, refCode);
|
||||
}
|
||||
if (!isRoot && root.refs) {
|
||||
var rootRefId = root.refs[ref];
|
||||
if (rootRefId !== undefined) {
|
||||
_refVal = root.refVal[rootRefId];
|
||||
refCode = addLocalRef(ref, _refVal);
|
||||
return resolvedRef(_refVal, refCode);
|
||||
}
|
||||
}
|
||||
|
||||
refCode = addLocalRef(ref);
|
||||
var v = resolve.call(self, localCompile, root, ref);
|
||||
if (v === undefined) {
|
||||
var localSchema = localRefs && localRefs[ref];
|
||||
if (localSchema) {
|
||||
v = resolve.inlineRef(localSchema, opts.inlineRefs)
|
||||
? localSchema
|
||||
: compile.call(self, localSchema, root, localRefs, baseId);
|
||||
}
|
||||
}
|
||||
|
||||
if (v === undefined) {
|
||||
removeLocalRef(ref);
|
||||
} else {
|
||||
replaceLocalRef(ref, v);
|
||||
return resolvedRef(v, refCode);
|
||||
}
|
||||
}
|
||||
|
||||
function addLocalRef(ref, v) {
|
||||
var refId = refVal.length;
|
||||
refVal[refId] = v;
|
||||
refs[ref] = refId;
|
||||
return 'refVal' + refId;
|
||||
}
|
||||
|
||||
function removeLocalRef(ref) {
|
||||
delete refs[ref];
|
||||
}
|
||||
|
||||
function replaceLocalRef(ref, v) {
|
||||
var refId = refs[ref];
|
||||
refVal[refId] = v;
|
||||
}
|
||||
|
||||
function resolvedRef(refVal, code) {
|
||||
return typeof refVal == 'object' || typeof refVal == 'boolean'
|
||||
? { code: code, schema: refVal, inline: true }
|
||||
: { code: code, $async: refVal && !!refVal.$async };
|
||||
}
|
||||
|
||||
function usePattern(regexStr) {
|
||||
var index = patternsHash[regexStr];
|
||||
if (index === undefined) {
|
||||
index = patternsHash[regexStr] = patterns.length;
|
||||
patterns[index] = regexStr;
|
||||
}
|
||||
return 'pattern' + index;
|
||||
}
|
||||
|
||||
function useDefault(value) {
|
||||
switch (typeof value) {
|
||||
case 'boolean':
|
||||
case 'number':
|
||||
return '' + value;
|
||||
case 'string':
|
||||
return util.toQuotedString(value);
|
||||
case 'object':
|
||||
if (value === null) return 'null';
|
||||
var valueStr = stableStringify(value);
|
||||
var index = defaultsHash[valueStr];
|
||||
if (index === undefined) {
|
||||
index = defaultsHash[valueStr] = defaults.length;
|
||||
defaults[index] = value;
|
||||
}
|
||||
return 'default' + index;
|
||||
}
|
||||
}
|
||||
|
||||
function useCustomRule(rule, schema, parentSchema, it) {
|
||||
if (self._opts.validateSchema !== false) {
|
||||
var deps = rule.definition.dependencies;
|
||||
if (deps && !deps.every(function(keyword) {
|
||||
return Object.prototype.hasOwnProperty.call(parentSchema, keyword);
|
||||
}))
|
||||
throw new Error('parent schema must have all required keywords: ' + deps.join(','));
|
||||
|
||||
var validateSchema = rule.definition.validateSchema;
|
||||
if (validateSchema) {
|
||||
var valid = validateSchema(schema);
|
||||
if (!valid) {
|
||||
var message = 'keyword schema is invalid: ' + self.errorsText(validateSchema.errors);
|
||||
if (self._opts.validateSchema == 'log') self.logger.error(message);
|
||||
else throw new Error(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var compile = rule.definition.compile
|
||||
, inline = rule.definition.inline
|
||||
, macro = rule.definition.macro;
|
||||
|
||||
var validate;
|
||||
if (compile) {
|
||||
validate = compile.call(self, schema, parentSchema, it);
|
||||
} else if (macro) {
|
||||
validate = macro.call(self, schema, parentSchema, it);
|
||||
if (opts.validateSchema !== false) self.validateSchema(validate, true);
|
||||
} else if (inline) {
|
||||
validate = inline.call(self, it, rule.keyword, schema, parentSchema);
|
||||
} else {
|
||||
validate = rule.definition.validate;
|
||||
if (!validate) return;
|
||||
}
|
||||
|
||||
if (validate === undefined)
|
||||
throw new Error('custom keyword "' + rule.keyword + '"failed to compile');
|
||||
|
||||
var index = customRules.length;
|
||||
customRules[index] = validate;
|
||||
|
||||
return {
|
||||
code: 'customRule' + index,
|
||||
validate: validate
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks if the schema is currently compiled
|
||||
* @this Ajv
|
||||
* @param {Object} schema schema to compile
|
||||
* @param {Object} root root object
|
||||
* @param {String} baseId base schema ID
|
||||
* @return {Object} object with properties "index" (compilation index) and "compiling" (boolean)
|
||||
*/
|
||||
function checkCompiling(schema, root, baseId) {
|
||||
/* jshint validthis: true */
|
||||
var index = compIndex.call(this, schema, root, baseId);
|
||||
if (index >= 0) return { index: index, compiling: true };
|
||||
index = this._compilations.length;
|
||||
this._compilations[index] = {
|
||||
schema: schema,
|
||||
root: root,
|
||||
baseId: baseId
|
||||
};
|
||||
return { index: index, compiling: false };
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes the schema from the currently compiled list
|
||||
* @this Ajv
|
||||
* @param {Object} schema schema to compile
|
||||
* @param {Object} root root object
|
||||
* @param {String} baseId base schema ID
|
||||
*/
|
||||
function endCompiling(schema, root, baseId) {
|
||||
/* jshint validthis: true */
|
||||
var i = compIndex.call(this, schema, root, baseId);
|
||||
if (i >= 0) this._compilations.splice(i, 1);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Index of schema compilation in the currently compiled list
|
||||
* @this Ajv
|
||||
* @param {Object} schema schema to compile
|
||||
* @param {Object} root root object
|
||||
* @param {String} baseId base schema ID
|
||||
* @return {Integer} compilation index
|
||||
*/
|
||||
function compIndex(schema, root, baseId) {
|
||||
/* jshint validthis: true */
|
||||
for (var i=0; i<this._compilations.length; i++) {
|
||||
var c = this._compilations[i];
|
||||
if (c.schema == schema && c.root == root && c.baseId == baseId) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
function patternCode(i, patterns) {
|
||||
return 'var pattern' + i + ' = new RegExp(' + util.toQuotedString(patterns[i]) + ');';
|
||||
}
|
||||
|
||||
|
||||
function defaultCode(i) {
|
||||
return 'var default' + i + ' = defaults[' + i + '];';
|
||||
}
|
||||
|
||||
|
||||
function refValCode(i, refVal) {
|
||||
return refVal[i] === undefined ? '' : 'var refVal' + i + ' = refVal[' + i + '];';
|
||||
}
|
||||
|
||||
|
||||
function customRuleCode(i) {
|
||||
return 'var customRule' + i + ' = customRules[' + i + '];';
|
||||
}
|
||||
|
||||
|
||||
function vars(arr, statement) {
|
||||
if (!arr.length) return '';
|
||||
var code = '';
|
||||
for (var i=0; i<arr.length; i++)
|
||||
code += statement(i, arr);
|
||||
return code;
|
||||
}
|
||||
+270
@@ -0,0 +1,270 @@
|
||||
'use strict';
|
||||
|
||||
var URI = require('uri-js')
|
||||
, equal = require('fast-deep-equal')
|
||||
, util = require('./util')
|
||||
, SchemaObject = require('./schema_obj')
|
||||
, traverse = require('json-schema-traverse');
|
||||
|
||||
module.exports = resolve;
|
||||
|
||||
resolve.normalizeId = normalizeId;
|
||||
resolve.fullPath = getFullPath;
|
||||
resolve.url = resolveUrl;
|
||||
resolve.ids = resolveIds;
|
||||
resolve.inlineRef = inlineRef;
|
||||
resolve.schema = resolveSchema;
|
||||
|
||||
/**
|
||||
* [resolve and compile the references ($ref)]
|
||||
* @this Ajv
|
||||
* @param {Function} compile reference to schema compilation funciton (localCompile)
|
||||
* @param {Object} root object with information about the root schema for the current schema
|
||||
* @param {String} ref reference to resolve
|
||||
* @return {Object|Function} schema object (if the schema can be inlined) or validation function
|
||||
*/
|
||||
function resolve(compile, root, ref) {
|
||||
/* jshint validthis: true */
|
||||
var refVal = this._refs[ref];
|
||||
if (typeof refVal == 'string') {
|
||||
if (this._refs[refVal]) refVal = this._refs[refVal];
|
||||
else return resolve.call(this, compile, root, refVal);
|
||||
}
|
||||
|
||||
refVal = refVal || this._schemas[ref];
|
||||
if (refVal instanceof SchemaObject) {
|
||||
return inlineRef(refVal.schema, this._opts.inlineRefs)
|
||||
? refVal.schema
|
||||
: refVal.validate || this._compile(refVal);
|
||||
}
|
||||
|
||||
var res = resolveSchema.call(this, root, ref);
|
||||
var schema, v, baseId;
|
||||
if (res) {
|
||||
schema = res.schema;
|
||||
root = res.root;
|
||||
baseId = res.baseId;
|
||||
}
|
||||
|
||||
if (schema instanceof SchemaObject) {
|
||||
v = schema.validate || compile.call(this, schema.schema, root, undefined, baseId);
|
||||
} else if (schema !== undefined) {
|
||||
v = inlineRef(schema, this._opts.inlineRefs)
|
||||
? schema
|
||||
: compile.call(this, schema, root, undefined, baseId);
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Resolve schema, its root and baseId
|
||||
* @this Ajv
|
||||
* @param {Object} root root object with properties schema, refVal, refs
|
||||
* @param {String} ref reference to resolve
|
||||
* @return {Object} object with properties schema, root, baseId
|
||||
*/
|
||||
function resolveSchema(root, ref) {
|
||||
/* jshint validthis: true */
|
||||
var p = URI.parse(ref)
|
||||
, refPath = _getFullPath(p)
|
||||
, baseId = getFullPath(this._getId(root.schema));
|
||||
if (Object.keys(root.schema).length === 0 || refPath !== baseId) {
|
||||
var id = normalizeId(refPath);
|
||||
var refVal = this._refs[id];
|
||||
if (typeof refVal == 'string') {
|
||||
return resolveRecursive.call(this, root, refVal, p);
|
||||
} else if (refVal instanceof SchemaObject) {
|
||||
if (!refVal.validate) this._compile(refVal);
|
||||
root = refVal;
|
||||
} else {
|
||||
refVal = this._schemas[id];
|
||||
if (refVal instanceof SchemaObject) {
|
||||
if (!refVal.validate) this._compile(refVal);
|
||||
if (id == normalizeId(ref))
|
||||
return { schema: refVal, root: root, baseId: baseId };
|
||||
root = refVal;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!root.schema) return;
|
||||
baseId = getFullPath(this._getId(root.schema));
|
||||
}
|
||||
return getJsonPointer.call(this, p, baseId, root.schema, root);
|
||||
}
|
||||
|
||||
|
||||
/* @this Ajv */
|
||||
function resolveRecursive(root, ref, parsedRef) {
|
||||
/* jshint validthis: true */
|
||||
var res = resolveSchema.call(this, root, ref);
|
||||
if (res) {
|
||||
var schema = res.schema;
|
||||
var baseId = res.baseId;
|
||||
root = res.root;
|
||||
var id = this._getId(schema);
|
||||
if (id) baseId = resolveUrl(baseId, id);
|
||||
return getJsonPointer.call(this, parsedRef, baseId, schema, root);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var PREVENT_SCOPE_CHANGE = util.toHash(['properties', 'patternProperties', 'enum', 'dependencies', 'definitions']);
|
||||
/* @this Ajv */
|
||||
function getJsonPointer(parsedRef, baseId, schema, root) {
|
||||
/* jshint validthis: true */
|
||||
parsedRef.fragment = parsedRef.fragment || '';
|
||||
if (parsedRef.fragment.slice(0,1) != '/') return;
|
||||
var parts = parsedRef.fragment.split('/');
|
||||
|
||||
for (var i = 1; i < parts.length; i++) {
|
||||
var part = parts[i];
|
||||
if (part) {
|
||||
part = util.unescapeFragment(part);
|
||||
schema = schema[part];
|
||||
if (schema === undefined) break;
|
||||
var id;
|
||||
if (!PREVENT_SCOPE_CHANGE[part]) {
|
||||
id = this._getId(schema);
|
||||
if (id) baseId = resolveUrl(baseId, id);
|
||||
if (schema.$ref) {
|
||||
var $ref = resolveUrl(baseId, schema.$ref);
|
||||
var res = resolveSchema.call(this, root, $ref);
|
||||
if (res) {
|
||||
schema = res.schema;
|
||||
root = res.root;
|
||||
baseId = res.baseId;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (schema !== undefined && schema !== root.schema)
|
||||
return { schema: schema, root: root, baseId: baseId };
|
||||
}
|
||||
|
||||
|
||||
var SIMPLE_INLINED = util.toHash([
|
||||
'type', 'format', 'pattern',
|
||||
'maxLength', 'minLength',
|
||||
'maxProperties', 'minProperties',
|
||||
'maxItems', 'minItems',
|
||||
'maximum', 'minimum',
|
||||
'uniqueItems', 'multipleOf',
|
||||
'required', 'enum'
|
||||
]);
|
||||
function inlineRef(schema, limit) {
|
||||
if (limit === false) return false;
|
||||
if (limit === undefined || limit === true) return checkNoRef(schema);
|
||||
else if (limit) return countKeys(schema) <= limit;
|
||||
}
|
||||
|
||||
|
||||
function checkNoRef(schema) {
|
||||
var item;
|
||||
if (Array.isArray(schema)) {
|
||||
for (var i=0; i<schema.length; i++) {
|
||||
item = schema[i];
|
||||
if (typeof item == 'object' && !checkNoRef(item)) return false;
|
||||
}
|
||||
} else {
|
||||
for (var key in schema) {
|
||||
if (key == '$ref') return false;
|
||||
item = schema[key];
|
||||
if (typeof item == 'object' && !checkNoRef(item)) return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
function countKeys(schema) {
|
||||
var count = 0, item;
|
||||
if (Array.isArray(schema)) {
|
||||
for (var i=0; i<schema.length; i++) {
|
||||
item = schema[i];
|
||||
if (typeof item == 'object') count += countKeys(item);
|
||||
if (count == Infinity) return Infinity;
|
||||
}
|
||||
} else {
|
||||
for (var key in schema) {
|
||||
if (key == '$ref') return Infinity;
|
||||
if (SIMPLE_INLINED[key]) {
|
||||
count++;
|
||||
} else {
|
||||
item = schema[key];
|
||||
if (typeof item == 'object') count += countKeys(item) + 1;
|
||||
if (count == Infinity) return Infinity;
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
function getFullPath(id, normalize) {
|
||||
if (normalize !== false) id = normalizeId(id);
|
||||
var p = URI.parse(id);
|
||||
return _getFullPath(p);
|
||||
}
|
||||
|
||||
|
||||
function _getFullPath(p) {
|
||||
return URI.serialize(p).split('#')[0] + '#';
|
||||
}
|
||||
|
||||
|
||||
var TRAILING_SLASH_HASH = /#\/?$/;
|
||||
function normalizeId(id) {
|
||||
return id ? id.replace(TRAILING_SLASH_HASH, '') : '';
|
||||
}
|
||||
|
||||
|
||||
function resolveUrl(baseId, id) {
|
||||
id = normalizeId(id);
|
||||
return URI.resolve(baseId, id);
|
||||
}
|
||||
|
||||
|
||||
/* @this Ajv */
|
||||
function resolveIds(schema) {
|
||||
var schemaId = normalizeId(this._getId(schema));
|
||||
var baseIds = {'': schemaId};
|
||||
var fullPaths = {'': getFullPath(schemaId, false)};
|
||||
var localRefs = {};
|
||||
var self = this;
|
||||
|
||||
traverse(schema, {allKeys: true}, function(sch, jsonPtr, rootSchema, parentJsonPtr, parentKeyword, parentSchema, keyIndex) {
|
||||
if (jsonPtr === '') return;
|
||||
var id = self._getId(sch);
|
||||
var baseId = baseIds[parentJsonPtr];
|
||||
var fullPath = fullPaths[parentJsonPtr] + '/' + parentKeyword;
|
||||
if (keyIndex !== undefined)
|
||||
fullPath += '/' + (typeof keyIndex == 'number' ? keyIndex : util.escapeFragment(keyIndex));
|
||||
|
||||
if (typeof id == 'string') {
|
||||
id = baseId = normalizeId(baseId ? URI.resolve(baseId, id) : id);
|
||||
|
||||
var refVal = self._refs[id];
|
||||
if (typeof refVal == 'string') refVal = self._refs[refVal];
|
||||
if (refVal && refVal.schema) {
|
||||
if (!equal(sch, refVal.schema))
|
||||
throw new Error('id "' + id + '" resolves to more than one schema');
|
||||
} else if (id != normalizeId(fullPath)) {
|
||||
if (id[0] == '#') {
|
||||
if (localRefs[id] && !equal(sch, localRefs[id]))
|
||||
throw new Error('id "' + id + '" resolves to more than one schema');
|
||||
localRefs[id] = sch;
|
||||
} else {
|
||||
self._refs[id] = fullPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
baseIds[jsonPtr] = baseId;
|
||||
fullPaths[jsonPtr] = fullPath;
|
||||
});
|
||||
|
||||
return localRefs;
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
'use strict';
|
||||
|
||||
var ruleModules = require('../dotjs')
|
||||
, toHash = require('./util').toHash;
|
||||
|
||||
module.exports = function rules() {
|
||||
var RULES = [
|
||||
{ type: 'number',
|
||||
rules: [ { 'maximum': ['exclusiveMaximum'] },
|
||||
{ 'minimum': ['exclusiveMinimum'] }, 'multipleOf', 'format'] },
|
||||
{ type: 'string',
|
||||
rules: [ 'maxLength', 'minLength', 'pattern', 'format' ] },
|
||||
{ type: 'array',
|
||||
rules: [ 'maxItems', 'minItems', 'items', 'contains', 'uniqueItems' ] },
|
||||
{ type: 'object',
|
||||
rules: [ 'maxProperties', 'minProperties', 'required', 'dependencies', 'propertyNames',
|
||||
{ 'properties': ['additionalProperties', 'patternProperties'] } ] },
|
||||
{ rules: [ '$ref', 'const', 'enum', 'not', 'anyOf', 'oneOf', 'allOf', 'if' ] }
|
||||
];
|
||||
|
||||
var ALL = [ 'type', '$comment' ];
|
||||
var KEYWORDS = [
|
||||
'$schema', '$id', 'id', '$data', '$async', 'title',
|
||||
'description', 'default', 'definitions',
|
||||
'examples', 'readOnly', 'writeOnly',
|
||||
'contentMediaType', 'contentEncoding',
|
||||
'additionalItems', 'then', 'else'
|
||||
];
|
||||
var TYPES = [ 'number', 'integer', 'string', 'array', 'object', 'boolean', 'null' ];
|
||||
RULES.all = toHash(ALL);
|
||||
RULES.types = toHash(TYPES);
|
||||
|
||||
RULES.forEach(function (group) {
|
||||
group.rules = group.rules.map(function (keyword) {
|
||||
var implKeywords;
|
||||
if (typeof keyword == 'object') {
|
||||
var key = Object.keys(keyword)[0];
|
||||
implKeywords = keyword[key];
|
||||
keyword = key;
|
||||
implKeywords.forEach(function (k) {
|
||||
ALL.push(k);
|
||||
RULES.all[k] = true;
|
||||
});
|
||||
}
|
||||
ALL.push(keyword);
|
||||
var rule = RULES.all[keyword] = {
|
||||
keyword: keyword,
|
||||
code: ruleModules[keyword],
|
||||
implements: implKeywords
|
||||
};
|
||||
return rule;
|
||||
});
|
||||
|
||||
RULES.all.$comment = {
|
||||
keyword: '$comment',
|
||||
code: ruleModules.$comment
|
||||
};
|
||||
|
||||
if (group.type) RULES.types[group.type] = group;
|
||||
});
|
||||
|
||||
RULES.keywords = toHash(ALL.concat(KEYWORDS));
|
||||
RULES.custom = {};
|
||||
|
||||
return RULES;
|
||||
};
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
'use strict';
|
||||
|
||||
var util = require('./util');
|
||||
|
||||
module.exports = SchemaObject;
|
||||
|
||||
function SchemaObject(obj) {
|
||||
util.copy(obj, this);
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
'use strict';
|
||||
|
||||
// https://mathiasbynens.be/notes/javascript-encoding
|
||||
// https://github.com/bestiejs/punycode.js - punycode.ucs2.decode
|
||||
module.exports = function ucs2length(str) {
|
||||
var length = 0
|
||||
, len = str.length
|
||||
, pos = 0
|
||||
, value;
|
||||
while (pos < len) {
|
||||
length++;
|
||||
value = str.charCodeAt(pos++);
|
||||
if (value >= 0xD800 && value <= 0xDBFF && pos < len) {
|
||||
// high surrogate, and there is a next character
|
||||
value = str.charCodeAt(pos);
|
||||
if ((value & 0xFC00) == 0xDC00) pos++; // low surrogate
|
||||
}
|
||||
}
|
||||
return length;
|
||||
};
|
||||
+239
@@ -0,0 +1,239 @@
|
||||
'use strict';
|
||||
|
||||
|
||||
module.exports = {
|
||||
copy: copy,
|
||||
checkDataType: checkDataType,
|
||||
checkDataTypes: checkDataTypes,
|
||||
coerceToTypes: coerceToTypes,
|
||||
toHash: toHash,
|
||||
getProperty: getProperty,
|
||||
escapeQuotes: escapeQuotes,
|
||||
equal: require('fast-deep-equal'),
|
||||
ucs2length: require('./ucs2length'),
|
||||
varOccurences: varOccurences,
|
||||
varReplace: varReplace,
|
||||
schemaHasRules: schemaHasRules,
|
||||
schemaHasRulesExcept: schemaHasRulesExcept,
|
||||
schemaUnknownRules: schemaUnknownRules,
|
||||
toQuotedString: toQuotedString,
|
||||
getPathExpr: getPathExpr,
|
||||
getPath: getPath,
|
||||
getData: getData,
|
||||
unescapeFragment: unescapeFragment,
|
||||
unescapeJsonPointer: unescapeJsonPointer,
|
||||
escapeFragment: escapeFragment,
|
||||
escapeJsonPointer: escapeJsonPointer
|
||||
};
|
||||
|
||||
|
||||
function copy(o, to) {
|
||||
to = to || {};
|
||||
for (var key in o) to[key] = o[key];
|
||||
return to;
|
||||
}
|
||||
|
||||
|
||||
function checkDataType(dataType, data, strictNumbers, negate) {
|
||||
var EQUAL = negate ? ' !== ' : ' === '
|
||||
, AND = negate ? ' || ' : ' && '
|
||||
, OK = negate ? '!' : ''
|
||||
, NOT = negate ? '' : '!';
|
||||
switch (dataType) {
|
||||
case 'null': return data + EQUAL + 'null';
|
||||
case 'array': return OK + 'Array.isArray(' + data + ')';
|
||||
case 'object': return '(' + OK + data + AND +
|
||||
'typeof ' + data + EQUAL + '"object"' + AND +
|
||||
NOT + 'Array.isArray(' + data + '))';
|
||||
case 'integer': return '(typeof ' + data + EQUAL + '"number"' + AND +
|
||||
NOT + '(' + data + ' % 1)' +
|
||||
AND + data + EQUAL + data +
|
||||
(strictNumbers ? (AND + OK + 'isFinite(' + data + ')') : '') + ')';
|
||||
case 'number': return '(typeof ' + data + EQUAL + '"' + dataType + '"' +
|
||||
(strictNumbers ? (AND + OK + 'isFinite(' + data + ')') : '') + ')';
|
||||
default: return 'typeof ' + data + EQUAL + '"' + dataType + '"';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function checkDataTypes(dataTypes, data, strictNumbers) {
|
||||
switch (dataTypes.length) {
|
||||
case 1: return checkDataType(dataTypes[0], data, strictNumbers, true);
|
||||
default:
|
||||
var code = '';
|
||||
var types = toHash(dataTypes);
|
||||
if (types.array && types.object) {
|
||||
code = types.null ? '(': '(!' + data + ' || ';
|
||||
code += 'typeof ' + data + ' !== "object")';
|
||||
delete types.null;
|
||||
delete types.array;
|
||||
delete types.object;
|
||||
}
|
||||
if (types.number) delete types.integer;
|
||||
for (var t in types)
|
||||
code += (code ? ' && ' : '' ) + checkDataType(t, data, strictNumbers, true);
|
||||
|
||||
return code;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var COERCE_TO_TYPES = toHash([ 'string', 'number', 'integer', 'boolean', 'null' ]);
|
||||
function coerceToTypes(optionCoerceTypes, dataTypes) {
|
||||
if (Array.isArray(dataTypes)) {
|
||||
var types = [];
|
||||
for (var i=0; i<dataTypes.length; i++) {
|
||||
var t = dataTypes[i];
|
||||
if (COERCE_TO_TYPES[t]) types[types.length] = t;
|
||||
else if (optionCoerceTypes === 'array' && t === 'array') types[types.length] = t;
|
||||
}
|
||||
if (types.length) return types;
|
||||
} else if (COERCE_TO_TYPES[dataTypes]) {
|
||||
return [dataTypes];
|
||||
} else if (optionCoerceTypes === 'array' && dataTypes === 'array') {
|
||||
return ['array'];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function toHash(arr) {
|
||||
var hash = {};
|
||||
for (var i=0; i<arr.length; i++) hash[arr[i]] = true;
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
||||
var IDENTIFIER = /^[a-z$_][a-z$_0-9]*$/i;
|
||||
var SINGLE_QUOTE = /'|\\/g;
|
||||
function getProperty(key) {
|
||||
return typeof key == 'number'
|
||||
? '[' + key + ']'
|
||||
: IDENTIFIER.test(key)
|
||||
? '.' + key
|
||||
: "['" + escapeQuotes(key) + "']";
|
||||
}
|
||||
|
||||
|
||||
function escapeQuotes(str) {
|
||||
return str.replace(SINGLE_QUOTE, '\\$&')
|
||||
.replace(/\n/g, '\\n')
|
||||
.replace(/\r/g, '\\r')
|
||||
.replace(/\f/g, '\\f')
|
||||
.replace(/\t/g, '\\t');
|
||||
}
|
||||
|
||||
|
||||
function varOccurences(str, dataVar) {
|
||||
dataVar += '[^0-9]';
|
||||
var matches = str.match(new RegExp(dataVar, 'g'));
|
||||
return matches ? matches.length : 0;
|
||||
}
|
||||
|
||||
|
||||
function varReplace(str, dataVar, expr) {
|
||||
dataVar += '([^0-9])';
|
||||
expr = expr.replace(/\$/g, '$$$$');
|
||||
return str.replace(new RegExp(dataVar, 'g'), expr + '$1');
|
||||
}
|
||||
|
||||
|
||||
function schemaHasRules(schema, rules) {
|
||||
if (typeof schema == 'boolean') return !schema;
|
||||
for (var key in schema) if (rules[key]) return true;
|
||||
}
|
||||
|
||||
|
||||
function schemaHasRulesExcept(schema, rules, exceptKeyword) {
|
||||
if (typeof schema == 'boolean') return !schema && exceptKeyword != 'not';
|
||||
for (var key in schema) if (key != exceptKeyword && rules[key]) return true;
|
||||
}
|
||||
|
||||
|
||||
function schemaUnknownRules(schema, rules) {
|
||||
if (typeof schema == 'boolean') return;
|
||||
for (var key in schema) if (!rules[key]) return key;
|
||||
}
|
||||
|
||||
|
||||
function toQuotedString(str) {
|
||||
return '\'' + escapeQuotes(str) + '\'';
|
||||
}
|
||||
|
||||
|
||||
function getPathExpr(currentPath, expr, jsonPointers, isNumber) {
|
||||
var path = jsonPointers // false by default
|
||||
? '\'/\' + ' + expr + (isNumber ? '' : '.replace(/~/g, \'~0\').replace(/\\//g, \'~1\')')
|
||||
: (isNumber ? '\'[\' + ' + expr + ' + \']\'' : '\'[\\\'\' + ' + expr + ' + \'\\\']\'');
|
||||
return joinPaths(currentPath, path);
|
||||
}
|
||||
|
||||
|
||||
function getPath(currentPath, prop, jsonPointers) {
|
||||
var path = jsonPointers // false by default
|
||||
? toQuotedString('/' + escapeJsonPointer(prop))
|
||||
: toQuotedString(getProperty(prop));
|
||||
return joinPaths(currentPath, path);
|
||||
}
|
||||
|
||||
|
||||
var JSON_POINTER = /^\/(?:[^~]|~0|~1)*$/;
|
||||
var RELATIVE_JSON_POINTER = /^([0-9]+)(#|\/(?:[^~]|~0|~1)*)?$/;
|
||||
function getData($data, lvl, paths) {
|
||||
var up, jsonPointer, data, matches;
|
||||
if ($data === '') return 'rootData';
|
||||
if ($data[0] == '/') {
|
||||
if (!JSON_POINTER.test($data)) throw new Error('Invalid JSON-pointer: ' + $data);
|
||||
jsonPointer = $data;
|
||||
data = 'rootData';
|
||||
} else {
|
||||
matches = $data.match(RELATIVE_JSON_POINTER);
|
||||
if (!matches) throw new Error('Invalid JSON-pointer: ' + $data);
|
||||
up = +matches[1];
|
||||
jsonPointer = matches[2];
|
||||
if (jsonPointer == '#') {
|
||||
if (up >= lvl) throw new Error('Cannot access property/index ' + up + ' levels up, current level is ' + lvl);
|
||||
return paths[lvl - up];
|
||||
}
|
||||
|
||||
if (up > lvl) throw new Error('Cannot access data ' + up + ' levels up, current level is ' + lvl);
|
||||
data = 'data' + ((lvl - up) || '');
|
||||
if (!jsonPointer) return data;
|
||||
}
|
||||
|
||||
var expr = data;
|
||||
var segments = jsonPointer.split('/');
|
||||
for (var i=0; i<segments.length; i++) {
|
||||
var segment = segments[i];
|
||||
if (segment) {
|
||||
data += getProperty(unescapeJsonPointer(segment));
|
||||
expr += ' && ' + data;
|
||||
}
|
||||
}
|
||||
return expr;
|
||||
}
|
||||
|
||||
|
||||
function joinPaths (a, b) {
|
||||
if (a == '""') return b;
|
||||
return (a + ' + ' + b).replace(/([^\\])' \+ '/g, '$1');
|
||||
}
|
||||
|
||||
|
||||
function unescapeFragment(str) {
|
||||
return unescapeJsonPointer(decodeURIComponent(str));
|
||||
}
|
||||
|
||||
|
||||
function escapeFragment(str) {
|
||||
return encodeURIComponent(escapeJsonPointer(str));
|
||||
}
|
||||
|
||||
|
||||
function escapeJsonPointer(str) {
|
||||
return str.replace(/~/g, '~0').replace(/\//g, '~1');
|
||||
}
|
||||
|
||||
|
||||
function unescapeJsonPointer(str) {
|
||||
return str.replace(/~1/g, '/').replace(/~0/g, '~');
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
'use strict';
|
||||
|
||||
var KEYWORDS = [
|
||||
'multipleOf',
|
||||
'maximum',
|
||||
'exclusiveMaximum',
|
||||
'minimum',
|
||||
'exclusiveMinimum',
|
||||
'maxLength',
|
||||
'minLength',
|
||||
'pattern',
|
||||
'additionalItems',
|
||||
'maxItems',
|
||||
'minItems',
|
||||
'uniqueItems',
|
||||
'maxProperties',
|
||||
'minProperties',
|
||||
'required',
|
||||
'additionalProperties',
|
||||
'enum',
|
||||
'format',
|
||||
'const'
|
||||
];
|
||||
|
||||
module.exports = function (metaSchema, keywordsJsonPointers) {
|
||||
for (var i=0; i<keywordsJsonPointers.length; i++) {
|
||||
metaSchema = JSON.parse(JSON.stringify(metaSchema));
|
||||
var segments = keywordsJsonPointers[i].split('/');
|
||||
var keywords = metaSchema;
|
||||
var j;
|
||||
for (j=1; j<segments.length; j++)
|
||||
keywords = keywords[segments[j]];
|
||||
|
||||
for (j=0; j<KEYWORDS.length; j++) {
|
||||
var key = KEYWORDS[j];
|
||||
var schema = keywords[key];
|
||||
if (schema) {
|
||||
keywords[key] = {
|
||||
anyOf: [
|
||||
schema,
|
||||
{ $ref: 'https://raw.githubusercontent.com/ajv-validator/ajv/master/lib/refs/data.json#' }
|
||||
]
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return metaSchema;
|
||||
};
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
'use strict';
|
||||
|
||||
var metaSchema = require('./refs/json-schema-draft-07.json');
|
||||
|
||||
module.exports = {
|
||||
$id: 'https://github.com/ajv-validator/ajv/blob/master/lib/definition_schema.js',
|
||||
definitions: {
|
||||
simpleTypes: metaSchema.definitions.simpleTypes
|
||||
},
|
||||
type: 'object',
|
||||
dependencies: {
|
||||
schema: ['validate'],
|
||||
$data: ['validate'],
|
||||
statements: ['inline'],
|
||||
valid: {not: {required: ['macro']}}
|
||||
},
|
||||
properties: {
|
||||
type: metaSchema.properties.type,
|
||||
schema: {type: 'boolean'},
|
||||
statements: {type: 'boolean'},
|
||||
dependencies: {
|
||||
type: 'array',
|
||||
items: {type: 'string'}
|
||||
},
|
||||
metaSchema: {type: 'object'},
|
||||
modifying: {type: 'boolean'},
|
||||
valid: {type: 'boolean'},
|
||||
$data: {type: 'boolean'},
|
||||
async: {type: 'boolean'},
|
||||
errors: {
|
||||
anyOf: [
|
||||
{type: 'boolean'},
|
||||
{const: 'full'}
|
||||
]
|
||||
}
|
||||
}
|
||||
};
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
{{# def.definitions }}
|
||||
{{# def.errors }}
|
||||
{{# def.setupKeyword }}
|
||||
{{# def.$data }}
|
||||
|
||||
{{## def.setExclusiveLimit:
|
||||
$exclusive = true;
|
||||
$errorKeyword = $exclusiveKeyword;
|
||||
$errSchemaPath = it.errSchemaPath + '/' + $exclusiveKeyword;
|
||||
#}}
|
||||
|
||||
{{
|
||||
var $isMax = $keyword == 'maximum'
|
||||
, $exclusiveKeyword = $isMax ? 'exclusiveMaximum' : 'exclusiveMinimum'
|
||||
, $schemaExcl = it.schema[$exclusiveKeyword]
|
||||
, $isDataExcl = it.opts.$data && $schemaExcl && $schemaExcl.$data
|
||||
, $op = $isMax ? '<' : '>'
|
||||
, $notOp = $isMax ? '>' : '<'
|
||||
, $errorKeyword = undefined;
|
||||
|
||||
if (!($isData || typeof $schema == 'number' || $schema === undefined)) {
|
||||
throw new Error($keyword + ' must be number');
|
||||
}
|
||||
if (!($isDataExcl || $schemaExcl === undefined
|
||||
|| typeof $schemaExcl == 'number'
|
||||
|| typeof $schemaExcl == 'boolean')) {
|
||||
throw new Error($exclusiveKeyword + ' must be number or boolean');
|
||||
}
|
||||
}}
|
||||
|
||||
{{? $isDataExcl }}
|
||||
{{
|
||||
var $schemaValueExcl = it.util.getData($schemaExcl.$data, $dataLvl, it.dataPathArr)
|
||||
, $exclusive = 'exclusive' + $lvl
|
||||
, $exclType = 'exclType' + $lvl
|
||||
, $exclIsNumber = 'exclIsNumber' + $lvl
|
||||
, $opExpr = 'op' + $lvl
|
||||
, $opStr = '\' + ' + $opExpr + ' + \'';
|
||||
}}
|
||||
var schemaExcl{{=$lvl}} = {{=$schemaValueExcl}};
|
||||
{{ $schemaValueExcl = 'schemaExcl' + $lvl; }}
|
||||
|
||||
var {{=$exclusive}};
|
||||
var {{=$exclType}} = typeof {{=$schemaValueExcl}};
|
||||
if ({{=$exclType}} != 'boolean' && {{=$exclType}} != 'undefined' && {{=$exclType}} != 'number') {
|
||||
{{ var $errorKeyword = $exclusiveKeyword; }}
|
||||
{{# def.error:'_exclusiveLimit' }}
|
||||
} else if ({{# def.$dataNotType:'number' }}
|
||||
{{=$exclType}} == 'number'
|
||||
? (
|
||||
({{=$exclusive}} = {{=$schemaValue}} === undefined || {{=$schemaValueExcl}} {{=$op}}= {{=$schemaValue}})
|
||||
? {{=$data}} {{=$notOp}}= {{=$schemaValueExcl}}
|
||||
: {{=$data}} {{=$notOp}} {{=$schemaValue}}
|
||||
)
|
||||
: (
|
||||
({{=$exclusive}} = {{=$schemaValueExcl}} === true)
|
||||
? {{=$data}} {{=$notOp}}= {{=$schemaValue}}
|
||||
: {{=$data}} {{=$notOp}} {{=$schemaValue}}
|
||||
)
|
||||
|| {{=$data}} !== {{=$data}}) {
|
||||
var op{{=$lvl}} = {{=$exclusive}} ? '{{=$op}}' : '{{=$op}}=';
|
||||
{{
|
||||
if ($schema === undefined) {
|
||||
$errorKeyword = $exclusiveKeyword;
|
||||
$errSchemaPath = it.errSchemaPath + '/' + $exclusiveKeyword;
|
||||
$schemaValue = $schemaValueExcl;
|
||||
$isData = $isDataExcl;
|
||||
}
|
||||
}}
|
||||
{{??}}
|
||||
{{
|
||||
var $exclIsNumber = typeof $schemaExcl == 'number'
|
||||
, $opStr = $op; /*used in error*/
|
||||
}}
|
||||
|
||||
{{? $exclIsNumber && $isData }}
|
||||
{{ var $opExpr = '\'' + $opStr + '\''; /*used in error*/ }}
|
||||
if ({{# def.$dataNotType:'number' }}
|
||||
( {{=$schemaValue}} === undefined
|
||||
|| {{=$schemaExcl}} {{=$op}}= {{=$schemaValue}}
|
||||
? {{=$data}} {{=$notOp}}= {{=$schemaExcl}}
|
||||
: {{=$data}} {{=$notOp}} {{=$schemaValue}} )
|
||||
|| {{=$data}} !== {{=$data}}) {
|
||||
{{??}}
|
||||
{{
|
||||
if ($exclIsNumber && $schema === undefined) {
|
||||
{{# def.setExclusiveLimit }}
|
||||
$schemaValue = $schemaExcl;
|
||||
$notOp += '=';
|
||||
} else {
|
||||
if ($exclIsNumber)
|
||||
$schemaValue = Math[$isMax ? 'min' : 'max']($schemaExcl, $schema);
|
||||
|
||||
if ($schemaExcl === ($exclIsNumber ? $schemaValue : true)) {
|
||||
{{# def.setExclusiveLimit }}
|
||||
$notOp += '=';
|
||||
} else {
|
||||
$exclusive = false;
|
||||
$opStr += '=';
|
||||
}
|
||||
}
|
||||
|
||||
var $opExpr = '\'' + $opStr + '\''; /*used in error*/
|
||||
}}
|
||||
|
||||
if ({{# def.$dataNotType:'number' }}
|
||||
{{=$data}} {{=$notOp}} {{=$schemaValue}}
|
||||
|| {{=$data}} !== {{=$data}}) {
|
||||
{{?}}
|
||||
{{?}}
|
||||
{{ $errorKeyword = $errorKeyword || $keyword; }}
|
||||
{{# def.error:'_limit' }}
|
||||
} {{? $breakOnError }} else { {{?}}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
{{# def.definitions }}
|
||||
{{# def.errors }}
|
||||
{{# def.setupKeyword }}
|
||||
{{# def.$data }}
|
||||
|
||||
{{# def.numberKeyword }}
|
||||
|
||||
{{ var $op = $keyword == 'maxItems' ? '>' : '<'; }}
|
||||
if ({{# def.$dataNotType:'number' }} {{=$data}}.length {{=$op}} {{=$schemaValue}}) {
|
||||
{{ var $errorKeyword = $keyword; }}
|
||||
{{# def.error:'_limitItems' }}
|
||||
} {{? $breakOnError }} else { {{?}}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
{{# def.definitions }}
|
||||
{{# def.errors }}
|
||||
{{# def.setupKeyword }}
|
||||
{{# def.$data }}
|
||||
|
||||
{{# def.numberKeyword }}
|
||||
|
||||
{{ var $op = $keyword == 'maxLength' ? '>' : '<'; }}
|
||||
if ({{# def.$dataNotType:'number' }} {{# def.strLength }} {{=$op}} {{=$schemaValue}}) {
|
||||
{{ var $errorKeyword = $keyword; }}
|
||||
{{# def.error:'_limitLength' }}
|
||||
} {{? $breakOnError }} else { {{?}}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
{{# def.definitions }}
|
||||
{{# def.errors }}
|
||||
{{# def.setupKeyword }}
|
||||
{{# def.$data }}
|
||||
|
||||
{{# def.numberKeyword }}
|
||||
|
||||
{{ var $op = $keyword == 'maxProperties' ? '>' : '<'; }}
|
||||
if ({{# def.$dataNotType:'number' }} Object.keys({{=$data}}).length {{=$op}} {{=$schemaValue}}) {
|
||||
{{ var $errorKeyword = $keyword; }}
|
||||
{{# def.error:'_limitProperties' }}
|
||||
} {{? $breakOnError }} else { {{?}}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
{{# def.definitions }}
|
||||
{{# def.errors }}
|
||||
{{# def.setupKeyword }}
|
||||
{{# def.setupNextLevel }}
|
||||
|
||||
{{
|
||||
var $currentBaseId = $it.baseId
|
||||
, $allSchemasEmpty = true;
|
||||
}}
|
||||
|
||||
{{~ $schema:$sch:$i }}
|
||||
{{? {{# def.nonEmptySchema:$sch }} }}
|
||||
{{
|
||||
$allSchemasEmpty = false;
|
||||
$it.schema = $sch;
|
||||
$it.schemaPath = $schemaPath + '[' + $i + ']';
|
||||
$it.errSchemaPath = $errSchemaPath + '/' + $i;
|
||||
}}
|
||||
|
||||
{{# def.insertSubschemaCode }}
|
||||
|
||||
{{# def.ifResultValid }}
|
||||
{{?}}
|
||||
{{~}}
|
||||
|
||||
{{? $breakOnError }}
|
||||
{{? $allSchemasEmpty }}
|
||||
if (true) {
|
||||
{{??}}
|
||||
{{= $closingBraces.slice(0,-1) }}
|
||||
{{?}}
|
||||
{{?}}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
{{# def.definitions }}
|
||||
{{# def.errors }}
|
||||
{{# def.setupKeyword }}
|
||||
{{# def.setupNextLevel }}
|
||||
|
||||
{{
|
||||
var $noEmptySchema = $schema.every(function($sch) {
|
||||
return {{# def.nonEmptySchema:$sch }};
|
||||
});
|
||||
}}
|
||||
{{? $noEmptySchema }}
|
||||
{{ var $currentBaseId = $it.baseId; }}
|
||||
var {{=$errs}} = errors;
|
||||
var {{=$valid}} = false;
|
||||
|
||||
{{# def.setCompositeRule }}
|
||||
|
||||
{{~ $schema:$sch:$i }}
|
||||
{{
|
||||
$it.schema = $sch;
|
||||
$it.schemaPath = $schemaPath + '[' + $i + ']';
|
||||
$it.errSchemaPath = $errSchemaPath + '/' + $i;
|
||||
}}
|
||||
|
||||
{{# def.insertSubschemaCode }}
|
||||
|
||||
{{=$valid}} = {{=$valid}} || {{=$nextValid}};
|
||||
|
||||
if (!{{=$valid}}) {
|
||||
{{ $closingBraces += '}'; }}
|
||||
{{~}}
|
||||
|
||||
{{# def.resetCompositeRule }}
|
||||
|
||||
{{= $closingBraces }}
|
||||
|
||||
if (!{{=$valid}}) {
|
||||
{{# def.extraError:'anyOf' }}
|
||||
} else {
|
||||
{{# def.resetErrors }}
|
||||
{{? it.opts.allErrors }} } {{?}}
|
||||
{{??}}
|
||||
{{? $breakOnError }}
|
||||
if (true) {
|
||||
{{?}}
|
||||
{{?}}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
{{## def.coerceType:
|
||||
{{
|
||||
var $dataType = 'dataType' + $lvl
|
||||
, $coerced = 'coerced' + $lvl;
|
||||
}}
|
||||
var {{=$dataType}} = typeof {{=$data}};
|
||||
var {{=$coerced}} = undefined;
|
||||
|
||||
{{? it.opts.coerceTypes == 'array' }}
|
||||
if ({{=$dataType}} == 'object' && Array.isArray({{=$data}}) && {{=$data}}.length == 1) {
|
||||
{{=$data}} = {{=$data}}[0];
|
||||
{{=$dataType}} = typeof {{=$data}};
|
||||
if ({{=it.util.checkDataType(it.schema.type, $data, it.opts.strictNumbers)}}) {{=$coerced}} = {{=$data}};
|
||||
}
|
||||
{{?}}
|
||||
|
||||
if ({{=$coerced}} !== undefined) ;
|
||||
{{~ $coerceToTypes:$type:$i }}
|
||||
{{? $type == 'string' }}
|
||||
else if ({{=$dataType}} == 'number' || {{=$dataType}} == 'boolean')
|
||||
{{=$coerced}} = '' + {{=$data}};
|
||||
else if ({{=$data}} === null) {{=$coerced}} = '';
|
||||
{{?? $type == 'number' || $type == 'integer' }}
|
||||
else if ({{=$dataType}} == 'boolean' || {{=$data}} === null
|
||||
|| ({{=$dataType}} == 'string' && {{=$data}} && {{=$data}} == +{{=$data}}
|
||||
{{? $type == 'integer' }} && !({{=$data}} % 1){{?}}))
|
||||
{{=$coerced}} = +{{=$data}};
|
||||
{{?? $type == 'boolean' }}
|
||||
else if ({{=$data}} === 'false' || {{=$data}} === 0 || {{=$data}} === null)
|
||||
{{=$coerced}} = false;
|
||||
else if ({{=$data}} === 'true' || {{=$data}} === 1)
|
||||
{{=$coerced}} = true;
|
||||
{{?? $type == 'null' }}
|
||||
else if ({{=$data}} === '' || {{=$data}} === 0 || {{=$data}} === false)
|
||||
{{=$coerced}} = null;
|
||||
{{?? it.opts.coerceTypes == 'array' && $type == 'array' }}
|
||||
else if ({{=$dataType}} == 'string' || {{=$dataType}} == 'number' || {{=$dataType}} == 'boolean' || {{=$data}} == null)
|
||||
{{=$coerced}} = [{{=$data}}];
|
||||
{{?}}
|
||||
{{~}}
|
||||
else {
|
||||
{{# def.error:'type' }}
|
||||
}
|
||||
|
||||
if ({{=$coerced}} !== undefined) {
|
||||
{{# def.setParentData }}
|
||||
{{=$data}} = {{=$coerced}};
|
||||
{{? !$dataLvl }}if ({{=$parentData}} !== undefined){{?}}
|
||||
{{=$parentData}}[{{=$parentDataProperty}}] = {{=$coerced}};
|
||||
}
|
||||
#}}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
{{# def.definitions }}
|
||||
{{# def.setupKeyword }}
|
||||
|
||||
{{ var $comment = it.util.toQuotedString($schema); }}
|
||||
{{? it.opts.$comment === true }}
|
||||
console.log({{=$comment}});
|
||||
{{?? typeof it.opts.$comment == 'function' }}
|
||||
self._opts.$comment({{=$comment}}, {{=it.util.toQuotedString($errSchemaPath)}}, validate.root.schema);
|
||||
{{?}}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
{{# def.definitions }}
|
||||
{{# def.errors }}
|
||||
{{# def.setupKeyword }}
|
||||
{{# def.$data }}
|
||||
|
||||
{{? !$isData }}
|
||||
var schema{{=$lvl}} = validate.schema{{=$schemaPath}};
|
||||
{{?}}
|
||||
var {{=$valid}} = equal({{=$data}}, schema{{=$lvl}});
|
||||
{{# def.checkError:'const' }}
|
||||
{{? $breakOnError }} else { {{?}}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
{{# def.definitions }}
|
||||
{{# def.errors }}
|
||||
{{# def.setupKeyword }}
|
||||
{{# def.setupNextLevel }}
|
||||
|
||||
|
||||
{{
|
||||
var $idx = 'i' + $lvl
|
||||
, $dataNxt = $it.dataLevel = it.dataLevel + 1
|
||||
, $nextData = 'data' + $dataNxt
|
||||
, $currentBaseId = it.baseId
|
||||
, $nonEmptySchema = {{# def.nonEmptySchema:$schema }};
|
||||
}}
|
||||
|
||||
var {{=$errs}} = errors;
|
||||
var {{=$valid}};
|
||||
|
||||
{{? $nonEmptySchema }}
|
||||
{{# def.setCompositeRule }}
|
||||
|
||||
{{
|
||||
$it.schema = $schema;
|
||||
$it.schemaPath = $schemaPath;
|
||||
$it.errSchemaPath = $errSchemaPath;
|
||||
}}
|
||||
|
||||
var {{=$nextValid}} = false;
|
||||
|
||||
for (var {{=$idx}} = 0; {{=$idx}} < {{=$data}}.length; {{=$idx}}++) {
|
||||
{{
|
||||
$it.errorPath = it.util.getPathExpr(it.errorPath, $idx, it.opts.jsonPointers, true);
|
||||
var $passData = $data + '[' + $idx + ']';
|
||||
$it.dataPathArr[$dataNxt] = $idx;
|
||||
}}
|
||||
|
||||
{{# def.generateSubschemaCode }}
|
||||
{{# def.optimizeValidate }}
|
||||
|
||||
if ({{=$nextValid}}) break;
|
||||
}
|
||||
|
||||
{{# def.resetCompositeRule }}
|
||||
{{= $closingBraces }}
|
||||
|
||||
if (!{{=$nextValid}}) {
|
||||
{{??}}
|
||||
if ({{=$data}}.length == 0) {
|
||||
{{?}}
|
||||
|
||||
{{# def.error:'contains' }}
|
||||
} else {
|
||||
{{? $nonEmptySchema }}
|
||||
{{# def.resetErrors }}
|
||||
{{?}}
|
||||
{{? it.opts.allErrors }} } {{?}}
|
||||
+191
@@ -0,0 +1,191 @@
|
||||
{{# def.definitions }}
|
||||
{{# def.errors }}
|
||||
{{# def.setupKeyword }}
|
||||
{{# def.$data }}
|
||||
|
||||
{{
|
||||
var $rule = this
|
||||
, $definition = 'definition' + $lvl
|
||||
, $rDef = $rule.definition
|
||||
, $closingBraces = '';
|
||||
var $validate = $rDef.validate;
|
||||
var $compile, $inline, $macro, $ruleValidate, $validateCode;
|
||||
}}
|
||||
|
||||
{{? $isData && $rDef.$data }}
|
||||
{{
|
||||
$validateCode = 'keywordValidate' + $lvl;
|
||||
var $validateSchema = $rDef.validateSchema;
|
||||
}}
|
||||
var {{=$definition}} = RULES.custom['{{=$keyword}}'].definition;
|
||||
var {{=$validateCode}} = {{=$definition}}.validate;
|
||||
{{??}}
|
||||
{{
|
||||
$ruleValidate = it.useCustomRule($rule, $schema, it.schema, it);
|
||||
if (!$ruleValidate) return;
|
||||
$schemaValue = 'validate.schema' + $schemaPath;
|
||||
$validateCode = $ruleValidate.code;
|
||||
$compile = $rDef.compile;
|
||||
$inline = $rDef.inline;
|
||||
$macro = $rDef.macro;
|
||||
}}
|
||||
{{?}}
|
||||
|
||||
{{
|
||||
var $ruleErrs = $validateCode + '.errors'
|
||||
, $i = 'i' + $lvl
|
||||
, $ruleErr = 'ruleErr' + $lvl
|
||||
, $asyncKeyword = $rDef.async;
|
||||
|
||||
if ($asyncKeyword && !it.async)
|
||||
throw new Error('async keyword in sync schema');
|
||||
}}
|
||||
|
||||
|
||||
{{? !($inline || $macro) }}{{=$ruleErrs}} = null;{{?}}
|
||||
var {{=$errs}} = errors;
|
||||
var {{=$valid}};
|
||||
|
||||
{{## def.callRuleValidate:
|
||||
{{=$validateCode}}.call(
|
||||
{{? it.opts.passContext }}this{{??}}self{{?}}
|
||||
{{? $compile || $rDef.schema === false }}
|
||||
, {{=$data}}
|
||||
{{??}}
|
||||
, {{=$schemaValue}}
|
||||
, {{=$data}}
|
||||
, validate.schema{{=it.schemaPath}}
|
||||
{{?}}
|
||||
, {{# def.dataPath }}
|
||||
{{# def.passParentData }}
|
||||
, rootData
|
||||
)
|
||||
#}}
|
||||
|
||||
{{## def.extendErrors:_inline:
|
||||
for (var {{=$i}}={{=$errs}}; {{=$i}}<errors; {{=$i}}++) {
|
||||
var {{=$ruleErr}} = vErrors[{{=$i}}];
|
||||
if ({{=$ruleErr}}.dataPath === undefined)
|
||||
{{=$ruleErr}}.dataPath = (dataPath || '') + {{= it.errorPath }};
|
||||
{{# _inline ? 'if (\{\{=$ruleErr\}\}.schemaPath === undefined) {' : '' }}
|
||||
{{=$ruleErr}}.schemaPath = "{{=$errSchemaPath}}";
|
||||
{{# _inline ? '}' : '' }}
|
||||
{{? it.opts.verbose }}
|
||||
{{=$ruleErr}}.schema = {{=$schemaValue}};
|
||||
{{=$ruleErr}}.data = {{=$data}};
|
||||
{{?}}
|
||||
}
|
||||
#}}
|
||||
|
||||
|
||||
{{? $isData && $rDef.$data }}
|
||||
{{ $closingBraces += '}'; }}
|
||||
if ({{=$schemaValue}} === undefined) {
|
||||
{{=$valid}} = true;
|
||||
} else {
|
||||
{{? $validateSchema }}
|
||||
{{ $closingBraces += '}'; }}
|
||||
{{=$valid}} = {{=$definition}}.validateSchema({{=$schemaValue}});
|
||||
if ({{=$valid}}) {
|
||||
{{?}}
|
||||
{{?}}
|
||||
|
||||
{{? $inline }}
|
||||
{{? $rDef.statements }}
|
||||
{{= $ruleValidate.validate }}
|
||||
{{??}}
|
||||
{{=$valid}} = {{= $ruleValidate.validate }};
|
||||
{{?}}
|
||||
{{?? $macro }}
|
||||
{{# def.setupNextLevel }}
|
||||
{{
|
||||
$it.schema = $ruleValidate.validate;
|
||||
$it.schemaPath = '';
|
||||
}}
|
||||
{{# def.setCompositeRule }}
|
||||
{{ var $code = it.validate($it).replace(/validate\.schema/g, $validateCode); }}
|
||||
{{# def.resetCompositeRule }}
|
||||
{{= $code }}
|
||||
{{??}}
|
||||
{{# def.beginDefOut}}
|
||||
{{# def.callRuleValidate }}
|
||||
{{# def.storeDefOut:def_callRuleValidate }}
|
||||
|
||||
{{? $rDef.errors === false }}
|
||||
{{=$valid}} = {{? $asyncKeyword }}await {{?}}{{= def_callRuleValidate }};
|
||||
{{??}}
|
||||
{{? $asyncKeyword }}
|
||||
{{ $ruleErrs = 'customErrors' + $lvl; }}
|
||||
var {{=$ruleErrs}} = null;
|
||||
try {
|
||||
{{=$valid}} = await {{= def_callRuleValidate }};
|
||||
} catch (e) {
|
||||
{{=$valid}} = false;
|
||||
if (e instanceof ValidationError) {{=$ruleErrs}} = e.errors;
|
||||
else throw e;
|
||||
}
|
||||
{{??}}
|
||||
{{=$ruleErrs}} = null;
|
||||
{{=$valid}} = {{= def_callRuleValidate }};
|
||||
{{?}}
|
||||
{{?}}
|
||||
{{?}}
|
||||
|
||||
{{? $rDef.modifying }}
|
||||
if ({{=$parentData}}) {{=$data}} = {{=$parentData}}[{{=$parentDataProperty}}];
|
||||
{{?}}
|
||||
|
||||
{{= $closingBraces }}
|
||||
|
||||
{{## def.notValidationResult:
|
||||
{{? $rDef.valid === undefined }}
|
||||
!{{? $macro }}{{=$nextValid}}{{??}}{{=$valid}}{{?}}
|
||||
{{??}}
|
||||
{{= !$rDef.valid }}
|
||||
{{?}}
|
||||
#}}
|
||||
|
||||
{{? $rDef.valid }}
|
||||
{{? $breakOnError }} if (true) { {{?}}
|
||||
{{??}}
|
||||
if ({{# def.notValidationResult }}) {
|
||||
{{ $errorKeyword = $rule.keyword; }}
|
||||
{{# def.beginDefOut}}
|
||||
{{# def.error:'custom' }}
|
||||
{{# def.storeDefOut:def_customError }}
|
||||
|
||||
{{? $inline }}
|
||||
{{? $rDef.errors }}
|
||||
{{? $rDef.errors != 'full' }}
|
||||
{{# def.extendErrors:true }}
|
||||
{{?}}
|
||||
{{??}}
|
||||
{{? $rDef.errors === false}}
|
||||
{{= def_customError }}
|
||||
{{??}}
|
||||
if ({{=$errs}} == errors) {
|
||||
{{= def_customError }}
|
||||
} else {
|
||||
{{# def.extendErrors:true }}
|
||||
}
|
||||
{{?}}
|
||||
{{?}}
|
||||
{{?? $macro }}
|
||||
{{# def.extraError:'custom' }}
|
||||
{{??}}
|
||||
{{? $rDef.errors === false}}
|
||||
{{= def_customError }}
|
||||
{{??}}
|
||||
if (Array.isArray({{=$ruleErrs}})) {
|
||||
if (vErrors === null) vErrors = {{=$ruleErrs}};
|
||||
else vErrors = vErrors.concat({{=$ruleErrs}});
|
||||
errors = vErrors.length;
|
||||
{{# def.extendErrors:false }}
|
||||
} else {
|
||||
{{= def_customError }}
|
||||
}
|
||||
{{?}}
|
||||
{{?}}
|
||||
|
||||
} {{? $breakOnError }} else { {{?}}
|
||||
{{?}}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
{{## def.assignDefault:
|
||||
{{? it.compositeRule }}
|
||||
{{
|
||||
if (it.opts.strictDefaults) {
|
||||
var $defaultMsg = 'default is ignored for: ' + $passData;
|
||||
if (it.opts.strictDefaults === 'log') it.logger.warn($defaultMsg);
|
||||
else throw new Error($defaultMsg);
|
||||
}
|
||||
}}
|
||||
{{??}}
|
||||
if ({{=$passData}} === undefined
|
||||
{{? it.opts.useDefaults == 'empty' }}
|
||||
|| {{=$passData}} === null
|
||||
|| {{=$passData}} === ''
|
||||
{{?}}
|
||||
)
|
||||
{{=$passData}} = {{? it.opts.useDefaults == 'shared' }}
|
||||
{{= it.useDefault($sch.default) }}
|
||||
{{??}}
|
||||
{{= JSON.stringify($sch.default) }}
|
||||
{{?}};
|
||||
{{?}}
|
||||
#}}
|
||||
|
||||
|
||||
{{## def.defaultProperties:
|
||||
{{
|
||||
var $schema = it.schema.properties
|
||||
, $schemaKeys = Object.keys($schema); }}
|
||||
{{~ $schemaKeys:$propertyKey }}
|
||||
{{ var $sch = $schema[$propertyKey]; }}
|
||||
{{? $sch.default !== undefined }}
|
||||
{{ var $passData = $data + it.util.getProperty($propertyKey); }}
|
||||
{{# def.assignDefault }}
|
||||
{{?}}
|
||||
{{~}}
|
||||
#}}
|
||||
|
||||
|
||||
{{## def.defaultItems:
|
||||
{{~ it.schema.items:$sch:$i }}
|
||||
{{? $sch.default !== undefined }}
|
||||
{{ var $passData = $data + '[' + $i + ']'; }}
|
||||
{{# def.assignDefault }}
|
||||
{{?}}
|
||||
{{~}}
|
||||
#}}
|
||||
+203
@@ -0,0 +1,203 @@
|
||||
{{## def.setupKeyword:
|
||||
{{
|
||||
var $lvl = it.level;
|
||||
var $dataLvl = it.dataLevel;
|
||||
var $schema = it.schema[$keyword];
|
||||
var $schemaPath = it.schemaPath + it.util.getProperty($keyword);
|
||||
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
|
||||
var $breakOnError = !it.opts.allErrors;
|
||||
var $errorKeyword;
|
||||
|
||||
var $data = 'data' + ($dataLvl || '');
|
||||
var $valid = 'valid' + $lvl;
|
||||
var $errs = 'errs__' + $lvl;
|
||||
}}
|
||||
#}}
|
||||
|
||||
|
||||
{{## def.setCompositeRule:
|
||||
{{
|
||||
var $wasComposite = it.compositeRule;
|
||||
it.compositeRule = $it.compositeRule = true;
|
||||
}}
|
||||
#}}
|
||||
|
||||
|
||||
{{## def.resetCompositeRule:
|
||||
{{ it.compositeRule = $it.compositeRule = $wasComposite; }}
|
||||
#}}
|
||||
|
||||
|
||||
{{## def.setupNextLevel:
|
||||
{{
|
||||
var $it = it.util.copy(it);
|
||||
var $closingBraces = '';
|
||||
$it.level++;
|
||||
var $nextValid = 'valid' + $it.level;
|
||||
}}
|
||||
#}}
|
||||
|
||||
|
||||
{{## def.ifValid:
|
||||
{{? $breakOnError }}
|
||||
if ({{=$valid}}) {
|
||||
{{ $closingBraces += '}'; }}
|
||||
{{?}}
|
||||
#}}
|
||||
|
||||
|
||||
{{## def.ifResultValid:
|
||||
{{? $breakOnError }}
|
||||
if ({{=$nextValid}}) {
|
||||
{{ $closingBraces += '}'; }}
|
||||
{{?}}
|
||||
#}}
|
||||
|
||||
|
||||
{{## def.elseIfValid:
|
||||
{{? $breakOnError }}
|
||||
{{ $closingBraces += '}'; }}
|
||||
else {
|
||||
{{?}}
|
||||
#}}
|
||||
|
||||
|
||||
{{## def.nonEmptySchema:_schema:
|
||||
(it.opts.strictKeywords
|
||||
? (typeof _schema == 'object' && Object.keys(_schema).length > 0)
|
||||
|| _schema === false
|
||||
: it.util.schemaHasRules(_schema, it.RULES.all))
|
||||
#}}
|
||||
|
||||
|
||||
{{## def.strLength:
|
||||
{{? it.opts.unicode === false }}
|
||||
{{=$data}}.length
|
||||
{{??}}
|
||||
ucs2length({{=$data}})
|
||||
{{?}}
|
||||
#}}
|
||||
|
||||
|
||||
{{## def.willOptimize:
|
||||
it.util.varOccurences($code, $nextData) < 2
|
||||
#}}
|
||||
|
||||
|
||||
{{## def.generateSubschemaCode:
|
||||
{{
|
||||
var $code = it.validate($it);
|
||||
$it.baseId = $currentBaseId;
|
||||
}}
|
||||
#}}
|
||||
|
||||
|
||||
{{## def.insertSubschemaCode:
|
||||
{{= it.validate($it) }}
|
||||
{{ $it.baseId = $currentBaseId; }}
|
||||
#}}
|
||||
|
||||
|
||||
{{## def._optimizeValidate:
|
||||
it.util.varReplace($code, $nextData, $passData)
|
||||
#}}
|
||||
|
||||
|
||||
{{## def.optimizeValidate:
|
||||
{{? {{# def.willOptimize}} }}
|
||||
{{= {{# def._optimizeValidate }} }}
|
||||
{{??}}
|
||||
var {{=$nextData}} = {{=$passData}};
|
||||
{{= $code }}
|
||||
{{?}}
|
||||
#}}
|
||||
|
||||
|
||||
{{## def.$data:
|
||||
{{
|
||||
var $isData = it.opts.$data && $schema && $schema.$data
|
||||
, $schemaValue;
|
||||
}}
|
||||
{{? $isData }}
|
||||
var schema{{=$lvl}} = {{= it.util.getData($schema.$data, $dataLvl, it.dataPathArr) }};
|
||||
{{ $schemaValue = 'schema' + $lvl; }}
|
||||
{{??}}
|
||||
{{ $schemaValue = $schema; }}
|
||||
{{?}}
|
||||
#}}
|
||||
|
||||
|
||||
{{## def.$dataNotType:_type:
|
||||
{{?$isData}} ({{=$schemaValue}} !== undefined && typeof {{=$schemaValue}} != _type) || {{?}}
|
||||
#}}
|
||||
|
||||
|
||||
{{## def.check$dataIsArray:
|
||||
if (schema{{=$lvl}} === undefined) {{=$valid}} = true;
|
||||
else if (!Array.isArray(schema{{=$lvl}})) {{=$valid}} = false;
|
||||
else {
|
||||
#}}
|
||||
|
||||
|
||||
{{## def.numberKeyword:
|
||||
{{? !($isData || typeof $schema == 'number') }}
|
||||
{{ throw new Error($keyword + ' must be number'); }}
|
||||
{{?}}
|
||||
#}}
|
||||
|
||||
|
||||
{{## def.beginDefOut:
|
||||
{{
|
||||
var $$outStack = $$outStack || [];
|
||||
$$outStack.push(out);
|
||||
out = '';
|
||||
}}
|
||||
#}}
|
||||
|
||||
|
||||
{{## def.storeDefOut:_variable:
|
||||
{{
|
||||
var _variable = out;
|
||||
out = $$outStack.pop();
|
||||
}}
|
||||
#}}
|
||||
|
||||
|
||||
{{## def.dataPath:(dataPath || ''){{? it.errorPath != '""'}} + {{= it.errorPath }}{{?}}#}}
|
||||
|
||||
{{## def.setParentData:
|
||||
{{
|
||||
var $parentData = $dataLvl ? 'data' + (($dataLvl-1)||'') : 'parentData'
|
||||
, $parentDataProperty = $dataLvl ? it.dataPathArr[$dataLvl] : 'parentDataProperty';
|
||||
}}
|
||||
#}}
|
||||
|
||||
{{## def.passParentData:
|
||||
{{# def.setParentData }}
|
||||
, {{= $parentData }}
|
||||
, {{= $parentDataProperty }}
|
||||
#}}
|
||||
|
||||
|
||||
{{## def.iterateProperties:
|
||||
{{? $ownProperties }}
|
||||
{{=$dataProperties}} = {{=$dataProperties}} || Object.keys({{=$data}});
|
||||
for (var {{=$idx}}=0; {{=$idx}}<{{=$dataProperties}}.length; {{=$idx}}++) {
|
||||
var {{=$key}} = {{=$dataProperties}}[{{=$idx}}];
|
||||
{{??}}
|
||||
for (var {{=$key}} in {{=$data}}) {
|
||||
{{?}}
|
||||
#}}
|
||||
|
||||
|
||||
{{## def.noPropertyInData:
|
||||
{{=$useData}} === undefined
|
||||
{{? $ownProperties }}
|
||||
|| !{{# def.isOwnProperty }}
|
||||
{{?}}
|
||||
#}}
|
||||
|
||||
|
||||
{{## def.isOwnProperty:
|
||||
Object.prototype.hasOwnProperty.call({{=$data}}, '{{=it.util.escapeQuotes($propertyKey)}}')
|
||||
#}}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
{{# def.definitions }}
|
||||
{{# def.errors }}
|
||||
{{# def.missing }}
|
||||
{{# def.setupKeyword }}
|
||||
{{# def.setupNextLevel }}
|
||||
|
||||
|
||||
{{## def.propertyInData:
|
||||
{{=$data}}{{= it.util.getProperty($property) }} !== undefined
|
||||
{{? $ownProperties }}
|
||||
&& Object.prototype.hasOwnProperty.call({{=$data}}, '{{=it.util.escapeQuotes($property)}}')
|
||||
{{?}}
|
||||
#}}
|
||||
|
||||
|
||||
{{
|
||||
var $schemaDeps = {}
|
||||
, $propertyDeps = {}
|
||||
, $ownProperties = it.opts.ownProperties;
|
||||
|
||||
for ($property in $schema) {
|
||||
if ($property == '__proto__') continue;
|
||||
var $sch = $schema[$property];
|
||||
var $deps = Array.isArray($sch) ? $propertyDeps : $schemaDeps;
|
||||
$deps[$property] = $sch;
|
||||
}
|
||||
}}
|
||||
|
||||
var {{=$errs}} = errors;
|
||||
|
||||
{{ var $currentErrorPath = it.errorPath; }}
|
||||
|
||||
var missing{{=$lvl}};
|
||||
{{ for (var $property in $propertyDeps) { }}
|
||||
{{ $deps = $propertyDeps[$property]; }}
|
||||
{{? $deps.length }}
|
||||
if ({{# def.propertyInData }}
|
||||
{{? $breakOnError }}
|
||||
&& ({{# def.checkMissingProperty:$deps }})) {
|
||||
{{# def.errorMissingProperty:'dependencies' }}
|
||||
{{??}}
|
||||
) {
|
||||
{{~ $deps:$propertyKey }}
|
||||
{{# def.allErrorsMissingProperty:'dependencies' }}
|
||||
{{~}}
|
||||
{{?}}
|
||||
} {{# def.elseIfValid }}
|
||||
{{?}}
|
||||
{{ } }}
|
||||
|
||||
{{
|
||||
it.errorPath = $currentErrorPath;
|
||||
var $currentBaseId = $it.baseId;
|
||||
}}
|
||||
|
||||
|
||||
{{ for (var $property in $schemaDeps) { }}
|
||||
{{ var $sch = $schemaDeps[$property]; }}
|
||||
{{? {{# def.nonEmptySchema:$sch }} }}
|
||||
{{=$nextValid}} = true;
|
||||
|
||||
if ({{# def.propertyInData }}) {
|
||||
{{
|
||||
$it.schema = $sch;
|
||||
$it.schemaPath = $schemaPath + it.util.getProperty($property);
|
||||
$it.errSchemaPath = $errSchemaPath + '/' + it.util.escapeFragment($property);
|
||||
}}
|
||||
|
||||
{{# def.insertSubschemaCode }}
|
||||
}
|
||||
|
||||
{{# def.ifResultValid }}
|
||||
{{?}}
|
||||
{{ } }}
|
||||
|
||||
{{? $breakOnError }}
|
||||
{{= $closingBraces }}
|
||||
if ({{=$errs}} == errors) {
|
||||
{{?}}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
{{# def.definitions }}
|
||||
{{# def.errors }}
|
||||
{{# def.setupKeyword }}
|
||||
{{# def.$data }}
|
||||
|
||||
{{
|
||||
var $i = 'i' + $lvl
|
||||
, $vSchema = 'schema' + $lvl;
|
||||
}}
|
||||
|
||||
{{? !$isData }}
|
||||
var {{=$vSchema}} = validate.schema{{=$schemaPath}};
|
||||
{{?}}
|
||||
var {{=$valid}};
|
||||
|
||||
{{?$isData}}{{# def.check$dataIsArray }}{{?}}
|
||||
|
||||
{{=$valid}} = false;
|
||||
|
||||
for (var {{=$i}}=0; {{=$i}}<{{=$vSchema}}.length; {{=$i}}++)
|
||||
if (equal({{=$data}}, {{=$vSchema}}[{{=$i}}])) {
|
||||
{{=$valid}} = true;
|
||||
break;
|
||||
}
|
||||
|
||||
{{? $isData }} } {{?}}
|
||||
|
||||
{{# def.checkError:'enum' }}
|
||||
|
||||
{{? $breakOnError }} else { {{?}}
|
||||
+194
@@ -0,0 +1,194 @@
|
||||
{{# def.definitions }}
|
||||
|
||||
{{## def._error:_rule:
|
||||
{{ 'istanbul ignore else'; }}
|
||||
{{? it.createErrors !== false }}
|
||||
{
|
||||
keyword: '{{= $errorKeyword || _rule }}'
|
||||
, dataPath: (dataPath || '') + {{= it.errorPath }}
|
||||
, schemaPath: {{=it.util.toQuotedString($errSchemaPath)}}
|
||||
, params: {{# def._errorParams[_rule] }}
|
||||
{{? it.opts.messages !== false }}
|
||||
, message: {{# def._errorMessages[_rule] }}
|
||||
{{?}}
|
||||
{{? it.opts.verbose }}
|
||||
, schema: {{# def._errorSchemas[_rule] }}
|
||||
, parentSchema: validate.schema{{=it.schemaPath}}
|
||||
, data: {{=$data}}
|
||||
{{?}}
|
||||
}
|
||||
{{??}}
|
||||
{}
|
||||
{{?}}
|
||||
#}}
|
||||
|
||||
|
||||
{{## def._addError:_rule:
|
||||
if (vErrors === null) vErrors = [err];
|
||||
else vErrors.push(err);
|
||||
errors++;
|
||||
#}}
|
||||
|
||||
|
||||
{{## def.addError:_rule:
|
||||
var err = {{# def._error:_rule }};
|
||||
{{# def._addError:_rule }}
|
||||
#}}
|
||||
|
||||
|
||||
{{## def.error:_rule:
|
||||
{{# def.beginDefOut}}
|
||||
{{# def._error:_rule }}
|
||||
{{# def.storeDefOut:__err }}
|
||||
|
||||
{{? !it.compositeRule && $breakOnError }}
|
||||
{{ 'istanbul ignore if'; }}
|
||||
{{? it.async }}
|
||||
throw new ValidationError([{{=__err}}]);
|
||||
{{??}}
|
||||
validate.errors = [{{=__err}}];
|
||||
return false;
|
||||
{{?}}
|
||||
{{??}}
|
||||
var err = {{=__err}};
|
||||
{{# def._addError:_rule }}
|
||||
{{?}}
|
||||
#}}
|
||||
|
||||
|
||||
{{## def.extraError:_rule:
|
||||
{{# def.addError:_rule}}
|
||||
{{? !it.compositeRule && $breakOnError }}
|
||||
{{ 'istanbul ignore if'; }}
|
||||
{{? it.async }}
|
||||
throw new ValidationError(vErrors);
|
||||
{{??}}
|
||||
validate.errors = vErrors;
|
||||
return false;
|
||||
{{?}}
|
||||
{{?}}
|
||||
#}}
|
||||
|
||||
|
||||
{{## def.checkError:_rule:
|
||||
if (!{{=$valid}}) {
|
||||
{{# def.error:_rule }}
|
||||
}
|
||||
#}}
|
||||
|
||||
|
||||
{{## def.resetErrors:
|
||||
errors = {{=$errs}};
|
||||
if (vErrors !== null) {
|
||||
if ({{=$errs}}) vErrors.length = {{=$errs}};
|
||||
else vErrors = null;
|
||||
}
|
||||
#}}
|
||||
|
||||
|
||||
{{## def.concatSchema:{{?$isData}}' + {{=$schemaValue}} + '{{??}}{{=$schema}}{{?}}#}}
|
||||
{{## def.appendSchema:{{?$isData}}' + {{=$schemaValue}}{{??}}{{=$schemaValue}}'{{?}}#}}
|
||||
{{## def.concatSchemaEQ:{{?$isData}}' + {{=$schemaValue}} + '{{??}}{{=it.util.escapeQuotes($schema)}}{{?}}#}}
|
||||
|
||||
{{## def._errorMessages = {
|
||||
'false schema': "'boolean schema is false'",
|
||||
$ref: "'can\\\'t resolve reference {{=it.util.escapeQuotes($schema)}}'",
|
||||
additionalItems: "'should NOT have more than {{=$schema.length}} items'",
|
||||
additionalProperties: "'{{? it.opts._errorDataPathProperty }}is an invalid additional property{{??}}should NOT have additional properties{{?}}'",
|
||||
anyOf: "'should match some schema in anyOf'",
|
||||
const: "'should be equal to constant'",
|
||||
contains: "'should contain a valid item'",
|
||||
dependencies: "'should have {{? $deps.length == 1 }}property {{= it.util.escapeQuotes($deps[0]) }}{{??}}properties {{= it.util.escapeQuotes($deps.join(\", \")) }}{{?}} when property {{= it.util.escapeQuotes($property) }} is present'",
|
||||
'enum': "'should be equal to one of the allowed values'",
|
||||
format: "'should match format \"{{#def.concatSchemaEQ}}\"'",
|
||||
'if': "'should match \"' + {{=$ifClause}} + '\" schema'",
|
||||
_limit: "'should be {{=$opStr}} {{#def.appendSchema}}",
|
||||
_exclusiveLimit: "'{{=$exclusiveKeyword}} should be boolean'",
|
||||
_limitItems: "'should NOT have {{?$keyword=='maxItems'}}more{{??}}fewer{{?}} than {{#def.concatSchema}} items'",
|
||||
_limitLength: "'should NOT be {{?$keyword=='maxLength'}}longer{{??}}shorter{{?}} than {{#def.concatSchema}} characters'",
|
||||
_limitProperties:"'should NOT have {{?$keyword=='maxProperties'}}more{{??}}fewer{{?}} than {{#def.concatSchema}} properties'",
|
||||
multipleOf: "'should be multiple of {{#def.appendSchema}}",
|
||||
not: "'should NOT be valid'",
|
||||
oneOf: "'should match exactly one schema in oneOf'",
|
||||
pattern: "'should match pattern \"{{#def.concatSchemaEQ}}\"'",
|
||||
propertyNames: "'property name \\'{{=$invalidName}}\\' is invalid'",
|
||||
required: "'{{? it.opts._errorDataPathProperty }}is a required property{{??}}should have required property \\'{{=$missingProperty}}\\'{{?}}'",
|
||||
type: "'should be {{? $typeIsArray }}{{= $typeSchema.join(\",\") }}{{??}}{{=$typeSchema}}{{?}}'",
|
||||
uniqueItems: "'should NOT have duplicate items (items ## ' + j + ' and ' + i + ' are identical)'",
|
||||
custom: "'should pass \"{{=$rule.keyword}}\" keyword validation'",
|
||||
patternRequired: "'should have property matching pattern \\'{{=$missingPattern}}\\''",
|
||||
switch: "'should pass \"switch\" keyword validation'",
|
||||
_formatLimit: "'should be {{=$opStr}} \"{{#def.concatSchemaEQ}}\"'",
|
||||
_formatExclusiveLimit: "'{{=$exclusiveKeyword}} should be boolean'"
|
||||
} #}}
|
||||
|
||||
|
||||
{{## def.schemaRefOrVal: {{?$isData}}validate.schema{{=$schemaPath}}{{??}}{{=$schema}}{{?}} #}}
|
||||
{{## def.schemaRefOrQS: {{?$isData}}validate.schema{{=$schemaPath}}{{??}}{{=it.util.toQuotedString($schema)}}{{?}} #}}
|
||||
|
||||
{{## def._errorSchemas = {
|
||||
'false schema': "false",
|
||||
$ref: "{{=it.util.toQuotedString($schema)}}",
|
||||
additionalItems: "false",
|
||||
additionalProperties: "false",
|
||||
anyOf: "validate.schema{{=$schemaPath}}",
|
||||
const: "validate.schema{{=$schemaPath}}",
|
||||
contains: "validate.schema{{=$schemaPath}}",
|
||||
dependencies: "validate.schema{{=$schemaPath}}",
|
||||
'enum': "validate.schema{{=$schemaPath}}",
|
||||
format: "{{#def.schemaRefOrQS}}",
|
||||
'if': "validate.schema{{=$schemaPath}}",
|
||||
_limit: "{{#def.schemaRefOrVal}}",
|
||||
_exclusiveLimit: "validate.schema{{=$schemaPath}}",
|
||||
_limitItems: "{{#def.schemaRefOrVal}}",
|
||||
_limitLength: "{{#def.schemaRefOrVal}}",
|
||||
_limitProperties:"{{#def.schemaRefOrVal}}",
|
||||
multipleOf: "{{#def.schemaRefOrVal}}",
|
||||
not: "validate.schema{{=$schemaPath}}",
|
||||
oneOf: "validate.schema{{=$schemaPath}}",
|
||||
pattern: "{{#def.schemaRefOrQS}}",
|
||||
propertyNames: "validate.schema{{=$schemaPath}}",
|
||||
required: "validate.schema{{=$schemaPath}}",
|
||||
type: "validate.schema{{=$schemaPath}}",
|
||||
uniqueItems: "{{#def.schemaRefOrVal}}",
|
||||
custom: "validate.schema{{=$schemaPath}}",
|
||||
patternRequired: "validate.schema{{=$schemaPath}}",
|
||||
switch: "validate.schema{{=$schemaPath}}",
|
||||
_formatLimit: "{{#def.schemaRefOrQS}}",
|
||||
_formatExclusiveLimit: "validate.schema{{=$schemaPath}}"
|
||||
} #}}
|
||||
|
||||
|
||||
{{## def.schemaValueQS: {{?$isData}}{{=$schemaValue}}{{??}}{{=it.util.toQuotedString($schema)}}{{?}} #}}
|
||||
|
||||
{{## def._errorParams = {
|
||||
'false schema': "{}",
|
||||
$ref: "{ ref: '{{=it.util.escapeQuotes($schema)}}' }",
|
||||
additionalItems: "{ limit: {{=$schema.length}} }",
|
||||
additionalProperties: "{ additionalProperty: '{{=$additionalProperty}}' }",
|
||||
anyOf: "{}",
|
||||
const: "{ allowedValue: schema{{=$lvl}} }",
|
||||
contains: "{}",
|
||||
dependencies: "{ property: '{{= it.util.escapeQuotes($property) }}', missingProperty: '{{=$missingProperty}}', depsCount: {{=$deps.length}}, deps: '{{= it.util.escapeQuotes($deps.length==1 ? $deps[0] : $deps.join(\", \")) }}' }",
|
||||
'enum': "{ allowedValues: schema{{=$lvl}} }",
|
||||
format: "{ format: {{#def.schemaValueQS}} }",
|
||||
'if': "{ failingKeyword: {{=$ifClause}} }",
|
||||
_limit: "{ comparison: {{=$opExpr}}, limit: {{=$schemaValue}}, exclusive: {{=$exclusive}} }",
|
||||
_exclusiveLimit: "{}",
|
||||
_limitItems: "{ limit: {{=$schemaValue}} }",
|
||||
_limitLength: "{ limit: {{=$schemaValue}} }",
|
||||
_limitProperties:"{ limit: {{=$schemaValue}} }",
|
||||
multipleOf: "{ multipleOf: {{=$schemaValue}} }",
|
||||
not: "{}",
|
||||
oneOf: "{ passingSchemas: {{=$passingSchemas}} }",
|
||||
pattern: "{ pattern: {{#def.schemaValueQS}} }",
|
||||
propertyNames: "{ propertyName: '{{=$invalidName}}' }",
|
||||
required: "{ missingProperty: '{{=$missingProperty}}' }",
|
||||
type: "{ type: '{{? $typeIsArray }}{{= $typeSchema.join(\",\") }}{{??}}{{=$typeSchema}}{{?}}' }",
|
||||
uniqueItems: "{ i: i, j: j }",
|
||||
custom: "{ keyword: '{{=$rule.keyword}}' }",
|
||||
patternRequired: "{ missingPattern: '{{=$missingPattern}}' }",
|
||||
switch: "{ caseIndex: {{=$caseIndex}} }",
|
||||
_formatLimit: "{ comparison: {{=$opExpr}}, limit: {{#def.schemaValueQS}}, exclusive: {{=$exclusive}} }",
|
||||
_formatExclusiveLimit: "{}"
|
||||
} #}}
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
{{# def.definitions }}
|
||||
{{# def.errors }}
|
||||
{{# def.setupKeyword }}
|
||||
|
||||
{{## def.skipFormat:
|
||||
{{? $breakOnError }} if (true) { {{?}}
|
||||
{{ return out; }}
|
||||
#}}
|
||||
|
||||
{{? it.opts.format === false }}{{# def.skipFormat }}{{?}}
|
||||
|
||||
|
||||
{{# def.$data }}
|
||||
|
||||
|
||||
{{## def.$dataCheckFormat:
|
||||
{{# def.$dataNotType:'string' }}
|
||||
({{? $unknownFormats != 'ignore' }}
|
||||
({{=$schemaValue}} && !{{=$format}}
|
||||
{{? $allowUnknown }}
|
||||
&& self._opts.unknownFormats.indexOf({{=$schemaValue}}) == -1
|
||||
{{?}}) ||
|
||||
{{?}}
|
||||
({{=$format}} && {{=$formatType}} == '{{=$ruleType}}'
|
||||
&& !(typeof {{=$format}} == 'function'
|
||||
? {{? it.async}}
|
||||
(async{{=$lvl}} ? await {{=$format}}({{=$data}}) : {{=$format}}({{=$data}}))
|
||||
{{??}}
|
||||
{{=$format}}({{=$data}})
|
||||
{{?}}
|
||||
: {{=$format}}.test({{=$data}}))))
|
||||
#}}
|
||||
|
||||
{{## def.checkFormat:
|
||||
{{
|
||||
var $formatRef = 'formats' + it.util.getProperty($schema);
|
||||
if ($isObject) $formatRef += '.validate';
|
||||
}}
|
||||
{{? typeof $format == 'function' }}
|
||||
{{=$formatRef}}({{=$data}})
|
||||
{{??}}
|
||||
{{=$formatRef}}.test({{=$data}})
|
||||
{{?}}
|
||||
#}}
|
||||
|
||||
|
||||
{{
|
||||
var $unknownFormats = it.opts.unknownFormats
|
||||
, $allowUnknown = Array.isArray($unknownFormats);
|
||||
}}
|
||||
|
||||
{{? $isData }}
|
||||
{{
|
||||
var $format = 'format' + $lvl
|
||||
, $isObject = 'isObject' + $lvl
|
||||
, $formatType = 'formatType' + $lvl;
|
||||
}}
|
||||
var {{=$format}} = formats[{{=$schemaValue}}];
|
||||
var {{=$isObject}} = typeof {{=$format}} == 'object'
|
||||
&& !({{=$format}} instanceof RegExp)
|
||||
&& {{=$format}}.validate;
|
||||
var {{=$formatType}} = {{=$isObject}} && {{=$format}}.type || 'string';
|
||||
if ({{=$isObject}}) {
|
||||
{{? it.async}}
|
||||
var async{{=$lvl}} = {{=$format}}.async;
|
||||
{{?}}
|
||||
{{=$format}} = {{=$format}}.validate;
|
||||
}
|
||||
if ({{# def.$dataCheckFormat }}) {
|
||||
{{??}}
|
||||
{{ var $format = it.formats[$schema]; }}
|
||||
{{? !$format }}
|
||||
{{? $unknownFormats == 'ignore' }}
|
||||
{{ it.logger.warn('unknown format "' + $schema + '" ignored in schema at path "' + it.errSchemaPath + '"'); }}
|
||||
{{# def.skipFormat }}
|
||||
{{?? $allowUnknown && $unknownFormats.indexOf($schema) >= 0 }}
|
||||
{{# def.skipFormat }}
|
||||
{{??}}
|
||||
{{ throw new Error('unknown format "' + $schema + '" is used in schema at path "' + it.errSchemaPath + '"'); }}
|
||||
{{?}}
|
||||
{{?}}
|
||||
{{
|
||||
var $isObject = typeof $format == 'object'
|
||||
&& !($format instanceof RegExp)
|
||||
&& $format.validate;
|
||||
var $formatType = $isObject && $format.type || 'string';
|
||||
if ($isObject) {
|
||||
var $async = $format.async === true;
|
||||
$format = $format.validate;
|
||||
}
|
||||
}}
|
||||
{{? $formatType != $ruleType }}
|
||||
{{# def.skipFormat }}
|
||||
{{?}}
|
||||
{{? $async }}
|
||||
{{
|
||||
if (!it.async) throw new Error('async format in sync schema');
|
||||
var $formatRef = 'formats' + it.util.getProperty($schema) + '.validate';
|
||||
}}
|
||||
if (!(await {{=$formatRef}}({{=$data}}))) {
|
||||
{{??}}
|
||||
if (!{{# def.checkFormat }}) {
|
||||
{{?}}
|
||||
{{?}}
|
||||
{{# def.error:'format' }}
|
||||
} {{? $breakOnError }} else { {{?}}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
{{# def.definitions }}
|
||||
{{# def.errors }}
|
||||
{{# def.setupKeyword }}
|
||||
{{# def.setupNextLevel }}
|
||||
|
||||
|
||||
{{## def.validateIfClause:_clause:
|
||||
{{
|
||||
$it.schema = it.schema['_clause'];
|
||||
$it.schemaPath = it.schemaPath + '._clause';
|
||||
$it.errSchemaPath = it.errSchemaPath + '/_clause';
|
||||
}}
|
||||
{{# def.insertSubschemaCode }}
|
||||
{{=$valid}} = {{=$nextValid}};
|
||||
{{? $thenPresent && $elsePresent }}
|
||||
{{ $ifClause = 'ifClause' + $lvl; }}
|
||||
var {{=$ifClause}} = '_clause';
|
||||
{{??}}
|
||||
{{ $ifClause = '\'_clause\''; }}
|
||||
{{?}}
|
||||
#}}
|
||||
|
||||
{{
|
||||
var $thenSch = it.schema['then']
|
||||
, $elseSch = it.schema['else']
|
||||
, $thenPresent = $thenSch !== undefined && {{# def.nonEmptySchema:$thenSch }}
|
||||
, $elsePresent = $elseSch !== undefined && {{# def.nonEmptySchema:$elseSch }}
|
||||
, $currentBaseId = $it.baseId;
|
||||
}}
|
||||
|
||||
{{? $thenPresent || $elsePresent }}
|
||||
{{
|
||||
var $ifClause;
|
||||
$it.createErrors = false;
|
||||
$it.schema = $schema;
|
||||
$it.schemaPath = $schemaPath;
|
||||
$it.errSchemaPath = $errSchemaPath;
|
||||
}}
|
||||
var {{=$errs}} = errors;
|
||||
var {{=$valid}} = true;
|
||||
|
||||
{{# def.setCompositeRule }}
|
||||
{{# def.insertSubschemaCode }}
|
||||
{{ $it.createErrors = true; }}
|
||||
{{# def.resetErrors }}
|
||||
{{# def.resetCompositeRule }}
|
||||
|
||||
{{? $thenPresent }}
|
||||
if ({{=$nextValid}}) {
|
||||
{{# def.validateIfClause:then }}
|
||||
}
|
||||
{{? $elsePresent }}
|
||||
else {
|
||||
{{?}}
|
||||
{{??}}
|
||||
if (!{{=$nextValid}}) {
|
||||
{{?}}
|
||||
|
||||
{{? $elsePresent }}
|
||||
{{# def.validateIfClause:else }}
|
||||
}
|
||||
{{?}}
|
||||
|
||||
if (!{{=$valid}}) {
|
||||
{{# def.extraError:'if' }}
|
||||
}
|
||||
{{? $breakOnError }} else { {{?}}
|
||||
{{??}}
|
||||
{{? $breakOnError }}
|
||||
if (true) {
|
||||
{{?}}
|
||||
{{?}}
|
||||
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
{{# def.definitions }}
|
||||
{{# def.errors }}
|
||||
{{# def.setupKeyword }}
|
||||
{{# def.setupNextLevel }}
|
||||
|
||||
|
||||
{{## def.validateItems:startFrom:
|
||||
for (var {{=$idx}} = {{=startFrom}}; {{=$idx}} < {{=$data}}.length; {{=$idx}}++) {
|
||||
{{
|
||||
$it.errorPath = it.util.getPathExpr(it.errorPath, $idx, it.opts.jsonPointers, true);
|
||||
var $passData = $data + '[' + $idx + ']';
|
||||
$it.dataPathArr[$dataNxt] = $idx;
|
||||
}}
|
||||
|
||||
{{# def.generateSubschemaCode }}
|
||||
{{# def.optimizeValidate }}
|
||||
|
||||
{{? $breakOnError }}
|
||||
if (!{{=$nextValid}}) break;
|
||||
{{?}}
|
||||
}
|
||||
#}}
|
||||
|
||||
{{
|
||||
var $idx = 'i' + $lvl
|
||||
, $dataNxt = $it.dataLevel = it.dataLevel + 1
|
||||
, $nextData = 'data' + $dataNxt
|
||||
, $currentBaseId = it.baseId;
|
||||
}}
|
||||
|
||||
var {{=$errs}} = errors;
|
||||
var {{=$valid}};
|
||||
|
||||
{{? Array.isArray($schema) }}
|
||||
{{ /* 'items' is an array of schemas */}}
|
||||
{{ var $additionalItems = it.schema.additionalItems; }}
|
||||
{{? $additionalItems === false }}
|
||||
{{=$valid}} = {{=$data}}.length <= {{= $schema.length }};
|
||||
{{
|
||||
var $currErrSchemaPath = $errSchemaPath;
|
||||
$errSchemaPath = it.errSchemaPath + '/additionalItems';
|
||||
}}
|
||||
{{# def.checkError:'additionalItems' }}
|
||||
{{ $errSchemaPath = $currErrSchemaPath; }}
|
||||
{{# def.elseIfValid}}
|
||||
{{?}}
|
||||
|
||||
{{~ $schema:$sch:$i }}
|
||||
{{? {{# def.nonEmptySchema:$sch }} }}
|
||||
{{=$nextValid}} = true;
|
||||
|
||||
if ({{=$data}}.length > {{=$i}}) {
|
||||
{{
|
||||
var $passData = $data + '[' + $i + ']';
|
||||
$it.schema = $sch;
|
||||
$it.schemaPath = $schemaPath + '[' + $i + ']';
|
||||
$it.errSchemaPath = $errSchemaPath + '/' + $i;
|
||||
$it.errorPath = it.util.getPathExpr(it.errorPath, $i, it.opts.jsonPointers, true);
|
||||
$it.dataPathArr[$dataNxt] = $i;
|
||||
}}
|
||||
|
||||
{{# def.generateSubschemaCode }}
|
||||
{{# def.optimizeValidate }}
|
||||
}
|
||||
|
||||
{{# def.ifResultValid }}
|
||||
{{?}}
|
||||
{{~}}
|
||||
|
||||
{{? typeof $additionalItems == 'object' && {{# def.nonEmptySchema:$additionalItems }} }}
|
||||
{{
|
||||
$it.schema = $additionalItems;
|
||||
$it.schemaPath = it.schemaPath + '.additionalItems';
|
||||
$it.errSchemaPath = it.errSchemaPath + '/additionalItems';
|
||||
}}
|
||||
{{=$nextValid}} = true;
|
||||
|
||||
if ({{=$data}}.length > {{= $schema.length }}) {
|
||||
{{# def.validateItems: $schema.length }}
|
||||
}
|
||||
|
||||
{{# def.ifResultValid }}
|
||||
{{?}}
|
||||
|
||||
{{?? {{# def.nonEmptySchema:$schema }} }}
|
||||
{{ /* 'items' is a single schema */}}
|
||||
{{
|
||||
$it.schema = $schema;
|
||||
$it.schemaPath = $schemaPath;
|
||||
$it.errSchemaPath = $errSchemaPath;
|
||||
}}
|
||||
{{# def.validateItems: 0 }}
|
||||
{{?}}
|
||||
|
||||
{{? $breakOnError }}
|
||||
{{= $closingBraces }}
|
||||
if ({{=$errs}} == errors) {
|
||||
{{?}}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
{{## def.checkMissingProperty:_properties:
|
||||
{{~ _properties:$propertyKey:$i }}
|
||||
{{?$i}} || {{?}}
|
||||
{{
|
||||
var $prop = it.util.getProperty($propertyKey)
|
||||
, $useData = $data + $prop;
|
||||
}}
|
||||
( ({{# def.noPropertyInData }}) && (missing{{=$lvl}} = {{= it.util.toQuotedString(it.opts.jsonPointers ? $propertyKey : $prop) }}) )
|
||||
{{~}}
|
||||
#}}
|
||||
|
||||
|
||||
{{## def.errorMissingProperty:_error:
|
||||
{{
|
||||
var $propertyPath = 'missing' + $lvl
|
||||
, $missingProperty = '\' + ' + $propertyPath + ' + \'';
|
||||
if (it.opts._errorDataPathProperty) {
|
||||
it.errorPath = it.opts.jsonPointers
|
||||
? it.util.getPathExpr($currentErrorPath, $propertyPath, true)
|
||||
: $currentErrorPath + ' + ' + $propertyPath;
|
||||
}
|
||||
}}
|
||||
{{# def.error:_error }}
|
||||
#}}
|
||||
|
||||
|
||||
{{## def.allErrorsMissingProperty:_error:
|
||||
{{
|
||||
var $prop = it.util.getProperty($propertyKey)
|
||||
, $missingProperty = it.util.escapeQuotes($propertyKey)
|
||||
, $useData = $data + $prop;
|
||||
if (it.opts._errorDataPathProperty) {
|
||||
it.errorPath = it.util.getPath($currentErrorPath, $propertyKey, it.opts.jsonPointers);
|
||||
}
|
||||
}}
|
||||
if ({{# def.noPropertyInData }}) {
|
||||
{{# def.addError:_error }}
|
||||
}
|
||||
#}}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
{{# def.definitions }}
|
||||
{{# def.errors }}
|
||||
{{# def.setupKeyword }}
|
||||
{{# def.$data }}
|
||||
|
||||
{{# def.numberKeyword }}
|
||||
|
||||
var division{{=$lvl}};
|
||||
if ({{?$isData}}
|
||||
{{=$schemaValue}} !== undefined && (
|
||||
typeof {{=$schemaValue}} != 'number' ||
|
||||
{{?}}
|
||||
(division{{=$lvl}} = {{=$data}} / {{=$schemaValue}},
|
||||
{{? it.opts.multipleOfPrecision }}
|
||||
Math.abs(Math.round(division{{=$lvl}}) - division{{=$lvl}}) > 1e-{{=it.opts.multipleOfPrecision}}
|
||||
{{??}}
|
||||
division{{=$lvl}} !== parseInt(division{{=$lvl}})
|
||||
{{?}}
|
||||
)
|
||||
{{?$isData}} ) {{?}} ) {
|
||||
{{# def.error:'multipleOf' }}
|
||||
} {{? $breakOnError }} else { {{?}}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
{{# def.definitions }}
|
||||
{{# def.errors }}
|
||||
{{# def.setupKeyword }}
|
||||
{{# def.setupNextLevel }}
|
||||
|
||||
{{? {{# def.nonEmptySchema:$schema }} }}
|
||||
{{
|
||||
$it.schema = $schema;
|
||||
$it.schemaPath = $schemaPath;
|
||||
$it.errSchemaPath = $errSchemaPath;
|
||||
}}
|
||||
|
||||
var {{=$errs}} = errors;
|
||||
|
||||
{{# def.setCompositeRule }}
|
||||
|
||||
{{
|
||||
$it.createErrors = false;
|
||||
var $allErrorsOption;
|
||||
if ($it.opts.allErrors) {
|
||||
$allErrorsOption = $it.opts.allErrors;
|
||||
$it.opts.allErrors = false;
|
||||
}
|
||||
}}
|
||||
{{= it.validate($it) }}
|
||||
{{
|
||||
$it.createErrors = true;
|
||||
if ($allErrorsOption) $it.opts.allErrors = $allErrorsOption;
|
||||
}}
|
||||
|
||||
{{# def.resetCompositeRule }}
|
||||
|
||||
if ({{=$nextValid}}) {
|
||||
{{# def.error:'not' }}
|
||||
} else {
|
||||
{{# def.resetErrors }}
|
||||
{{? it.opts.allErrors }} } {{?}}
|
||||
{{??}}
|
||||
{{# def.addError:'not' }}
|
||||
{{? $breakOnError}}
|
||||
if (false) {
|
||||
{{?}}
|
||||
{{?}}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
{{# def.definitions }}
|
||||
{{# def.errors }}
|
||||
{{# def.setupKeyword }}
|
||||
{{# def.setupNextLevel }}
|
||||
|
||||
{{
|
||||
var $currentBaseId = $it.baseId
|
||||
, $prevValid = 'prevValid' + $lvl
|
||||
, $passingSchemas = 'passingSchemas' + $lvl;
|
||||
}}
|
||||
|
||||
var {{=$errs}} = errors
|
||||
, {{=$prevValid}} = false
|
||||
, {{=$valid}} = false
|
||||
, {{=$passingSchemas}} = null;
|
||||
|
||||
{{# def.setCompositeRule }}
|
||||
|
||||
{{~ $schema:$sch:$i }}
|
||||
{{? {{# def.nonEmptySchema:$sch }} }}
|
||||
{{
|
||||
$it.schema = $sch;
|
||||
$it.schemaPath = $schemaPath + '[' + $i + ']';
|
||||
$it.errSchemaPath = $errSchemaPath + '/' + $i;
|
||||
}}
|
||||
|
||||
{{# def.insertSubschemaCode }}
|
||||
{{??}}
|
||||
var {{=$nextValid}} = true;
|
||||
{{?}}
|
||||
|
||||
{{? $i }}
|
||||
if ({{=$nextValid}} && {{=$prevValid}}) {
|
||||
{{=$valid}} = false;
|
||||
{{=$passingSchemas}} = [{{=$passingSchemas}}, {{=$i}}];
|
||||
} else {
|
||||
{{ $closingBraces += '}'; }}
|
||||
{{?}}
|
||||
|
||||
if ({{=$nextValid}}) {
|
||||
{{=$valid}} = {{=$prevValid}} = true;
|
||||
{{=$passingSchemas}} = {{=$i}};
|
||||
}
|
||||
{{~}}
|
||||
|
||||
{{# def.resetCompositeRule }}
|
||||
|
||||
{{= $closingBraces }}
|
||||
|
||||
if (!{{=$valid}}) {
|
||||
{{# def.extraError:'oneOf' }}
|
||||
} else {
|
||||
{{# def.resetErrors }}
|
||||
{{? it.opts.allErrors }} } {{?}}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
{{# def.definitions }}
|
||||
{{# def.errors }}
|
||||
{{# def.setupKeyword }}
|
||||
{{# def.$data }}
|
||||
|
||||
{{
|
||||
var $regexp = $isData
|
||||
? '(new RegExp(' + $schemaValue + '))'
|
||||
: it.usePattern($schema);
|
||||
}}
|
||||
|
||||
if ({{# def.$dataNotType:'string' }} !{{=$regexp}}.test({{=$data}}) ) {
|
||||
{{# def.error:'pattern' }}
|
||||
} {{? $breakOnError }} else { {{?}}
|
||||
+245
@@ -0,0 +1,245 @@
|
||||
{{# def.definitions }}
|
||||
{{# def.errors }}
|
||||
{{# def.setupKeyword }}
|
||||
{{# def.setupNextLevel }}
|
||||
|
||||
|
||||
{{## def.validateAdditional:
|
||||
{{ /* additionalProperties is schema */
|
||||
$it.schema = $aProperties;
|
||||
$it.schemaPath = it.schemaPath + '.additionalProperties';
|
||||
$it.errSchemaPath = it.errSchemaPath + '/additionalProperties';
|
||||
$it.errorPath = it.opts._errorDataPathProperty
|
||||
? it.errorPath
|
||||
: it.util.getPathExpr(it.errorPath, $key, it.opts.jsonPointers);
|
||||
var $passData = $data + '[' + $key + ']';
|
||||
$it.dataPathArr[$dataNxt] = $key;
|
||||
}}
|
||||
|
||||
{{# def.generateSubschemaCode }}
|
||||
{{# def.optimizeValidate }}
|
||||
#}}
|
||||
|
||||
|
||||
{{
|
||||
var $key = 'key' + $lvl
|
||||
, $idx = 'idx' + $lvl
|
||||
, $dataNxt = $it.dataLevel = it.dataLevel + 1
|
||||
, $nextData = 'data' + $dataNxt
|
||||
, $dataProperties = 'dataProperties' + $lvl;
|
||||
|
||||
var $schemaKeys = Object.keys($schema || {}).filter(notProto)
|
||||
, $pProperties = it.schema.patternProperties || {}
|
||||
, $pPropertyKeys = Object.keys($pProperties).filter(notProto)
|
||||
, $aProperties = it.schema.additionalProperties
|
||||
, $someProperties = $schemaKeys.length || $pPropertyKeys.length
|
||||
, $noAdditional = $aProperties === false
|
||||
, $additionalIsSchema = typeof $aProperties == 'object'
|
||||
&& Object.keys($aProperties).length
|
||||
, $removeAdditional = it.opts.removeAdditional
|
||||
, $checkAdditional = $noAdditional || $additionalIsSchema || $removeAdditional
|
||||
, $ownProperties = it.opts.ownProperties
|
||||
, $currentBaseId = it.baseId;
|
||||
|
||||
var $required = it.schema.required;
|
||||
if ($required && !(it.opts.$data && $required.$data) && $required.length < it.opts.loopRequired) {
|
||||
var $requiredHash = it.util.toHash($required);
|
||||
}
|
||||
|
||||
function notProto(p) { return p !== '__proto__'; }
|
||||
}}
|
||||
|
||||
|
||||
var {{=$errs}} = errors;
|
||||
var {{=$nextValid}} = true;
|
||||
{{? $ownProperties }}
|
||||
var {{=$dataProperties}} = undefined;
|
||||
{{?}}
|
||||
|
||||
{{? $checkAdditional }}
|
||||
{{# def.iterateProperties }}
|
||||
{{? $someProperties }}
|
||||
var isAdditional{{=$lvl}} = !(false
|
||||
{{? $schemaKeys.length }}
|
||||
{{? $schemaKeys.length > 8 }}
|
||||
|| validate.schema{{=$schemaPath}}.hasOwnProperty({{=$key}})
|
||||
{{??}}
|
||||
{{~ $schemaKeys:$propertyKey }}
|
||||
|| {{=$key}} == {{= it.util.toQuotedString($propertyKey) }}
|
||||
{{~}}
|
||||
{{?}}
|
||||
{{?}}
|
||||
{{? $pPropertyKeys.length }}
|
||||
{{~ $pPropertyKeys:$pProperty:$i }}
|
||||
|| {{= it.usePattern($pProperty) }}.test({{=$key}})
|
||||
{{~}}
|
||||
{{?}}
|
||||
);
|
||||
|
||||
if (isAdditional{{=$lvl}}) {
|
||||
{{?}}
|
||||
{{? $removeAdditional == 'all' }}
|
||||
delete {{=$data}}[{{=$key}}];
|
||||
{{??}}
|
||||
{{
|
||||
var $currentErrorPath = it.errorPath;
|
||||
var $additionalProperty = '\' + ' + $key + ' + \'';
|
||||
if (it.opts._errorDataPathProperty) {
|
||||
it.errorPath = it.util.getPathExpr(it.errorPath, $key, it.opts.jsonPointers);
|
||||
}
|
||||
}}
|
||||
{{? $noAdditional }}
|
||||
{{? $removeAdditional }}
|
||||
delete {{=$data}}[{{=$key}}];
|
||||
{{??}}
|
||||
{{=$nextValid}} = false;
|
||||
{{
|
||||
var $currErrSchemaPath = $errSchemaPath;
|
||||
$errSchemaPath = it.errSchemaPath + '/additionalProperties';
|
||||
}}
|
||||
{{# def.error:'additionalProperties' }}
|
||||
{{ $errSchemaPath = $currErrSchemaPath; }}
|
||||
{{? $breakOnError }} break; {{?}}
|
||||
{{?}}
|
||||
{{?? $additionalIsSchema }}
|
||||
{{? $removeAdditional == 'failing' }}
|
||||
var {{=$errs}} = errors;
|
||||
{{# def.setCompositeRule }}
|
||||
|
||||
{{# def.validateAdditional }}
|
||||
|
||||
if (!{{=$nextValid}}) {
|
||||
errors = {{=$errs}};
|
||||
if (validate.errors !== null) {
|
||||
if (errors) validate.errors.length = errors;
|
||||
else validate.errors = null;
|
||||
}
|
||||
delete {{=$data}}[{{=$key}}];
|
||||
}
|
||||
|
||||
{{# def.resetCompositeRule }}
|
||||
{{??}}
|
||||
{{# def.validateAdditional }}
|
||||
{{? $breakOnError }} if (!{{=$nextValid}}) break; {{?}}
|
||||
{{?}}
|
||||
{{?}}
|
||||
{{ it.errorPath = $currentErrorPath; }}
|
||||
{{?}}
|
||||
{{? $someProperties }}
|
||||
}
|
||||
{{?}}
|
||||
}
|
||||
|
||||
{{# def.ifResultValid }}
|
||||
{{?}}
|
||||
|
||||
{{ var $useDefaults = it.opts.useDefaults && !it.compositeRule; }}
|
||||
|
||||
{{? $schemaKeys.length }}
|
||||
{{~ $schemaKeys:$propertyKey }}
|
||||
{{ var $sch = $schema[$propertyKey]; }}
|
||||
|
||||
{{? {{# def.nonEmptySchema:$sch}} }}
|
||||
{{
|
||||
var $prop = it.util.getProperty($propertyKey)
|
||||
, $passData = $data + $prop
|
||||
, $hasDefault = $useDefaults && $sch.default !== undefined;
|
||||
$it.schema = $sch;
|
||||
$it.schemaPath = $schemaPath + $prop;
|
||||
$it.errSchemaPath = $errSchemaPath + '/' + it.util.escapeFragment($propertyKey);
|
||||
$it.errorPath = it.util.getPath(it.errorPath, $propertyKey, it.opts.jsonPointers);
|
||||
$it.dataPathArr[$dataNxt] = it.util.toQuotedString($propertyKey);
|
||||
}}
|
||||
|
||||
{{# def.generateSubschemaCode }}
|
||||
|
||||
{{? {{# def.willOptimize }} }}
|
||||
{{
|
||||
$code = {{# def._optimizeValidate }};
|
||||
var $useData = $passData;
|
||||
}}
|
||||
{{??}}
|
||||
{{ var $useData = $nextData; }}
|
||||
var {{=$nextData}} = {{=$passData}};
|
||||
{{?}}
|
||||
|
||||
{{? $hasDefault }}
|
||||
{{= $code }}
|
||||
{{??}}
|
||||
{{? $requiredHash && $requiredHash[$propertyKey] }}
|
||||
if ({{# def.noPropertyInData }}) {
|
||||
{{=$nextValid}} = false;
|
||||
{{
|
||||
var $currentErrorPath = it.errorPath
|
||||
, $currErrSchemaPath = $errSchemaPath
|
||||
, $missingProperty = it.util.escapeQuotes($propertyKey);
|
||||
if (it.opts._errorDataPathProperty) {
|
||||
it.errorPath = it.util.getPath($currentErrorPath, $propertyKey, it.opts.jsonPointers);
|
||||
}
|
||||
$errSchemaPath = it.errSchemaPath + '/required';
|
||||
}}
|
||||
{{# def.error:'required' }}
|
||||
{{ $errSchemaPath = $currErrSchemaPath; }}
|
||||
{{ it.errorPath = $currentErrorPath; }}
|
||||
} else {
|
||||
{{??}}
|
||||
{{? $breakOnError }}
|
||||
if ({{# def.noPropertyInData }}) {
|
||||
{{=$nextValid}} = true;
|
||||
} else {
|
||||
{{??}}
|
||||
if ({{=$useData}} !== undefined
|
||||
{{? $ownProperties }}
|
||||
&& {{# def.isOwnProperty }}
|
||||
{{?}}
|
||||
) {
|
||||
{{?}}
|
||||
{{?}}
|
||||
|
||||
{{= $code }}
|
||||
}
|
||||
{{?}} {{ /* $hasDefault */ }}
|
||||
{{?}} {{ /* def.nonEmptySchema */ }}
|
||||
|
||||
{{# def.ifResultValid }}
|
||||
{{~}}
|
||||
{{?}}
|
||||
|
||||
{{? $pPropertyKeys.length }}
|
||||
{{~ $pPropertyKeys:$pProperty }}
|
||||
{{ var $sch = $pProperties[$pProperty]; }}
|
||||
|
||||
{{? {{# def.nonEmptySchema:$sch}} }}
|
||||
{{
|
||||
$it.schema = $sch;
|
||||
$it.schemaPath = it.schemaPath + '.patternProperties' + it.util.getProperty($pProperty);
|
||||
$it.errSchemaPath = it.errSchemaPath + '/patternProperties/'
|
||||
+ it.util.escapeFragment($pProperty);
|
||||
}}
|
||||
|
||||
{{# def.iterateProperties }}
|
||||
if ({{= it.usePattern($pProperty) }}.test({{=$key}})) {
|
||||
{{
|
||||
$it.errorPath = it.util.getPathExpr(it.errorPath, $key, it.opts.jsonPointers);
|
||||
var $passData = $data + '[' + $key + ']';
|
||||
$it.dataPathArr[$dataNxt] = $key;
|
||||
}}
|
||||
|
||||
{{# def.generateSubschemaCode }}
|
||||
{{# def.optimizeValidate }}
|
||||
|
||||
{{? $breakOnError }} if (!{{=$nextValid}}) break; {{?}}
|
||||
}
|
||||
{{? $breakOnError }} else {{=$nextValid}} = true; {{?}}
|
||||
}
|
||||
|
||||
{{# def.ifResultValid }}
|
||||
{{?}} {{ /* def.nonEmptySchema */ }}
|
||||
{{~}}
|
||||
{{?}}
|
||||
|
||||
|
||||
{{? $breakOnError }}
|
||||
{{= $closingBraces }}
|
||||
if ({{=$errs}} == errors) {
|
||||
{{?}}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
{{# def.definitions }}
|
||||
{{# def.errors }}
|
||||
{{# def.setupKeyword }}
|
||||
{{# def.setupNextLevel }}
|
||||
|
||||
var {{=$errs}} = errors;
|
||||
|
||||
{{? {{# def.nonEmptySchema:$schema }} }}
|
||||
{{
|
||||
$it.schema = $schema;
|
||||
$it.schemaPath = $schemaPath;
|
||||
$it.errSchemaPath = $errSchemaPath;
|
||||
}}
|
||||
|
||||
{{
|
||||
var $key = 'key' + $lvl
|
||||
, $idx = 'idx' + $lvl
|
||||
, $i = 'i' + $lvl
|
||||
, $invalidName = '\' + ' + $key + ' + \''
|
||||
, $dataNxt = $it.dataLevel = it.dataLevel + 1
|
||||
, $nextData = 'data' + $dataNxt
|
||||
, $dataProperties = 'dataProperties' + $lvl
|
||||
, $ownProperties = it.opts.ownProperties
|
||||
, $currentBaseId = it.baseId;
|
||||
}}
|
||||
|
||||
{{? $ownProperties }}
|
||||
var {{=$dataProperties}} = undefined;
|
||||
{{?}}
|
||||
{{# def.iterateProperties }}
|
||||
var startErrs{{=$lvl}} = errors;
|
||||
|
||||
{{ var $passData = $key; }}
|
||||
{{# def.setCompositeRule }}
|
||||
{{# def.generateSubschemaCode }}
|
||||
{{# def.optimizeValidate }}
|
||||
{{# def.resetCompositeRule }}
|
||||
|
||||
if (!{{=$nextValid}}) {
|
||||
for (var {{=$i}}=startErrs{{=$lvl}}; {{=$i}}<errors; {{=$i}}++) {
|
||||
vErrors[{{=$i}}].propertyName = {{=$key}};
|
||||
}
|
||||
{{# def.extraError:'propertyNames' }}
|
||||
{{? $breakOnError }} break; {{?}}
|
||||
}
|
||||
}
|
||||
{{?}}
|
||||
|
||||
{{? $breakOnError }}
|
||||
{{= $closingBraces }}
|
||||
if ({{=$errs}} == errors) {
|
||||
{{?}}
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
{{# def.definitions }}
|
||||
{{# def.errors }}
|
||||
{{# def.setupKeyword }}
|
||||
|
||||
{{## def._validateRef:_v:
|
||||
{{? it.opts.passContext }}
|
||||
{{=_v}}.call(this,
|
||||
{{??}}
|
||||
{{=_v}}(
|
||||
{{?}}
|
||||
{{=$data}}, {{# def.dataPath }}{{# def.passParentData }}, rootData)
|
||||
#}}
|
||||
|
||||
{{ var $async, $refCode; }}
|
||||
{{? $schema == '#' || $schema == '#/' }}
|
||||
{{
|
||||
if (it.isRoot) {
|
||||
$async = it.async;
|
||||
$refCode = 'validate';
|
||||
} else {
|
||||
$async = it.root.schema.$async === true;
|
||||
$refCode = 'root.refVal[0]';
|
||||
}
|
||||
}}
|
||||
{{??}}
|
||||
{{ var $refVal = it.resolveRef(it.baseId, $schema, it.isRoot); }}
|
||||
{{? $refVal === undefined }}
|
||||
{{ var $message = it.MissingRefError.message(it.baseId, $schema); }}
|
||||
{{? it.opts.missingRefs == 'fail' }}
|
||||
{{ it.logger.error($message); }}
|
||||
{{# def.error:'$ref' }}
|
||||
{{? $breakOnError }} if (false) { {{?}}
|
||||
{{?? it.opts.missingRefs == 'ignore' }}
|
||||
{{ it.logger.warn($message); }}
|
||||
{{? $breakOnError }} if (true) { {{?}}
|
||||
{{??}}
|
||||
{{ throw new it.MissingRefError(it.baseId, $schema, $message); }}
|
||||
{{?}}
|
||||
{{?? $refVal.inline }}
|
||||
{{# def.setupNextLevel }}
|
||||
{{
|
||||
$it.schema = $refVal.schema;
|
||||
$it.schemaPath = '';
|
||||
$it.errSchemaPath = $schema;
|
||||
}}
|
||||
{{ var $code = it.validate($it).replace(/validate\.schema/g, $refVal.code); }}
|
||||
{{= $code }}
|
||||
{{? $breakOnError}}
|
||||
if ({{=$nextValid}}) {
|
||||
{{?}}
|
||||
{{??}}
|
||||
{{
|
||||
$async = $refVal.$async === true || (it.async && $refVal.$async !== false);
|
||||
$refCode = $refVal.code;
|
||||
}}
|
||||
{{?}}
|
||||
{{?}}
|
||||
|
||||
{{? $refCode }}
|
||||
{{# def.beginDefOut}}
|
||||
{{# def._validateRef:$refCode }}
|
||||
{{# def.storeDefOut:__callValidate }}
|
||||
|
||||
{{? $async }}
|
||||
{{ if (!it.async) throw new Error('async schema referenced by sync schema'); }}
|
||||
{{? $breakOnError }} var {{=$valid}}; {{?}}
|
||||
try {
|
||||
await {{=__callValidate}};
|
||||
{{? $breakOnError }} {{=$valid}} = true; {{?}}
|
||||
} catch (e) {
|
||||
if (!(e instanceof ValidationError)) throw e;
|
||||
if (vErrors === null) vErrors = e.errors;
|
||||
else vErrors = vErrors.concat(e.errors);
|
||||
errors = vErrors.length;
|
||||
{{? $breakOnError }} {{=$valid}} = false; {{?}}
|
||||
}
|
||||
{{? $breakOnError }} if ({{=$valid}}) { {{?}}
|
||||
{{??}}
|
||||
if (!{{=__callValidate}}) {
|
||||
if (vErrors === null) vErrors = {{=$refCode}}.errors;
|
||||
else vErrors = vErrors.concat({{=$refCode}}.errors);
|
||||
errors = vErrors.length;
|
||||
} {{? $breakOnError }} else { {{?}}
|
||||
{{?}}
|
||||
{{?}}
|
||||
Loaded 100 of 5220 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user