Agregado toping en los menus

This commit is contained in:
Pablinux
2025-05-25 12:10:15 -05:00
parent c7aabd4d1f
commit 0b8549c63c
53 changed files with 3235 additions and 2916 deletions

View File

@@ -67,6 +67,13 @@ los iconos se usado son de font awesome
buscar iconos buscar iconos
(https://fontawesome.com/search) (https://fontawesome.com/search)
## compilacion de proyecto
npm install pkg --save
npm run build-win
npm run build-linux
npm run build-mac
reemplazar axios por node fetch.. ya que causa problemas con pkg:
npm install node-fetch@2
## Autores ## Autores
| [![](https://avatars.githubusercontent.com/u/27124364?s=96&v=4)]([https://github.com/telcotronics](https://github.com/telcotronics)) | [![](https://avatars.githubusercontent.com/u/27124364?s=96&v=4)]([https://github.com/telcotronics](https://github.com/telcotronics))

View File

@@ -1,3 +1,10 @@
1.20.3 / 2024-09-10
===================
* deps: qs@6.13.0
* add `depth` option to customize the depth level in the parser
* IMPORTANT: The default `depth` level for parsing URL-encoded data is now `32` (previously was `Infinity`)
1.20.2 / 2023-02-21 1.20.2 / 2023-02-21
=================== ===================

11
node_modules/body-parser/README.md generated vendored
View File

@@ -4,6 +4,7 @@
[![NPM Downloads][npm-downloads-image]][npm-url] [![NPM Downloads][npm-downloads-image]][npm-url]
[![Build Status][ci-image]][ci-url] [![Build Status][ci-image]][ci-url]
[![Test Coverage][coveralls-image]][coveralls-url] [![Test Coverage][coveralls-image]][coveralls-url]
[![OpenSSF Scorecard Badge][ossf-scorecard-badge]][ossf-scorecard-visualizer]
Node.js body parsing middleware. Node.js body parsing middleware.
@@ -277,6 +278,10 @@ The `verify` option, if supplied, is called as `verify(req, res, buf, encoding)`
where `buf` is a `Buffer` of the raw request body and `encoding` is the where `buf` is a `Buffer` of the raw request body and `encoding` is the
encoding of the request. The parsing can be aborted by throwing an error. encoding of the request. The parsing can be aborted by throwing an error.
#### depth
The `depth` option is used to configure the maximum depth of the `qs` library when `extended` is `true`. This allows you to limit the amount of keys that are parsed and can be useful to prevent certain types of abuse. Defaults to `32`. It is recommended to keep this value as low as possible.
## Errors ## Errors
The middlewares provided by this module create errors using the The middlewares provided by this module create errors using the
@@ -373,6 +378,10 @@ as well as in the `encoding` property. The `status` property is set to `415`,
the `type` property is set to `'encoding.unsupported'`, and the `encoding` the `type` property is set to `'encoding.unsupported'`, and the `encoding`
property is set to the encoding that is unsupported. property is set to the encoding that is unsupported.
### The input exceeded the depth
This error occurs when using `bodyParser.urlencoded` with the `extended` property set to `true` and the input exceeds the configured `depth` option. The `status` property is set to `400`. It is recommended to review the `depth` option and evaluate if it requires a higher value. When the `depth` option is set to `32` (default value), the error will not be thrown.
## Examples ## Examples
### Express/Connect top-level generic ### Express/Connect top-level generic
@@ -463,3 +472,5 @@ app.use(bodyParser.text({ type: 'text/html' }))
[npm-downloads-image]: https://badgen.net/npm/dm/body-parser [npm-downloads-image]: https://badgen.net/npm/dm/body-parser
[npm-url]: https://npmjs.org/package/body-parser [npm-url]: https://npmjs.org/package/body-parser
[npm-version-image]: https://badgen.net/npm/v/body-parser [npm-version-image]: https://badgen.net/npm/v/body-parser
[ossf-scorecard-badge]: https://api.scorecard.dev/projects/github.com/expressjs/body-parser/badge
[ossf-scorecard-visualizer]: https://ossf.github.io/scorecard-visualizer/#/projects/github.com/expressjs/body-parser

View File

@@ -55,6 +55,9 @@ function urlencoded (options) {
: opts.limit : opts.limit
var type = opts.type || 'application/x-www-form-urlencoded' var type = opts.type || 'application/x-www-form-urlencoded'
var verify = opts.verify || false var verify = opts.verify || false
var depth = typeof opts.depth !== 'number'
? Number(opts.depth || 32)
: opts.depth
if (verify !== false && typeof verify !== 'function') { if (verify !== false && typeof verify !== 'function') {
throw new TypeError('option verify must be function') throw new TypeError('option verify must be function')
@@ -118,7 +121,8 @@ function urlencoded (options) {
encoding: charset, encoding: charset,
inflate: inflate, inflate: inflate,
limit: limit, limit: limit,
verify: verify verify: verify,
depth: depth
}) })
} }
} }
@@ -133,12 +137,20 @@ function extendedparser (options) {
var parameterLimit = options.parameterLimit !== undefined var parameterLimit = options.parameterLimit !== undefined
? options.parameterLimit ? options.parameterLimit
: 1000 : 1000
var depth = typeof options.depth !== 'number'
? Number(options.depth || 32)
: options.depth
var parse = parser('qs') var parse = parser('qs')
if (isNaN(parameterLimit) || parameterLimit < 1) { if (isNaN(parameterLimit) || parameterLimit < 1) {
throw new TypeError('option parameterLimit must be a positive number') throw new TypeError('option parameterLimit must be a positive number')
} }
if (isNaN(depth) || depth < 0) {
throw new TypeError('option depth must be a zero or a positive number')
}
if (isFinite(parameterLimit)) { if (isFinite(parameterLimit)) {
parameterLimit = parameterLimit | 0 parameterLimit = parameterLimit | 0
} }
@@ -156,12 +168,23 @@ function extendedparser (options) {
var arrayLimit = Math.max(100, paramCount) var arrayLimit = Math.max(100, paramCount)
debug('parse extended urlencoding') debug('parse extended urlencoding')
try {
return parse(body, { return parse(body, {
allowPrototypes: true, allowPrototypes: true,
arrayLimit: arrayLimit, arrayLimit: arrayLimit,
depth: Infinity, depth: depth,
strictDepth: true,
parameterLimit: parameterLimit parameterLimit: parameterLimit
}) })
} catch (err) {
if (err instanceof RangeError) {
throw createError(400, 'The input exceeded the depth', {
type: 'querystring.parse.rangeError'
})
} else {
throw err
}
}
} }
} }

View File

@@ -1,7 +1,7 @@
{ {
"name": "body-parser", "name": "body-parser",
"description": "Node.js body parsing middleware", "description": "Node.js body parsing middleware",
"version": "1.20.2", "version": "1.20.3",
"contributors": [ "contributors": [
"Douglas Christopher Wilson <doug@somethingdoug.com>", "Douglas Christopher Wilson <doug@somethingdoug.com>",
"Jonathan Ong <me@jongleberry.com> (http://jongleberry.com)" "Jonathan Ong <me@jongleberry.com> (http://jongleberry.com)"
@@ -17,7 +17,7 @@
"http-errors": "2.0.0", "http-errors": "2.0.0",
"iconv-lite": "0.4.24", "iconv-lite": "0.4.24",
"on-finished": "2.4.1", "on-finished": "2.4.1",
"qs": "6.11.0", "qs": "6.13.0",
"raw-body": "2.5.2", "raw-body": "2.5.2",
"type-is": "~1.6.18", "type-is": "~1.6.18",
"unpipe": "1.0.0" "unpipe": "1.0.0"

147
node_modules/cookie/HISTORY.md generated vendored
View File

@@ -1,147 +0,0 @@
0.6.0 / 2023-11-06
==================
* Add `partitioned` option
0.5.0 / 2022-04-11
==================
* Add `priority` option
* Fix `expires` option to reject invalid dates
* perf: improve default decode speed
* perf: remove slow string split in parse
0.4.2 / 2022-02-02
==================
* perf: read value only when assigning in parse
* perf: remove unnecessary regexp in parse
0.4.1 / 2020-04-21
==================
* Fix `maxAge` option to reject invalid values
0.4.0 / 2019-05-15
==================
* Add `SameSite=None` support
0.3.1 / 2016-05-26
==================
* Fix `sameSite: true` to work with draft-7 clients
- `true` now sends `SameSite=Strict` instead of `SameSite`
0.3.0 / 2016-05-26
==================
* Add `sameSite` option
- Replaces `firstPartyOnly` option, never implemented by browsers
* Improve error message when `encode` is not a function
* Improve error message when `expires` is not a `Date`
0.2.4 / 2016-05-20
==================
* perf: enable strict mode
* perf: use for loop in parse
* perf: use string concatenation for serialization
0.2.3 / 2015-10-25
==================
* Fix cookie `Max-Age` to never be a floating point number
0.2.2 / 2015-09-17
==================
* Fix regression when setting empty cookie value
- Ease the new restriction, which is just basic header-level validation
* Fix typo in invalid value errors
0.2.1 / 2015-09-17
==================
* Throw on invalid values provided to `serialize`
- Ensures the resulting string is a valid HTTP header value
0.2.0 / 2015-08-13
==================
* Add `firstPartyOnly` option
* Throw better error for invalid argument to parse
* perf: hoist regular expression
0.1.5 / 2015-09-17
==================
* Fix regression when setting empty cookie value
- Ease the new restriction, which is just basic header-level validation
* Fix typo in invalid value errors
0.1.4 / 2015-09-17
==================
* Throw better error for invalid argument to parse
* Throw on invalid values provided to `serialize`
- Ensures the resulting string is a valid HTTP header value
0.1.3 / 2015-05-19
==================
* Reduce the scope of try-catch deopt
* Remove argument reassignments
0.1.2 / 2014-04-16
==================
* Remove unnecessary files from npm package
0.1.1 / 2014-02-23
==================
* Fix bad parse when cookie value contained a comma
* Fix support for `maxAge` of `0`
0.1.0 / 2013-05-01
==================
* Add `decode` option
* Add `encode` option
0.0.6 / 2013-04-08
==================
* Ignore cookie parts missing `=`
0.0.5 / 2012-10-29
==================
* Return raw cookie value if value unescape errors
0.0.4 / 2012-06-21
==================
* Use encode/decodeURIComponent for cookie encoding/decoding
- Improve server/client interoperability
0.0.3 / 2012-06-06
==================
* Only escape special characters per the cookie RFC
0.0.2 / 2012-06-01
==================
* Fix `maxAge` option to not throw error
0.0.1 / 2012-05-28
==================
* Add more tests
0.0.0 / 2012-05-28
==================
* Initial release

174
node_modules/cookie/index.js generated vendored
View File

@@ -23,14 +23,66 @@ exports.serialize = serialize;
var __toString = Object.prototype.toString var __toString = Object.prototype.toString
/** /**
* RegExp to match field-content in RFC 7230 sec 3.2 * RegExp to match cookie-name in RFC 6265 sec 4.1.1
* This refers out to the obsoleted definition of token in RFC 2616 sec 2.2
* which has been replaced by the token definition in RFC 7230 appendix B.
* *
* field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ] * cookie-name = token
* field-vchar = VCHAR / obs-text * token = 1*tchar
* obs-text = %x80-FF * tchar = "!" / "#" / "$" / "%" / "&" / "'" /
* "*" / "+" / "-" / "." / "^" / "_" /
* "`" / "|" / "~" / DIGIT / ALPHA
*/ */
var fieldContentRegExp = /^[\u0009\u0020-\u007e\u0080-\u00ff]+$/; var cookieNameRegExp = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
/**
* RegExp to match cookie-value in RFC 6265 sec 4.1.1
*
* cookie-value = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE )
* cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E
* ; US-ASCII characters excluding CTLs,
* ; whitespace DQUOTE, comma, semicolon,
* ; and backslash
*/
var cookieValueRegExp = /^("?)[\u0021\u0023-\u002B\u002D-\u003A\u003C-\u005B\u005D-\u007E]*\1$/;
/**
* RegExp to match domain-value in RFC 6265 sec 4.1.1
*
* domain-value = <subdomain>
* ; defined in [RFC1034], Section 3.5, as
* ; enhanced by [RFC1123], Section 2.1
* <subdomain> = <label> | <subdomain> "." <label>
* <label> = <let-dig> [ [ <ldh-str> ] <let-dig> ]
* Labels must be 63 characters or less.
* 'let-dig' not 'letter' in the first char, per RFC1123
* <ldh-str> = <let-dig-hyp> | <let-dig-hyp> <ldh-str>
* <let-dig-hyp> = <let-dig> | "-"
* <let-dig> = <letter> | <digit>
* <letter> = any one of the 52 alphabetic characters A through Z in
* upper case and a through z in lower case
* <digit> = any one of the ten digits 0 through 9
*
* Keep support for leading dot: https://github.com/jshttp/cookie/issues/173
*
* > (Note that a leading %x2E ("."), if present, is ignored even though that
* character is not permitted, but a trailing %x2E ("."), if present, will
* cause the user agent to ignore the attribute.)
*/
var domainValueRegExp = /^([.]?[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)([.][a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)*$/i;
/**
* RegExp to match path-value in RFC 6265 sec 4.1.1
*
* path-value = <any CHAR except CTLs or ";">
* CHAR = %x01-7F
* ; defined in RFC 5234 appendix B.1
*/
var pathValueRegExp = /^[\u0020-\u003A\u003D-\u007E]*$/;
/** /**
* Parse a cookie header. * Parse a cookie header.
@@ -39,107 +91,128 @@ var fieldContentRegExp = /^[\u0009\u0020-\u007e\u0080-\u00ff]+$/;
* The object has the various cookies as keys(names) => values * The object has the various cookies as keys(names) => values
* *
* @param {string} str * @param {string} str
* @param {object} [options] * @param {object} [opt]
* @return {object} * @return {object}
* @public * @public
*/ */
function parse(str, options) { function parse(str, opt) {
if (typeof str !== 'string') { if (typeof str !== 'string') {
throw new TypeError('argument str must be a string'); throw new TypeError('argument str must be a string');
} }
var obj = {} var obj = {};
var opt = options || {}; var len = str.length;
var dec = opt.decode || decode; // RFC 6265 sec 4.1.1, RFC 2616 2.2 defines a cookie name consists of one char minimum, plus '='.
if (len < 2) return obj;
var index = 0 var dec = (opt && opt.decode) || decode;
while (index < str.length) { var index = 0;
var eqIdx = str.indexOf('=', index) var eqIdx = 0;
var endIdx = 0;
// no more cookie pairs do {
if (eqIdx === -1) { eqIdx = str.indexOf('=', index);
break if (eqIdx === -1) break; // No more cookie pairs.
}
var endIdx = str.indexOf(';', index) endIdx = str.indexOf(';', index);
if (endIdx === -1) { if (endIdx === -1) {
endIdx = str.length endIdx = len;
} else if (endIdx < eqIdx) { } else if (eqIdx > endIdx) {
// backtrack on prior semicolon // backtrack on prior semicolon
index = str.lastIndexOf(';', eqIdx - 1) + 1 index = str.lastIndexOf(';', eqIdx - 1) + 1;
continue continue;
} }
var key = str.slice(index, eqIdx).trim() var keyStartIdx = startIndex(str, index, eqIdx);
var keyEndIdx = endIndex(str, eqIdx, keyStartIdx);
var key = str.slice(keyStartIdx, keyEndIdx);
// only assign once // only assign once
if (undefined === obj[key]) { if (!obj.hasOwnProperty(key)) {
var val = str.slice(eqIdx + 1, endIdx).trim() var valStartIdx = startIndex(str, eqIdx + 1, endIdx);
var valEndIdx = endIndex(str, endIdx, valStartIdx);
// quoted values if (str.charCodeAt(valStartIdx) === 0x22 /* " */ && str.charCodeAt(valEndIdx - 1) === 0x22 /* " */) {
if (val.charCodeAt(0) === 0x22) { valStartIdx++;
val = val.slice(1, -1) valEndIdx--;
} }
var val = str.slice(valStartIdx, valEndIdx);
obj[key] = tryDecode(val, dec); obj[key] = tryDecode(val, dec);
} }
index = endIdx + 1 index = endIdx + 1
} } while (index < len);
return obj; return obj;
} }
function startIndex(str, index, max) {
do {
var code = str.charCodeAt(index);
if (code !== 0x20 /* */ && code !== 0x09 /* \t */) return index;
} while (++index < max);
return max;
}
function endIndex(str, index, min) {
while (index > min) {
var code = str.charCodeAt(--index);
if (code !== 0x20 /* */ && code !== 0x09 /* \t */) return index + 1;
}
return min;
}
/** /**
* Serialize data into a cookie header. * Serialize data into a cookie header.
* *
* Serialize the a name value pair into a cookie string suitable for * Serialize a name value pair into a cookie string suitable for
* http headers. An optional options object specified cookie parameters. * http headers. An optional options object specifies cookie parameters.
* *
* serialize('foo', 'bar', { httpOnly: true }) * serialize('foo', 'bar', { httpOnly: true })
* => "foo=bar; httpOnly" * => "foo=bar; httpOnly"
* *
* @param {string} name * @param {string} name
* @param {string} val * @param {string} val
* @param {object} [options] * @param {object} [opt]
* @return {string} * @return {string}
* @public * @public
*/ */
function serialize(name, val, options) { function serialize(name, val, opt) {
var opt = options || {}; var enc = (opt && opt.encode) || encodeURIComponent;
var enc = opt.encode || encode;
if (typeof enc !== 'function') { if (typeof enc !== 'function') {
throw new TypeError('option encode is invalid'); throw new TypeError('option encode is invalid');
} }
if (!fieldContentRegExp.test(name)) { if (!cookieNameRegExp.test(name)) {
throw new TypeError('argument name is invalid'); throw new TypeError('argument name is invalid');
} }
var value = enc(val); var value = enc(val);
if (value && !fieldContentRegExp.test(value)) { if (!cookieValueRegExp.test(value)) {
throw new TypeError('argument val is invalid'); throw new TypeError('argument val is invalid');
} }
var str = name + '=' + value; var str = name + '=' + value;
if (!opt) return str;
if (null != opt.maxAge) { if (null != opt.maxAge) {
var maxAge = opt.maxAge - 0; var maxAge = Math.floor(opt.maxAge);
if (isNaN(maxAge) || !isFinite(maxAge)) { if (!isFinite(maxAge)) {
throw new TypeError('option maxAge is invalid') throw new TypeError('option maxAge is invalid')
} }
str += '; Max-Age=' + Math.floor(maxAge); str += '; Max-Age=' + maxAge;
} }
if (opt.domain) { if (opt.domain) {
if (!fieldContentRegExp.test(opt.domain)) { if (!domainValueRegExp.test(opt.domain)) {
throw new TypeError('option domain is invalid'); throw new TypeError('option domain is invalid');
} }
@@ -147,7 +220,7 @@ function serialize(name, val, options) {
} }
if (opt.path) { if (opt.path) {
if (!fieldContentRegExp.test(opt.path)) { if (!pathValueRegExp.test(opt.path)) {
throw new TypeError('option path is invalid'); throw new TypeError('option path is invalid');
} }
@@ -178,8 +251,7 @@ function serialize(name, val, options) {
if (opt.priority) { if (opt.priority) {
var priority = typeof opt.priority === 'string' var priority = typeof opt.priority === 'string'
? opt.priority.toLowerCase() ? opt.priority.toLowerCase() : opt.priority;
: opt.priority
switch (priority) { switch (priority) {
case 'low': case 'low':
@@ -234,17 +306,6 @@ function decode (str) {
: str : str
} }
/**
* URL-encode value.
*
* @param {string} val
* @returns {string}
*/
function encode (val) {
return encodeURIComponent(val)
}
/** /**
* Determine if value is a Date. * Determine if value is a Date.
* *
@@ -253,8 +314,7 @@ function encode (val) {
*/ */
function isDate (val) { function isDate (val) {
return __toString.call(val) === '[object Date]' || return __toString.call(val) === '[object Date]';
val instanceof Date
} }
/** /**

6
node_modules/cookie/package.json generated vendored
View File

@@ -1,7 +1,7 @@
{ {
"name": "cookie", "name": "cookie",
"description": "HTTP server cookie parsing and serialization", "description": "HTTP server cookie parsing and serialization",
"version": "0.6.0", "version": "0.7.1",
"author": "Roman Shtylman <shtylman@gmail.com>", "author": "Roman Shtylman <shtylman@gmail.com>",
"contributors": [ "contributors": [
"Douglas Christopher Wilson <doug@somethingdoug.com>" "Douglas Christopher Wilson <doug@somethingdoug.com>"
@@ -29,6 +29,7 @@
"SECURITY.md", "SECURITY.md",
"index.js" "index.js"
], ],
"main": "index.js",
"engines": { "engines": {
"node": ">= 0.6" "node": ">= 0.6"
}, },
@@ -38,7 +39,6 @@
"test": "mocha --reporter spec --bail --check-leaks test/", "test": "mocha --reporter spec --bail --check-leaks test/",
"test-ci": "nyc --reporter=lcov --reporter=text npm test", "test-ci": "nyc --reporter=lcov --reporter=text npm test",
"test-cov": "nyc --reporter=html --reporter=text npm test", "test-cov": "nyc --reporter=html --reporter=text npm test",
"update-bench": "node scripts/update-benchmark.js", "update-bench": "node scripts/update-benchmark.js"
"version": "node scripts/version-history.js && git add HISTORY.md"
} }
} }

14
node_modules/encodeurl/HISTORY.md generated vendored
View File

@@ -1,14 +0,0 @@
1.0.2 / 2018-01-21
==================
* Fix encoding `%` as last character
1.0.1 / 2016-06-09
==================
* Fix encoding unpaired surrogates at start/end of string
1.0.0 / 2016-06-08
==================
* Initial release

57
node_modules/encodeurl/README.md generated vendored
View File

@@ -1,21 +1,11 @@
# encodeurl # Encode URL
[![NPM Version][npm-image]][npm-url] Encode a URL to a percent-encoded form, excluding already-encoded sequences.
[![NPM Downloads][downloads-image]][downloads-url]
[![Node.js Version][node-version-image]][node-version-url]
[![Build Status][travis-image]][travis-url]
[![Test Coverage][coveralls-image]][coveralls-url]
Encode a URL to a percent-encoded form, excluding already-encoded sequences
## Installation ## Installation
This is a [Node.js](https://nodejs.org/en/) module available through the
[npm registry](https://www.npmjs.com/). Installation is done using the
[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally):
```sh ```sh
$ npm install encodeurl npm install encodeurl
``` ```
## API ## API
@@ -28,24 +18,13 @@ var encodeUrl = require('encodeurl')
Encode a URL to a percent-encoded form, excluding already-encoded sequences. Encode a URL to a percent-encoded form, excluding already-encoded sequences.
This function will take an already-encoded URL and encode all the non-URL This function accepts a URL and encodes all the non-URL code points (as UTF-8 byte sequences). It will not encode the "%" character unless it is not part of a valid sequence (`%20` will be left as-is, but `%foo` will be encoded as `%25foo`).
code points (as UTF-8 byte sequences). This function will not encode the
"%" character unless it is not part of a valid sequence (`%20` will be
left as-is, but `%foo` will be encoded as `%25foo`).
This encode is meant to be "safe" and does not throw errors. It will try as This encode is meant to be "safe" and does not throw errors. It will try as hard as it can to properly encode the given URL, including replacing any raw, unpaired surrogate pairs with the Unicode replacement character prior to encoding.
hard as it can to properly encode the given URL, including replacing any raw,
unpaired surrogate pairs with the Unicode replacement character prior to
encoding.
This function is _similar_ to the intrinsic function `encodeURI`, except it
will not encode the `%` character if that is part of a valid sequence, will
not encode `[` and `]` (for IPv6 hostnames) and will replace raw, unpaired
surrogate pairs with the Unicode replacement character (instead of throwing).
## Examples ## Examples
### Encode a URL containing user-controled data ### Encode a URL containing user-controlled data
```js ```js
var encodeUrl = require('encodeurl') var encodeUrl = require('encodeurl')
@@ -97,6 +76,19 @@ http.createServer(function onRequest (req, res) {
}) })
``` ```
## Similarities
This function is _similar_ to the intrinsic function `encodeURI`. However, it will not encode:
* The `\`, `^`, or `|` characters
* The `%` character when it's part of a valid sequence
* `[` and `]` (for IPv6 hostnames)
* Replaces raw, unpaired surrogate pairs with the Unicode replacement character
As a result, the encoding aligns closely with the behavior in the [WHATWG URL specification][whatwg-url]. However, this package only encodes strings and does not do any URL parsing or formatting.
It is expected that any output from `new URL(url)` will not change when used with this package, as the output has already been encoded. Additionally, if we were to encode before `new URL(url)`, we do not expect the before and after encoded formats to be parsed any differently.
## Testing ## Testing
```sh ```sh
@@ -115,14 +107,3 @@ $ npm run lint
## License ## License
[MIT](LICENSE) [MIT](LICENSE)
[npm-image]: https://img.shields.io/npm/v/encodeurl.svg
[npm-url]: https://npmjs.org/package/encodeurl
[node-version-image]: https://img.shields.io/node/v/encodeurl.svg
[node-version-url]: https://nodejs.org/en/download
[travis-image]: https://img.shields.io/travis/pillarjs/encodeurl.svg
[travis-url]: https://travis-ci.org/pillarjs/encodeurl
[coveralls-image]: https://img.shields.io/coveralls/pillarjs/encodeurl.svg
[coveralls-url]: https://coveralls.io/r/pillarjs/encodeurl?branch=master
[downloads-image]: https://img.shields.io/npm/dm/encodeurl.svg
[downloads-url]: https://npmjs.org/package/encodeurl

2
node_modules/encodeurl/index.js generated vendored
View File

@@ -19,7 +19,7 @@ module.exports = encodeUrl
* @private * @private
*/ */
var ENCODE_CHARS_REGEXP = /(?:[^\x21\x25\x26-\x3B\x3D\x3F-\x5B\x5D\x5F\x61-\x7A\x7E]|%(?:[^0-9A-Fa-f]|[0-9A-Fa-f][^0-9A-Fa-f]|$))+/g var ENCODE_CHARS_REGEXP = /(?:[^\x21\x23-\x3B\x3D\x3F-\x5F\x61-\x7A\x7C\x7E]|%(?:[^0-9A-Fa-f]|[0-9A-Fa-f][^0-9A-Fa-f]|$))+/g
/** /**
* RegExp to match unmatched surrogate pair. * RegExp to match unmatched surrogate pair.

14
node_modules/encodeurl/package.json generated vendored
View File

@@ -1,7 +1,7 @@
{ {
"name": "encodeurl", "name": "encodeurl",
"description": "Encode a URL to a percent-encoded form, excluding already-encoded sequences", "description": "Encode a URL to a percent-encoded form, excluding already-encoded sequences",
"version": "1.0.2", "version": "2.0.0",
"contributors": [ "contributors": [
"Douglas Christopher Wilson <doug@somethingdoug.com>" "Douglas Christopher Wilson <doug@somethingdoug.com>"
], ],
@@ -13,12 +13,12 @@
], ],
"repository": "pillarjs/encodeurl", "repository": "pillarjs/encodeurl",
"devDependencies": { "devDependencies": {
"eslint": "3.19.0", "eslint": "5.11.1",
"eslint-config-standard": "10.2.1", "eslint-config-standard": "12.0.0",
"eslint-plugin-import": "2.8.0", "eslint-plugin-import": "2.14.0",
"eslint-plugin-node": "5.2.1", "eslint-plugin-node": "7.0.1",
"eslint-plugin-promise": "3.6.0", "eslint-plugin-promise": "4.0.1",
"eslint-plugin-standard": "3.0.1", "eslint-plugin-standard": "4.0.0",
"istanbul": "0.4.5", "istanbul": "0.4.5",
"mocha": "2.5.3" "mocha": "2.5.3"
}, },

41
node_modules/express/History.md generated vendored
View File

@@ -1,3 +1,44 @@
4.21.2 / 2024-11-06
==========
* deps: path-to-regexp@0.1.12
- Fix backtracking protection
* deps: path-to-regexp@0.1.11
- Throws an error on invalid path values
4.21.1 / 2024-10-08
==========
* Backported a fix for [CVE-2024-47764](https://nvd.nist.gov/vuln/detail/CVE-2024-47764)
4.21.0 / 2024-09-11
==========
* Deprecate `res.location("back")` and `res.redirect("back")` magic string
* deps: serve-static@1.16.2
* includes send@0.19.0
* deps: finalhandler@1.3.1
* deps: qs@6.13.0
4.20.0 / 2024-09-10
==========
* deps: serve-static@0.16.0
* Remove link renderization in html while redirecting
* deps: send@0.19.0
* Remove link renderization in html while redirecting
* deps: body-parser@0.6.0
* add `depth` option to customize the depth level in the parser
* IMPORTANT: The default `depth` level for parsing URL-encoded data is now `32` (previously was `Infinity`)
* Remove link renderization in html while using `res.redirect`
* deps: path-to-regexp@0.1.10
- Adds support for named matching groups in the routes using a regex
- Adds backtracking protection to parameters without regexes defined
* deps: encodeurl@~2.0.0
- Removes encoding of `\`, `|`, and `^` to align better with URL spec
* Deprecate passing `options.maxAge` and `options.expires` to `res.clearCookie`
- Will be ignored in v5, clearCookie will set a cookie with an expires in the past to instruct clients to delete the cookie
4.19.2 / 2024-03-25 4.19.2 / 2024-03-25
========== ==========

100
node_modules/express/Readme.md generated vendored
View File

@@ -1,10 +1,29 @@
[![Express Logo](https://i.cloudup.com/zfY6lL7eFa-3000x3000.png)](http://expressjs.com/) [![Express Logo](https://i.cloudup.com/zfY6lL7eFa-3000x3000.png)](http://expressjs.com/)
Fast, unopinionated, minimalist web framework for [Node.js](http://nodejs.org). **Fast, unopinionated, minimalist web framework for [Node.js](http://nodejs.org).**
**This project has a [Code of Conduct][].**
## Table of contents
* [Installation](#Installation)
* [Features](#Features)
* [Docs & Community](#docs--community)
* [Quick Start](#Quick-Start)
* [Running Tests](#Running-Tests)
* [Philosophy](#Philosophy)
* [Examples](#Examples)
* [Contributing to Express](#Contributing)
* [TC (Technical Committee)](#tc-technical-committee)
* [Triagers](#triagers)
* [License](#license)
[![NPM Version][npm-version-image]][npm-url] [![NPM Version][npm-version-image]][npm-url]
[![NPM Install Size][npm-install-size-image]][npm-install-size-url] [![NPM Install Size][npm-install-size-image]][npm-install-size-url]
[![NPM Downloads][npm-downloads-image]][npm-downloads-url] [![NPM Downloads][npm-downloads-image]][npm-downloads-url]
[![OpenSSF Scorecard Badge][ossf-scorecard-badge]][ossf-scorecard-visualizer]
```js ```js
const express = require('express') const express = require('express')
@@ -144,10 +163,82 @@ $ npm test
The original author of Express is [TJ Holowaychuk](https://github.com/tj) The original author of Express is [TJ Holowaychuk](https://github.com/tj)
The current lead maintainer is [Douglas Christopher Wilson](https://github.com/dougwilson)
[List of all contributors](https://github.com/expressjs/express/graphs/contributors) [List of all contributors](https://github.com/expressjs/express/graphs/contributors)
### TC (Technical Committee)
* [UlisesGascon](https://github.com/UlisesGascon) - **Ulises Gascón** (he/him)
* [jonchurch](https://github.com/jonchurch) - **Jon Church**
* [wesleytodd](https://github.com/wesleytodd) - **Wes Todd**
* [LinusU](https://github.com/LinusU) - **Linus Unnebäck**
* [blakeembrey](https://github.com/blakeembrey) - **Blake Embrey**
* [sheplu](https://github.com/sheplu) - **Jean Burellier**
* [crandmck](https://github.com/crandmck) - **Rand McKinney**
* [ctcpip](https://github.com/ctcpip) - **Chris de Almeida**
<details>
<summary>TC emeriti members</summary>
#### TC emeriti members
* [dougwilson](https://github.com/dougwilson) - **Douglas Wilson**
* [hacksparrow](https://github.com/hacksparrow) - **Hage Yaapa**
* [jonathanong](https://github.com/jonathanong) - **jongleberry**
* [niftylettuce](https://github.com/niftylettuce) - **niftylettuce**
* [troygoode](https://github.com/troygoode) - **Troy Goode**
</details>
### Triagers
* [aravindvnair99](https://github.com/aravindvnair99) - **Aravind Nair**
* [carpasse](https://github.com/carpasse) - **Carlos Serrano**
* [CBID2](https://github.com/CBID2) - **Christine Belzie**
* [enyoghasim](https://github.com/enyoghasim) - **David Enyoghasim**
* [UlisesGascon](https://github.com/UlisesGascon) - **Ulises Gascón** (he/him)
* [mertcanaltin](https://github.com/mertcanaltin) - **Mert Can Altin**
* [0ss](https://github.com/0ss) - **Salah**
* [import-brain](https://github.com/import-brain) - **Eric Cheng** (he/him)
* [3imed-jaberi](https://github.com/3imed-jaberi) - **Imed Jaberi**
* [dakshkhetan](https://github.com/dakshkhetan) - **Daksh Khetan** (he/him)
* [lucasraziel](https://github.com/lucasraziel) - **Lucas Soares Do Rego**
* [IamLizu](https://github.com/IamLizu) - **S M Mahmudul Hasan** (he/him)
* [Sushmeet](https://github.com/Sushmeet) - **Sushmeet Sunger**
<details>
<summary>Triagers emeriti members</summary>
#### Emeritus Triagers
* [AuggieH](https://github.com/AuggieH) - **Auggie Hudak**
* [G-Rath](https://github.com/G-Rath) - **Gareth Jones**
* [MohammadXroid](https://github.com/MohammadXroid) - **Mohammad Ayashi**
* [NawafSwe](https://github.com/NawafSwe) - **Nawaf Alsharqi**
* [NotMoni](https://github.com/NotMoni) - **Moni**
* [VigneshMurugan](https://github.com/VigneshMurugan) - **Vignesh Murugan**
* [davidmashe](https://github.com/davidmashe) - **David Ashe**
* [digitaIfabric](https://github.com/digitaIfabric) - **David**
* [e-l-i-s-e](https://github.com/e-l-i-s-e) - **Elise Bonner**
* [fed135](https://github.com/fed135) - **Frederic Charette**
* [firmanJS](https://github.com/firmanJS) - **Firman Abdul Hakim**
* [getspooky](https://github.com/getspooky) - **Yasser Ameur**
* [ghinks](https://github.com/ghinks) - **Glenn**
* [ghousemohamed](https://github.com/ghousemohamed) - **Ghouse Mohamed**
* [gireeshpunathil](https://github.com/gireeshpunathil) - **Gireesh Punathil**
* [jake32321](https://github.com/jake32321) - **Jake Reed**
* [jonchurch](https://github.com/jonchurch) - **Jon Church**
* [lekanikotun](https://github.com/lekanikotun) - **Troy Goode**
* [marsonya](https://github.com/marsonya) - **Lekan Ikotun**
* [mastermatt](https://github.com/mastermatt) - **Matt R. Wilson**
* [maxakuru](https://github.com/maxakuru) - **Max Edell**
* [mlrawlings](https://github.com/mlrawlings) - **Michael Rawlings**
* [rodion-arr](https://github.com/rodion-arr) - **Rodion Abdurakhimov**
* [sheplu](https://github.com/sheplu) - **Jean Burellier**
* [tarunyadav1](https://github.com/tarunyadav1) - **Tarun yadav**
* [tunniclm](https://github.com/tunniclm) - **Mike Tunnicliffe**
</details>
## License ## License
[MIT](LICENSE) [MIT](LICENSE)
@@ -164,3 +255,6 @@ The current lead maintainer is [Douglas Christopher Wilson](https://github.com/d
[npm-install-size-url]: https://packagephobia.com/result?p=express [npm-install-size-url]: https://packagephobia.com/result?p=express
[npm-url]: https://npmjs.org/package/express [npm-url]: https://npmjs.org/package/express
[npm-version-image]: https://badgen.net/npm/v/express [npm-version-image]: https://badgen.net/npm/v/express
[ossf-scorecard-badge]: https://api.scorecard.dev/projects/github.com/expressjs/express/badge
[ossf-scorecard-visualizer]: https://ossf.github.io/scorecard-visualizer/#/projects/github.com/expressjs/express
[Code of Conduct]: https://github.com/expressjs/express/blob/master/Code-Of-Conduct.md

21
node_modules/express/lib/response.js generated vendored
View File

@@ -55,7 +55,6 @@ module.exports = res
*/ */
var charsetRegExp = /;\s*charset\s*=/; var charsetRegExp = /;\s*charset\s*=/;
var schemaAndHostRegExp = /^(?:[a-zA-Z][a-zA-Z0-9+.-]*:)?\/\/[^\\\/\?]+/;
/** /**
* Set status `code`. * Set status `code`.
@@ -823,6 +822,14 @@ res.get = function(field){
*/ */
res.clearCookie = function clearCookie(name, options) { res.clearCookie = function clearCookie(name, options) {
if (options) {
if (options.maxAge) {
deprecate('res.clearCookie: Passing "options.maxAge" is deprecated. In v5.0.0 of Express, this option will be ignored, as res.clearCookie will automatically set cookies to expire immediately. Please update your code to omit this option.');
}
if (options.expires) {
deprecate('res.clearCookie: Passing "options.expires" is deprecated. In v5.0.0 of Express, this option will be ignored, as res.clearCookie will automatically set cookies to expire immediately. Please update your code to omit this option.');
}
}
var opts = merge({ expires: new Date(1), path: '/' }, options); var opts = merge({ expires: new Date(1), path: '/' }, options);
return this.cookie(name, '', opts); return this.cookie(name, '', opts);
@@ -909,19 +916,13 @@ res.location = function location(url) {
// "back" is an alias for the referrer // "back" is an alias for the referrer
if (url === 'back') { if (url === 'back') {
deprecate('res.location("back"): use res.location(req.get("Referrer") || "/") and refer to https://dub.sh/security-redirect for best practices');
loc = this.req.get('Referrer') || '/'; loc = this.req.get('Referrer') || '/';
} else { } else {
loc = String(url); loc = String(url);
} }
var m = schemaAndHostRegExp.exec(loc); return this.set('Location', encodeUrl(loc));
var pos = m ? m[0].length + 1 : 0;
// Only encode after host to avoid invalid encoding which can introduce
// vulnerabilities (e.g. `\\` to `%5C`).
loc = loc.slice(0, pos) + encodeUrl(loc.slice(pos));
return this.set('Location', loc);
}; };
/** /**
@@ -969,7 +970,7 @@ res.redirect = function redirect(url) {
html: function(){ html: function(){
var u = escapeHtml(address); var u = escapeHtml(address);
body = '<p>' + statuses.message[status] + '. Redirecting to <a href="' + u + '">' + u + '</a></p>' body = '<p>' + statuses.message[status] + '. Redirecting to ' + u + '</p>'
}, },
default: function(){ default: function(){

28
node_modules/express/package.json generated vendored
View File

@@ -1,7 +1,7 @@
{ {
"name": "express", "name": "express",
"description": "Fast, unopinionated, minimalist web framework", "description": "Fast, unopinionated, minimalist web framework",
"version": "4.19.2", "version": "4.21.2",
"author": "TJ Holowaychuk <tj@vision-media.ca>", "author": "TJ Holowaychuk <tj@vision-media.ca>",
"contributors": [ "contributors": [
"Aaron Heckmann <aaron.heckmann+github@gmail.com>", "Aaron Heckmann <aaron.heckmann+github@gmail.com>",
@@ -15,6 +15,10 @@
"license": "MIT", "license": "MIT",
"repository": "expressjs/express", "repository": "expressjs/express",
"homepage": "http://expressjs.com/", "homepage": "http://expressjs.com/",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
},
"keywords": [ "keywords": [
"express", "express",
"framework", "framework",
@@ -30,30 +34,30 @@
"dependencies": { "dependencies": {
"accepts": "~1.3.8", "accepts": "~1.3.8",
"array-flatten": "1.1.1", "array-flatten": "1.1.1",
"body-parser": "1.20.2", "body-parser": "1.20.3",
"content-disposition": "0.5.4", "content-disposition": "0.5.4",
"content-type": "~1.0.4", "content-type": "~1.0.4",
"cookie": "0.6.0", "cookie": "0.7.1",
"cookie-signature": "1.0.6", "cookie-signature": "1.0.6",
"debug": "2.6.9", "debug": "2.6.9",
"depd": "2.0.0", "depd": "2.0.0",
"encodeurl": "~1.0.2", "encodeurl": "~2.0.0",
"escape-html": "~1.0.3", "escape-html": "~1.0.3",
"etag": "~1.8.1", "etag": "~1.8.1",
"finalhandler": "1.2.0", "finalhandler": "1.3.1",
"fresh": "0.5.2", "fresh": "0.5.2",
"http-errors": "2.0.0", "http-errors": "2.0.0",
"merge-descriptors": "1.0.1", "merge-descriptors": "1.0.3",
"methods": "~1.1.2", "methods": "~1.1.2",
"on-finished": "2.4.1", "on-finished": "2.4.1",
"parseurl": "~1.3.3", "parseurl": "~1.3.3",
"path-to-regexp": "0.1.7", "path-to-regexp": "0.1.12",
"proxy-addr": "~2.0.7", "proxy-addr": "~2.0.7",
"qs": "6.11.0", "qs": "6.13.0",
"range-parser": "~1.2.1", "range-parser": "~1.2.1",
"safe-buffer": "5.2.1", "safe-buffer": "5.2.1",
"send": "0.18.0", "send": "0.19.0",
"serve-static": "1.15.0", "serve-static": "1.16.2",
"setprototypeof": "1.2.0", "setprototypeof": "1.2.0",
"statuses": "2.0.1", "statuses": "2.0.1",
"type-is": "~1.6.18", "type-is": "~1.6.18",
@@ -91,8 +95,8 @@
"scripts": { "scripts": {
"lint": "eslint .", "lint": "eslint .",
"test": "mocha --require test/support/env --reporter spec --bail --check-leaks test/ test/acceptance/", "test": "mocha --require test/support/env --reporter spec --bail --check-leaks test/ test/acceptance/",
"test-ci": "nyc --reporter=lcovonly --reporter=text npm test", "test-ci": "nyc --exclude examples --exclude test --exclude benchmarks --reporter=lcovonly --reporter=text npm test",
"test-cov": "nyc --reporter=html --reporter=text npm test", "test-cov": "nyc --exclude examples --exclude test --exclude benchmarks --reporter=html --reporter=text npm test",
"test-tap": "mocha --require test/support/env --reporter tap --check-leaks test/ test/acceptance/" "test-tap": "mocha --require test/support/env --reporter tap --check-leaks test/ test/acceptance/"
} }
} }

15
node_modules/finalhandler/HISTORY.md generated vendored
View File

@@ -1,3 +1,18 @@
v1.3.1 / 2024-09-11
==================
* deps: encodeurl@~2.0.0
v1.3.0 / 2024-09-03
==================
* ignore status message for HTTP/2 (#53)
v1.2.1 / 2024-09-02
==================
* Gracefully handle when handling an error and socket is null
1.2.0 / 2022-03-22 1.2.0 / 2022-03-22
================== ==================

View File

@@ -143,5 +143,5 @@ function logerror (err) {
[coveralls-url]: https://coveralls.io/r/pillarjs/finalhandler?branch=master [coveralls-url]: https://coveralls.io/r/pillarjs/finalhandler?branch=master
[downloads-image]: https://img.shields.io/npm/dm/finalhandler.svg [downloads-image]: https://img.shields.io/npm/dm/finalhandler.svg
[downloads-url]: https://npmjs.org/package/finalhandler [downloads-url]: https://npmjs.org/package/finalhandler
[github-actions-ci-image]: https://img.shields.io/github/workflow/status/pillarjs/finalhandler/ci/master?label=ci [github-actions-ci-image]: https://github.com/pillarjs/finalhandler/actions/workflows/ci.yml/badge.svg
[github-actions-ci-url]: https://github.com/jshttp/pillarjs/finalhandler?query=workflow%3Aci [github-actions-ci-url]: https://github.com/pillarjs/finalhandler/actions/workflows/ci.yml

5
node_modules/finalhandler/index.js generated vendored
View File

@@ -125,7 +125,9 @@ function finalhandler (req, res, options) {
// cannot actually respond // cannot actually respond
if (headersSent(res)) { if (headersSent(res)) {
debug('cannot %d after headers sent', status) debug('cannot %d after headers sent', status)
if (req.socket) {
req.socket.destroy() req.socket.destroy()
}
return return
} }
@@ -276,7 +278,10 @@ function send (req, res, status, headers, message) {
// response status // response status
res.statusCode = status res.statusCode = status
if (req.httpVersionMajor < 2) {
res.statusMessage = statuses.message[status] res.statusMessage = statuses.message[status]
}
// remove any content headers // remove any content headers
res.removeHeader('Content-Encoding') res.removeHeader('Content-Encoding')

View File

@@ -1,13 +1,13 @@
{ {
"name": "finalhandler", "name": "finalhandler",
"description": "Node.js final http responder", "description": "Node.js final http responder",
"version": "1.2.0", "version": "1.3.1",
"author": "Douglas Christopher Wilson <doug@somethingdoug.com>", "author": "Douglas Christopher Wilson <doug@somethingdoug.com>",
"license": "MIT", "license": "MIT",
"repository": "pillarjs/finalhandler", "repository": "pillarjs/finalhandler",
"dependencies": { "dependencies": {
"debug": "2.6.9", "debug": "2.6.9",
"encodeurl": "~1.0.2", "encodeurl": "~2.0.0",
"escape-html": "~1.0.3", "escape-html": "~1.0.3",
"on-finished": "2.4.1", "on-finished": "2.4.1",
"parseurl": "~1.3.3", "parseurl": "~1.3.3",
@@ -17,16 +17,16 @@
"devDependencies": { "devDependencies": {
"eslint": "7.32.0", "eslint": "7.32.0",
"eslint-config-standard": "14.1.1", "eslint-config-standard": "14.1.1",
"eslint-plugin-import": "2.25.4", "eslint-plugin-import": "2.26.0",
"eslint-plugin-markdown": "2.2.1", "eslint-plugin-markdown": "2.2.1",
"eslint-plugin-node": "11.1.0", "eslint-plugin-node": "11.1.0",
"eslint-plugin-promise": "5.2.0", "eslint-plugin-promise": "5.2.0",
"eslint-plugin-standard": "4.1.0", "eslint-plugin-standard": "4.1.0",
"mocha": "9.2.2", "mocha": "10.0.0",
"nyc": "15.1.0", "nyc": "15.1.0",
"readable-stream": "2.3.6", "readable-stream": "2.3.6",
"safe-buffer": "5.2.1", "safe-buffer": "5.2.1",
"supertest": "6.2.2" "supertest": "6.2.4"
}, },
"files": [ "files": [
"LICENSE", "LICENSE",
@@ -39,8 +39,9 @@
}, },
"scripts": { "scripts": {
"lint": "eslint .", "lint": "eslint .",
"test": "mocha --reporter spec --bail --check-leaks test/", "test": "mocha --reporter spec --check-leaks test/",
"test-ci": "nyc --reporter=lcovonly --reporter=text npm test", "test-ci": "nyc --reporter=lcovonly --reporter=text npm test",
"test-cov": "nyc --reporter=html --reporter=text npm test" "test-cov": "nyc --reporter=html --reporter=text npm test",
"test-inspect": "mocha --reporter spec --inspect --inspect-brk test/"
} }
} }

View File

@@ -1,4 +1,4 @@
# Merge Descriptors # merge-descriptors
[![NPM Version][npm-image]][npm-url] [![NPM Version][npm-image]][npm-url]
[![NPM Downloads][downloads-image]][downloads-url] [![NPM Downloads][downloads-image]][downloads-url]
@@ -27,12 +27,13 @@ animal.name === 'jon'
### merge(destination, source) ### merge(destination, source)
Redefines `destination`'s descriptors with `source`'s. Redefines `destination`'s descriptors with `source`'s. The return value is the
`destination` object.
### merge(destination, source, false) ### merge(destination, source, false)
Defines `source`'s descriptors on `destination` if `destination` does not have Defines `source`'s descriptors on `destination` if `destination` does not have
a descriptor by the same name. a descriptor by the same name. The return value is the `destination` object.
## License ## License

View File

@@ -47,7 +47,7 @@ function merge(dest, src, redefine) {
Object.getOwnPropertyNames(src).forEach(function forEachOwnPropertyName (name) { Object.getOwnPropertyNames(src).forEach(function forEachOwnPropertyName (name) {
if (!redefine && hasOwnProperty.call(dest, name)) { if (!redefine && hasOwnProperty.call(dest, name)) {
// Skip desriptor // Skip descriptor
return return
} }

View File

@@ -1,7 +1,7 @@
{ {
"name": "merge-descriptors", "name": "merge-descriptors",
"description": "Merge objects using descriptors", "description": "Merge objects using descriptors",
"version": "1.0.1", "version": "1.0.3",
"author": { "author": {
"name": "Jonathan Ong", "name": "Jonathan Ong",
"email": "me@jongleberry.com", "email": "me@jongleberry.com",
@@ -13,10 +13,17 @@
"Mike Grabowski <grabbou@gmail.com>" "Mike Grabowski <grabbou@gmail.com>"
], ],
"license": "MIT", "license": "MIT",
"repository": "component/merge-descriptors", "repository": "sindresorhus/merge-descriptors",
"funding": "https://github.com/sponsors/sindresorhus",
"devDependencies": { "devDependencies": {
"istanbul": "0.4.1", "eslint": "5.9.0",
"mocha": "1.21.5" "eslint-config-standard": "12.0.0",
"eslint-plugin-import": "2.14.0",
"eslint-plugin-node": "7.0.1",
"eslint-plugin-promise": "4.0.1",
"eslint-plugin-standard": "4.0.0",
"mocha": "5.2.0",
"nyc": "13.1.0"
}, },
"files": [ "files": [
"HISTORY.md", "HISTORY.md",
@@ -25,8 +32,8 @@
"index.js" "index.js"
], ],
"scripts": { "scripts": {
"test": "mocha --reporter spec --bail --check-leaks test/", "lint": "eslint .",
"test-ci": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/", "test": "mocha test/",
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/" "test-cov": "nyc --reporter=html --reporter=text npm test"
} }
} }

View File

@@ -1,36 +0,0 @@
0.1.7 / 2015-07-28
==================
* Fixed regression with escaped round brackets and matching groups.
0.1.6 / 2015-06-19
==================
* Replace `index` feature by outputting all parameters, unnamed and named.
0.1.5 / 2015-05-08
==================
* Add an index property for position in match result.
0.1.4 / 2015-03-05
==================
* Add license information
0.1.3 / 2014-07-06
==================
* Better array support
* Improved support for trailing slash in non-ending mode
0.1.0 / 2014-03-06
==================
* add options.end
0.0.2 / 2013-02-10
==================
* Update to match current express
* add .license property to component.json

109
node_modules/path-to-regexp/index.js generated vendored
View File

@@ -1,13 +1,13 @@
/** /**
* Expose `pathtoRegexp`. * Expose `pathToRegexp`.
*/ */
module.exports = pathtoRegexp; module.exports = pathToRegexp;
/** /**
* Match matching groups in a regular expression. * Match matching groups in a regular expression.
*/ */
var MATCHING_GROUP_REGEXP = /\((?!\?)/g; var MATCHING_GROUP_REGEXP = /\\.|\((?:\?<(.*?)>)?(?!\?)/g;
/** /**
* Normalize the given path string, * Normalize the given path string,
@@ -25,22 +25,27 @@ var MATCHING_GROUP_REGEXP = /\((?!\?)/g;
* @api private * @api private
*/ */
function pathtoRegexp(path, keys, options) { function pathToRegexp(path, keys, options) {
options = options || {}; options = options || {};
keys = keys || []; keys = keys || [];
var strict = options.strict; var strict = options.strict;
var end = options.end !== false; var end = options.end !== false;
var flags = options.sensitive ? '' : 'i'; var flags = options.sensitive ? '' : 'i';
var lookahead = options.lookahead !== false;
var extraOffset = 0; var extraOffset = 0;
var keysOffset = keys.length; var keysOffset = keys.length;
var i = 0; var i = 0;
var name = 0; var name = 0;
var pos = 0;
var backtrack = '';
var m; var m;
if (path instanceof RegExp) { if (path instanceof RegExp) {
while (m = MATCHING_GROUP_REGEXP.exec(path.source)) { while (m = MATCHING_GROUP_REGEXP.exec(path.source)) {
if (m[0][0] === '\\') continue;
keys.push({ keys.push({
name: name++, name: m[1] || name++,
optional: false, optional: false,
offset: m.index offset: m.index
}); });
@@ -54,20 +59,57 @@ function pathtoRegexp(path, keys, options) {
// the same keys and options instance into every generation to get // the same keys and options instance into every generation to get
// consistent matching groups before we join the sources together. // consistent matching groups before we join the sources together.
path = path.map(function (value) { path = path.map(function (value) {
return pathtoRegexp(value, keys, options).source; return pathToRegexp(value, keys, options).source;
}); });
return new RegExp('(?:' + path.join('|') + ')', flags); return new RegExp(path.join('|'), flags);
}
if (typeof path !== 'string') {
throw new TypeError('path must be a string, array of strings, or regular expression');
}
path = path.replace(
/\\.|(\/)?(\.)?:(\w+)(\(.*?\))?(\*)?(\?)?|[.*]|\/\(/g,
function (match, slash, format, key, capture, star, optional, offset) {
if (match[0] === '\\') {
backtrack += match;
pos += 2;
return match;
}
if (match === '.') {
backtrack += '\\.';
extraOffset += 1;
pos += 1;
return '\\.';
}
if (slash || format) {
backtrack = '';
} else {
backtrack += path.slice(pos, offset);
}
pos = offset + match.length;
if (match === '*') {
extraOffset += 3;
return '(.*)';
}
if (match === '/(') {
backtrack += '/';
extraOffset += 2;
return '/(?:';
} }
path = ('^' + path + (strict ? '' : path[path.length - 1] === '/' ? '?' : '/?'))
.replace(/\/\(/g, '/(?:')
.replace(/([\/\.])/g, '\\$1')
.replace(/(\\\/)?(\\\.)?:(\w+)(\(.*?\))?(\*)?(\?)?/g, function (match, slash, format, key, capture, star, optional, offset) {
slash = slash || ''; slash = slash || '';
format = format || ''; format = format ? '\\.' : '';
capture = capture || '([^\\/' + format + ']+?)';
optional = optional || ''; optional = optional || '';
capture = capture ?
capture.replace(/\\.|\*/, function (m) { return m === '*' ? '(.*)' : m; }) :
(backtrack ? '((?:(?!/|' + backtrack + ').)+?)' : '([^/' + format + ']+?)');
keys.push({ keys.push({
name: key, name: key,
@@ -75,41 +117,20 @@ function pathtoRegexp(path, keys, options) {
offset: offset + extraOffset offset: offset + extraOffset
}); });
var result = '' var result = '(?:'
+ (optional ? '' : slash) + format + slash + capture
+ '(?:' + (star ? '((?:[/' + format + '].+?)?)' : '')
+ format + (optional ? slash : '') + capture
+ (star ? '((?:[\\/' + format + '].+?)?)' : '')
+ ')' + ')'
+ optional; + optional;
extraOffset += result.length - match.length; extraOffset += result.length - match.length;
return result; return result;
})
.replace(/\*/g, function (star, index) {
var len = keys.length
while (len-- > keysOffset && keys[len].offset > index) {
keys[len].offset += 3; // Replacement length minus asterisk length.
}
return '(.*)';
}); });
// This is a workaround for handling unnamed matching groups. // This is a workaround for handling unnamed matching groups.
while (m = MATCHING_GROUP_REGEXP.exec(path)) { while (m = MATCHING_GROUP_REGEXP.exec(path)) {
var escapeCount = 0; if (m[0][0] === '\\') continue;
var index = m.index;
while (path.charAt(--index) === '\\') {
escapeCount++;
}
// It's possible to escape the bracket.
if (escapeCount % 2 === 1) {
continue;
}
if (keysOffset + i === keys.length || keys[keysOffset + i].offset > m.index) { if (keysOffset + i === keys.length || keys[keysOffset + i].offset > m.index) {
keys.splice(keysOffset + i, 0, { keys.splice(keysOffset + i, 0, {
@@ -122,8 +143,14 @@ function pathtoRegexp(path, keys, options) {
i++; i++;
} }
// If the path is non-ending, match until the end or a slash. path += strict ? '' : path[path.length - 1] === '/' ? '?' : '/?';
path += (end ? '$' : (path[path.length - 1] === '/' ? '' : '(?=\\/|$)'));
return new RegExp(path, flags); // If the path is non-ending, match until the end or a slash.
if (end) {
path += '$';
} else if (path[path.length - 1] !== '/') {
path += lookahead ? '(?=/|$)' : '(?:/|$)';
}
return new RegExp('^' + path, flags);
}; };

View File

@@ -1,7 +1,7 @@
{ {
"name": "path-to-regexp", "name": "path-to-regexp",
"description": "Express style path to RegExp utility", "description": "Express style path to RegExp utility",
"version": "0.1.7", "version": "0.1.12",
"files": [ "files": [
"index.js", "index.js",
"LICENSE" "LICENSE"
@@ -21,7 +21,7 @@
"license": "MIT", "license": "MIT",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/component/path-to-regexp.git" "url": "https://github.com/pillarjs/path-to-regexp.git"
}, },
"devDependencies": { "devDependencies": {
"mocha": "^1.17.1", "mocha": "^1.17.1",

3
node_modules/qs/.editorconfig generated vendored
View File

@@ -41,3 +41,6 @@ max_line_length = off
[.nycrc] [.nycrc]
indent_style = tab indent_style = tab
[tea.yaml]
indent_size = 2

4
node_modules/qs/.eslintrc generated vendored
View File

@@ -14,8 +14,8 @@
"id-length": [2, { "min": 1, "max": 25, "properties": "never" }], "id-length": [2, { "min": 1, "max": 25, "properties": "never" }],
"indent": [2, 4], "indent": [2, 4],
"max-lines-per-function": [2, { "max": 150 }], "max-lines-per-function": [2, { "max": 150 }],
"max-params": [2, 16], "max-params": [2, 18],
"max-statements": [2, 53], "max-statements": [2, 100],
"multiline-comment-style": 0, "multiline-comment-style": 0,
"no-continue": 1, "no-continue": 1,
"no-magic-numbers": 0, "no-magic-numbers": 0,

64
node_modules/qs/CHANGELOG.md generated vendored
View File

@@ -1,4 +1,58 @@
## **6.11.0 ## **6.13.0**
- [New] `parse`: add `strictDepth` option (#511)
- [Tests] use `npm audit` instead of `aud`
## **6.12.3**
- [Fix] `parse`: properly account for `strictNullHandling` when `allowEmptyArrays`
- [meta] fix changelog indentation
## **6.12.2**
- [Fix] `parse`: parse encoded square brackets (#506)
- [readme] add CII best practices badge
## **6.12.1**
- [Fix] `parse`: Disable `decodeDotInKeys` by default to restore previous behavior (#501)
- [Performance] `utils`: Optimize performance under large data volumes, reduce memory usage, and speed up processing (#502)
- [Refactor] `utils`: use `+=`
- [Tests] increase coverage
## **6.12.0**
- [New] `parse`/`stringify`: add `decodeDotInKeys`/`encodeDotKeys` options (#488)
- [New] `parse`: add `duplicates` option
- [New] `parse`/`stringify`: add `allowEmptyArrays` option to allow [] in object values (#487)
- [Refactor] `parse`/`stringify`: move allowDots config logic to its own variable
- [Refactor] `stringify`: move option-handling code into `normalizeStringifyOptions`
- [readme] update readme, add logos (#484)
- [readme] `stringify`: clarify default `arrayFormat` behavior
- [readme] fix line wrapping
- [readme] remove dead badges
- [Deps] update `side-channel`
- [meta] make the dist build 50% smaller
- [meta] add `sideEffects` flag
- [meta] run build in prepack, not prepublish
- [Tests] `parse`: remove useless tests; add coverage
- [Tests] `stringify`: increase coverage
- [Tests] use `mock-property`
- [Tests] `stringify`: improve coverage
- [Dev Deps] update `@ljharb/eslint-config `, `aud`, `has-override-mistake`, `has-property-descriptors`, `mock-property`, `npmignore`, `object-inspect`, `tape`
- [Dev Deps] pin `glob`, since v10.3.8+ requires a broken `jackspeak`
- [Dev Deps] pin `jackspeak` since 2.1.2+ depends on npm aliases, which kill the install process in npm < 6
## **6.11.2**
- [Fix] `parse`: Fix parsing when the global Object prototype is frozen (#473)
- [Tests] add passing test cases with empty keys (#473)
## **6.11.1**
- [Fix] `stringify`: encode comma values more consistently (#463)
- [readme] add usage of `filter` option for injecting custom serialization, i.e. of custom types (#447)
- [meta] remove extraneous code backticks (#457)
- [meta] fix changelog markdown
- [actions] update checkout action
- [actions] restrict action permissions
- [Dev Deps] update `@ljharb/eslint-config`, `aud`, `object-inspect`, `tape`
## **6.11.0**
- [New] [Fix] `stringify`: revert 0e903c0; add `commaRoundTrip` option (#442) - [New] [Fix] `stringify`: revert 0e903c0; add `commaRoundTrip` option (#442)
- [readme] fix version badge - [readme] fix version badge
@@ -238,7 +292,7 @@
## **6.5.3** ## **6.5.3**
- [Fix] `parse`: ignore `__proto__` keys (#428) - [Fix] `parse`: ignore `__proto__` keys (#428)
- [Fix]` `utils.merge`: avoid a crash with a null target and a truthy non-array source - [Fix] `utils.merge`: avoid a crash with a null target and a truthy non-array source
- [Fix] correctly parse nested arrays - [Fix] correctly parse nested arrays
- [Fix] `stringify`: fix a crash with `strictNullHandling` and a custom `filter`/`serializeDate` (#279) - [Fix] `stringify`: fix a crash with `strictNullHandling` and a custom `filter`/`serializeDate` (#279)
- [Fix] `utils`: `merge`: fix crash when `source` is a truthy primitive & no options are provided - [Fix] `utils`: `merge`: fix crash when `source` is a truthy primitive & no options are provided
@@ -291,7 +345,7 @@
- [Fix] fix for an impossible situation: when the formatter is called with a non-string value - [Fix] fix for an impossible situation: when the formatter is called with a non-string value
- [Fix] use `safer-buffer` instead of `Buffer` constructor - [Fix] use `safer-buffer` instead of `Buffer` constructor
- [Fix] `utils.merge`: avoid a crash with a null target and an array source - [Fix] `utils.merge`: avoid a crash with a null target and an array source
- [Fix]` `utils.merge`: avoid a crash with a null target and a truthy non-array source - [Fix] `utils.merge`: avoid a crash with a null target and a truthy non-array source
- [Fix] `stringify`: fix a crash with `strictNullHandling` and a custom `filter`/`serializeDate` (#279) - [Fix] `stringify`: fix a crash with `strictNullHandling` and a custom `filter`/`serializeDate` (#279)
- [Fix] `utils`: `merge`: fix crash when `source` is a truthy primitive & no options are provided - [Fix] `utils`: `merge`: fix crash when `source` is a truthy primitive & no options are provided
- [Fix] when `parseArrays` is false, properly handle keys ending in `[]` - [Fix] when `parseArrays` is false, properly handle keys ending in `[]`
@@ -320,7 +374,7 @@
- [Fix] `parse`: ignore `__proto__` keys (#428) - [Fix] `parse`: ignore `__proto__` keys (#428)
- [Fix] fix for an impossible situation: when the formatter is called with a non-string value - [Fix] fix for an impossible situation: when the formatter is called with a non-string value
- [Fix] `utils.merge`: avoid a crash with a null target and an array source - [Fix] `utils.merge`: avoid a crash with a null target and an array source
- [Fix]` `utils.merge`: avoid a crash with a null target and a truthy non-array source - [Fix] `utils.merge`: avoid a crash with a null target and a truthy non-array source
- [Fix] `stringify`: fix a crash with `strictNullHandling` and a custom `filter`/`serializeDate` (#279) - [Fix] `stringify`: fix a crash with `strictNullHandling` and a custom `filter`/`serializeDate` (#279)
- [Fix] `utils`: `merge`: fix crash when `source` is a truthy primitive & no options are provided - [Fix] `utils`: `merge`: fix crash when `source` is a truthy primitive & no options are provided
- [Fix] when `parseArrays` is false, properly handle keys ending in `[]` - [Fix] when `parseArrays` is false, properly handle keys ending in `[]`
@@ -407,7 +461,7 @@
- [New] add "encoder" and "decoder" options, for custom param encoding/decoding (#160) - [New] add "encoder" and "decoder" options, for custom param encoding/decoding (#160)
- [Fix] fix compacting of nested sparse arrays (#150) - [Fix] fix compacting of nested sparse arrays (#150)
## **6.1.2 ## **6.1.2**
- [Fix] follow `allowPrototypes` option during merge (#201, #200) - [Fix] follow `allowPrototypes` option during merge (#201, #200)
- [Fix] chmod a-x - [Fix] chmod a-x
- [Fix] support keys starting with brackets (#202, #200) - [Fix] support keys starting with brackets (#202, #200)

182
node_modules/qs/README.md generated vendored
View File

@@ -1,11 +1,14 @@
<p align="center">
<img alt="qs" src="./logos/banner_default.png" width="800" />
</p>
# qs <sup>[![Version Badge][npm-version-svg]][package-url]</sup> # qs <sup>[![Version Badge][npm-version-svg]][package-url]</sup>
[![github actions][actions-image]][actions-url] [![github actions][actions-image]][actions-url]
[![coverage][codecov-image]][codecov-url] [![coverage][codecov-image]][codecov-url]
[![dependency status][deps-svg]][deps-url]
[![dev dependency status][dev-deps-svg]][dev-deps-url]
[![License][license-image]][license-url] [![License][license-image]][license-url]
[![Downloads][downloads-image]][downloads-url] [![Downloads][downloads-image]][downloads-url]
[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/9058/badge)](https://bestpractices.coreinfrastructure.org/projects/9058)
[![npm badge][npm-badge-png]][package-url] [![npm badge][npm-badge-png]][package-url]
@@ -53,7 +56,9 @@ var nullObject = qs.parse('a[hasOwnProperty]=b', { plainObjects: true });
assert.deepEqual(nullObject, { a: { hasOwnProperty: 'b' } }); assert.deepEqual(nullObject, { a: { hasOwnProperty: 'b' } });
``` ```
By default parameters that would overwrite properties on the object prototype are ignored, if you wish to keep the data from those fields either use `plainObjects` as mentioned above, or set `allowPrototypes` to `true` which will allow user input to overwrite those properties. *WARNING* It is generally a bad idea to enable this option as it can cause problems when attempting to use the properties that have been overwritten. Always be careful with this option. By default parameters that would overwrite properties on the object prototype are ignored, if you wish to keep the data from those fields either use `plainObjects` as mentioned above, or set `allowPrototypes` to `true` which will allow user input to overwrite those properties.
*WARNING* It is generally a bad idea to enable this option as it can cause problems when attempting to use the properties that have been overwritten.
Always be careful with this option.
```javascript ```javascript
var protoObject = qs.parse('a[hasOwnProperty]=b', { allowPrototypes: true }); var protoObject = qs.parse('a[hasOwnProperty]=b', { allowPrototypes: true });
@@ -80,8 +85,8 @@ assert.deepEqual(qs.parse('foo[bar][baz]=foobarbaz'), {
}); });
``` ```
By default, when nesting objects **qs** will only parse up to 5 children deep. This means if you attempt to parse a string like By default, when nesting objects **qs** will only parse up to 5 children deep.
`'a[b][c][d][e][f][g][h][i]=j'` your resulting object will be: This means if you attempt to parse a string like `'a[b][c][d][e][f][g][h][i]=j'` your resulting object will be:
```javascript ```javascript
var expected = { var expected = {
@@ -110,7 +115,18 @@ var deep = qs.parse('a[b][c][d][e][f][g][h][i]=j', { depth: 1 });
assert.deepEqual(deep, { a: { b: { '[c][d][e][f][g][h][i]': 'j' } } }); assert.deepEqual(deep, { a: { b: { '[c][d][e][f][g][h][i]': 'j' } } });
``` ```
The depth limit helps mitigate abuse when **qs** is used to parse user input, and it is recommended to keep it a reasonably small number. You can configure **qs** to throw an error when parsing nested input beyond this depth using the `strictDepth` option (defaulted to false):
```javascript
try {
qs.parse('a[b][c][d][e][f][g][h][i]=j', { depth: 1, strictDepth: true });
} catch (err) {
assert(err instanceof RangeError);
assert.strictEqual(err.message, 'Input depth exceeded depth option of 1 and strictDepth is true');
}
```
The depth limit helps mitigate abuse when **qs** is used to parse user input, and it is recommended to keep it a reasonably small number. The strictDepth option adds a layer of protection by throwing an error when the limit is exceeded, allowing you to catch and handle such cases.
For similar reasons, by default **qs** will only parse up to 1000 parameters. This can be overridden by passing a `parameterLimit` option: For similar reasons, by default **qs** will only parse up to 1000 parameters. This can be overridden by passing a `parameterLimit` option:
@@ -147,32 +163,44 @@ var withDots = qs.parse('a.b=c', { allowDots: true });
assert.deepEqual(withDots, { a: { b: 'c' } }); assert.deepEqual(withDots, { a: { b: 'c' } });
``` ```
If you have to deal with legacy browsers or services, there's Option `decodeDotInKeys` can be used to decode dots in keys
also support for decoding percent-encoded octets as iso-8859-1: Note: it implies `allowDots`, so `parse` will error if you set `decodeDotInKeys` to `true`, and `allowDots` to `false`.
```javascript
var withDots = qs.parse('name%252Eobj.first=John&name%252Eobj.last=Doe', { decodeDotInKeys: true });
assert.deepEqual(withDots, { 'name.obj': { first: 'John', last: 'Doe' }});
```
Option `allowEmptyArrays` can be used to allowing empty array values in object
```javascript
var withEmptyArrays = qs.parse('foo[]&bar=baz', { allowEmptyArrays: true });
assert.deepEqual(withEmptyArrays, { foo: [], bar: 'baz' });
```
Option `duplicates` can be used to change the behavior when duplicate keys are encountered
```javascript
assert.deepEqual(qs.parse('foo=bar&foo=baz'), { foo: ['bar', 'baz'] });
assert.deepEqual(qs.parse('foo=bar&foo=baz', { duplicates: 'combine' }), { foo: ['bar', 'baz'] });
assert.deepEqual(qs.parse('foo=bar&foo=baz', { duplicates: 'first' }), { foo: 'bar' });
assert.deepEqual(qs.parse('foo=bar&foo=baz', { duplicates: 'last' }), { foo: 'baz' });
```
If you have to deal with legacy browsers or services, there's also support for decoding percent-encoded octets as iso-8859-1:
```javascript ```javascript
var oldCharset = qs.parse('a=%A7', { charset: 'iso-8859-1' }); var oldCharset = qs.parse('a=%A7', { charset: 'iso-8859-1' });
assert.deepEqual(oldCharset, { a: '§' }); assert.deepEqual(oldCharset, { a: '§' });
``` ```
Some services add an initial `utf8=✓` value to forms so that old Some services add an initial `utf8=✓` value to forms so that old Internet Explorer versions are more likely to submit the form as utf-8.
Internet Explorer versions are more likely to submit the form as Additionally, the server can check the value against wrong encodings of the checkmark character and detect that a query string or `application/x-www-form-urlencoded` body was *not* sent as utf-8, eg. if the form had an `accept-charset` parameter or the containing page had a different character set.
utf-8. Additionally, the server can check the value against wrong
encodings of the checkmark character and detect that a query string
or `application/x-www-form-urlencoded` body was *not* sent as
utf-8, eg. if the form had an `accept-charset` parameter or the
containing page had a different character set.
**qs** supports this mechanism via the `charsetSentinel` option. **qs** supports this mechanism via the `charsetSentinel` option.
If specified, the `utf8` parameter will be omitted from the If specified, the `utf8` parameter will be omitted from the returned object.
returned object. It will be used to switch to `iso-8859-1`/`utf-8` It will be used to switch to `iso-8859-1`/`utf-8` mode depending on how the checkmark is encoded.
mode depending on how the checkmark is encoded.
**Important**: When you specify both the `charset` option and the **Important**: When you specify both the `charset` option and the `charsetSentinel` option, the `charset` will be overridden when the request contains a `utf8` parameter from which the actual charset can be deduced.
`charsetSentinel` option, the `charset` will be overridden when In that sense the `charset` will behave as the default charset rather than the authoritative charset.
the request contains a `utf8` parameter from which the actual
charset can be deduced. In that sense the `charset` will behave
as the default charset rather than the authoritative charset.
```javascript ```javascript
var detectedAsUtf8 = qs.parse('utf8=%E2%9C%93&a=%C3%B8', { var detectedAsUtf8 = qs.parse('utf8=%E2%9C%93&a=%C3%B8', {
@@ -189,8 +217,7 @@ var detectedAsIso8859_1 = qs.parse('utf8=%26%2310003%3B&a=%F8', {
assert.deepEqual(detectedAsIso8859_1, { a: 'ø' }); assert.deepEqual(detectedAsIso8859_1, { a: 'ø' });
``` ```
If you want to decode the `&#...;` syntax to the actual character, If you want to decode the `&#...;` syntax to the actual character, you can specify the `interpretNumericEntities` option as well:
you can specify the `interpretNumericEntities` option as well:
```javascript ```javascript
var detectedAsIso8859_1 = qs.parse('a=%26%239786%3B', { var detectedAsIso8859_1 = qs.parse('a=%26%239786%3B', {
@@ -200,8 +227,7 @@ var detectedAsIso8859_1 = qs.parse('a=%26%239786%3B', {
assert.deepEqual(detectedAsIso8859_1, { a: '☺' }); assert.deepEqual(detectedAsIso8859_1, { a: '☺' });
``` ```
It also works when the charset has been detected in `charsetSentinel` It also works when the charset has been detected in `charsetSentinel` mode.
mode.
### Parsing Arrays ### Parsing Arrays
@@ -219,9 +245,8 @@ var withIndexes = qs.parse('a[1]=c&a[0]=b');
assert.deepEqual(withIndexes, { a: ['b', 'c'] }); assert.deepEqual(withIndexes, { a: ['b', 'c'] });
``` ```
Note that the only difference between an index in an array and a key in an object is that the value between the brackets must be a number Note that the only difference between an index in an array and a key in an object is that the value between the brackets must be a number to create an array.
to create an array. When creating arrays with specific indices, **qs** will compact a sparse array to only the existing values preserving When creating arrays with specific indices, **qs** will compact a sparse array to only the existing values preserving their order:
their order:
```javascript ```javascript
var noSparse = qs.parse('a[1]=b&a[15]=c'); var noSparse = qs.parse('a[1]=b&a[15]=c');
@@ -245,8 +270,9 @@ var withIndexedEmptyString = qs.parse('a[0]=b&a[1]=&a[2]=c');
assert.deepEqual(withIndexedEmptyString, { a: ['b', '', 'c'] }); assert.deepEqual(withIndexedEmptyString, { a: ['b', '', 'c'] });
``` ```
**qs** will also limit specifying indices in an array to a maximum index of `20`. Any array members with an index of greater than `20` will **qs** will also limit specifying indices in an array to a maximum index of `20`.
instead be converted to an object with the index as the key. This is needed to handle cases when someone sent, for example, `a[999999999]` and it will take significant time to iterate over this huge array. Any array members with an index of greater than `20` will instead be converted to an object with the index as the key.
This is needed to handle cases when someone sent, for example, `a[999999999]` and it will take significant time to iterate over this huge array.
```javascript ```javascript
var withMaxIndex = qs.parse('a[100]=b'); var withMaxIndex = qs.parse('a[100]=b');
@@ -290,7 +316,8 @@ assert.deepEqual(arraysOfObjects, { a: ['b', 'c'] })
### Parsing primitive/scalar values (numbers, booleans, null, etc) ### Parsing primitive/scalar values (numbers, booleans, null, etc)
By default, all values are parsed as strings. This behavior will not change and is explained in [issue #91](https://github.com/ljharb/qs/issues/91). By default, all values are parsed as strings.
This behavior will not change and is explained in [issue #91](https://github.com/ljharb/qs/issues/91).
```javascript ```javascript
var primitiveValues = qs.parse('a=15&b=true&c=null'); var primitiveValues = qs.parse('a=15&b=true&c=null');
@@ -373,16 +400,17 @@ var decoded = qs.parse('x=z', { decoder: function (str, defaultDecoder, charset,
}}) }})
``` ```
Examples beyond this point will be shown as though the output is not URI encoded for clarity. Please note that the return values in these cases *will* be URI encoded during real usage. Examples beyond this point will be shown as though the output is not URI encoded for clarity.
Please note that the return values in these cases *will* be URI encoded during real usage.
When arrays are stringified, by default they are given explicit indices: When arrays are stringified, they follow the `arrayFormat` option, which defaults to `indices`:
```javascript ```javascript
qs.stringify({ a: ['b', 'c', 'd'] }); qs.stringify({ a: ['b', 'c', 'd'] });
// 'a[0]=b&a[1]=c&a[2]=d' // 'a[0]=b&a[1]=c&a[2]=d'
``` ```
You may override this by setting the `indices` option to `false`: You may override this by setting the `indices` option to `false`, or to be more explicit, the `arrayFormat` option to `repeat`:
```javascript ```javascript
qs.stringify({ a: ['b', 'c', 'd'] }, { indices: false }); qs.stringify({ a: ['b', 'c', 'd'] }, { indices: false });
@@ -418,6 +446,20 @@ qs.stringify({ a: { b: { c: 'd', e: 'f' } } }, { allowDots: true });
// 'a.b.c=d&a.b.e=f' // 'a.b.c=d&a.b.e=f'
``` ```
You may encode the dot notation in the keys of object with option `encodeDotInKeys` by setting it to `true`:
Note: it implies `allowDots`, so `stringify` will error if you set `decodeDotInKeys` to `true`, and `allowDots` to `false`.
Caveat: when `encodeValuesOnly` is `true` as well as `encodeDotInKeys`, only dots in keys and nothing else will be encoded.
```javascript
qs.stringify({ "name.obj": { "first": "John", "last": "Doe" } }, { allowDots: true, encodeDotInKeys: true })
// 'name%252Eobj.first=John&name%252Eobj.last=Doe'
```
You may allow empty array values by setting the `allowEmptyArrays` option to `true`:
```javascript
qs.stringify({ foo: [], bar: 'baz' }, { allowEmptyArrays: true });
// 'foo[]&bar=baz'
```
Empty strings and null values will omit the value, but the equals sign (=) remains in place: Empty strings and null values will omit the value, but the equals sign (=) remains in place:
```javascript ```javascript
@@ -473,8 +515,8 @@ assert.equal(qs.stringify({ a: 'c', z: 'y', b : 'f' }, { sort: alphabeticalSort
``` ```
Finally, you can use the `filter` option to restrict which keys will be included in the stringified output. Finally, you can use the `filter` option to restrict which keys will be included in the stringified output.
If you pass a function, it will be called for each key to obtain the replacement value. Otherwise, if you If you pass a function, it will be called for each key to obtain the replacement value.
pass an array, it will be used to select properties and array indices for stringification: Otherwise, if you pass an array, it will be used to select properties and array indices for stringification:
```javascript ```javascript
function filterFunc(prefix, value) { function filterFunc(prefix, value) {
@@ -498,6 +540,44 @@ qs.stringify({ a: ['b', 'c', 'd'], e: 'f' }, { filter: ['a', 0, 2] });
// 'a[0]=b&a[2]=d' // 'a[0]=b&a[2]=d'
``` ```
You could also use `filter` to inject custom serialization for user defined types.
Consider you're working with some api that expects query strings of the format for ranges:
```
https://domain.com/endpoint?range=30...70
```
For which you model as:
```javascript
class Range {
constructor(from, to) {
this.from = from;
this.to = to;
}
}
```
You could _inject_ a custom serializer to handle values of this type:
```javascript
qs.stringify(
{
range: new Range(30, 70),
},
{
filter: (prefix, value) => {
if (value instanceof Range) {
return `${value.from}...${value.to}`;
}
// serialize the usual way
return value;
},
}
);
// range=30...70
```
### Handling of `null` values ### Handling of `null` values
By default, `null` values are treated like empty strings: By default, `null` values are treated like empty strings:
@@ -507,7 +587,8 @@ var withNull = qs.stringify({ a: null, b: '' });
assert.equal(withNull, 'a=&b='); assert.equal(withNull, 'a=&b=');
``` ```
Parsing does not distinguish between parameters with and without equal signs. Both are converted to empty strings. Parsing does not distinguish between parameters with and without equal signs.
Both are converted to empty strings.
```javascript ```javascript
var equalsInsensitive = qs.parse('a&b='); var equalsInsensitive = qs.parse('a&b=');
@@ -536,25 +617,21 @@ var nullsSkipped = qs.stringify({ a: 'b', c: null}, { skipNulls: true });
assert.equal(nullsSkipped, 'a=b'); assert.equal(nullsSkipped, 'a=b');
``` ```
If you're communicating with legacy systems, you can switch to `iso-8859-1` If you're communicating with legacy systems, you can switch to `iso-8859-1` using the `charset` option:
using the `charset` option:
```javascript ```javascript
var iso = qs.stringify({ æ: 'æ' }, { charset: 'iso-8859-1' }); var iso = qs.stringify({ æ: 'æ' }, { charset: 'iso-8859-1' });
assert.equal(iso, '%E6=%E6'); assert.equal(iso, '%E6=%E6');
``` ```
Characters that don't exist in `iso-8859-1` will be converted to numeric Characters that don't exist in `iso-8859-1` will be converted to numeric entities, similar to what browsers do:
entities, similar to what browsers do:
```javascript ```javascript
var numeric = qs.stringify({ a: '☺' }, { charset: 'iso-8859-1' }); var numeric = qs.stringify({ a: '☺' }, { charset: 'iso-8859-1' });
assert.equal(numeric, 'a=%26%239786%3B'); assert.equal(numeric, 'a=%26%239786%3B');
``` ```
You can use the `charsetSentinel` option to announce the character by You can use the `charsetSentinel` option to announce the character by including an `utf8=✓` parameter with the proper encoding if the checkmark, similar to what Ruby on Rails and others do when submitting forms.
including an `utf8=✓` parameter with the proper encoding if the checkmark,
similar to what Ruby on Rails and others do when submitting forms.
```javascript ```javascript
var sentinel = qs.stringify({ a: '☺' }, { charsetSentinel: true }); var sentinel = qs.stringify({ a: '☺' }, { charsetSentinel: true });
@@ -566,8 +643,7 @@ assert.equal(isoSentinel, 'utf8=%26%2310003%3B&a=%E6');
### Dealing with special character sets ### Dealing with special character sets
By default the encoding and decoding of characters is done in `utf-8`, By default the encoding and decoding of characters is done in `utf-8`, and `iso-8859-1` support is also built in via the `charset` parameter.
and `iso-8859-1` support is also built in via the `charset` parameter.
If you wish to encode querystrings to a different character set (i.e. If you wish to encode querystrings to a different character set (i.e.
[Shift JIS](https://en.wikipedia.org/wiki/Shift_JIS)) you can use the [Shift JIS](https://en.wikipedia.org/wiki/Shift_JIS)) you can use the
@@ -606,7 +682,9 @@ Please email [@ljharb](https://github.com/ljharb) or see https://tidelift.com/se
Available as part of the Tidelift Subscription Available as part of the Tidelift Subscription
The maintainers of qs and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/npm-qs?utm_source=npm-qs&utm_medium=referral&utm_campaign=enterprise&utm_term=repo) The maintainers of qs and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications.
Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use.
[Learn more.](https://tidelift.com/subscription/pkg/npm-qs?utm_source=npm-qs&utm_medium=referral&utm_campaign=enterprise&utm_term=repo)
[package-url]: https://npmjs.org/package/qs [package-url]: https://npmjs.org/package/qs
[npm-version-svg]: https://versionbadg.es/ljharb/qs.svg [npm-version-svg]: https://versionbadg.es/ljharb/qs.svg
@@ -623,3 +701,9 @@ The maintainers of qs and thousands of other packages are working with Tidelift
[codecov-url]: https://app.codecov.io/gh/ljharb/qs/ [codecov-url]: https://app.codecov.io/gh/ljharb/qs/
[actions-image]: https://img.shields.io/endpoint?url=https://github-actions-badge-u3jn4tfpocch.runkit.sh/ljharb/qs [actions-image]: https://img.shields.io/endpoint?url=https://github-actions-badge-u3jn4tfpocch.runkit.sh/ljharb/qs
[actions-url]: https://github.com/ljharb/qs/actions [actions-url]: https://github.com/ljharb/qs/actions
## Acknowledgements
qs logo by [NUMI](https://github.com/numi-hq/open-design):
[<img src="https://raw.githubusercontent.com/numi-hq/open-design/main/assets/numi-lockup.png" alt="NUMI Logo" style="width: 200px;"/>](https://numi.tech/?ref=qs)

2076
node_modules/qs/dist/qs.js generated vendored

File diff suppressed because one or more lines are too long

59
node_modules/qs/lib/parse.js generated vendored
View File

@@ -7,20 +7,24 @@ var isArray = Array.isArray;
var defaults = { var defaults = {
allowDots: false, allowDots: false,
allowEmptyArrays: false,
allowPrototypes: false, allowPrototypes: false,
allowSparse: false, allowSparse: false,
arrayLimit: 20, arrayLimit: 20,
charset: 'utf-8', charset: 'utf-8',
charsetSentinel: false, charsetSentinel: false,
comma: false, comma: false,
decodeDotInKeys: false,
decoder: utils.decode, decoder: utils.decode,
delimiter: '&', delimiter: '&',
depth: 5, depth: 5,
duplicates: 'combine',
ignoreQueryPrefix: false, ignoreQueryPrefix: false,
interpretNumericEntities: false, interpretNumericEntities: false,
parameterLimit: 1000, parameterLimit: 1000,
parseArrays: true, parseArrays: true,
plainObjects: false, plainObjects: false,
strictDepth: false,
strictNullHandling: false strictNullHandling: false
}; };
@@ -49,8 +53,10 @@ var isoSentinel = 'utf8=%26%2310003%3B'; // encodeURIComponent('&#10003;')
var charsetSentinel = 'utf8=%E2%9C%93'; // encodeURIComponent('✓') var charsetSentinel = 'utf8=%E2%9C%93'; // encodeURIComponent('✓')
var parseValues = function parseQueryStringValues(str, options) { var parseValues = function parseQueryStringValues(str, options) {
var obj = {}; var obj = { __proto__: null };
var cleanStr = options.ignoreQueryPrefix ? str.replace(/^\?/, '') : str; var cleanStr = options.ignoreQueryPrefix ? str.replace(/^\?/, '') : str;
cleanStr = cleanStr.replace(/%5B/gi, '[').replace(/%5D/gi, ']');
var limit = options.parameterLimit === Infinity ? undefined : options.parameterLimit; var limit = options.parameterLimit === Infinity ? undefined : options.parameterLimit;
var parts = cleanStr.split(options.delimiter, limit); var parts = cleanStr.split(options.delimiter, limit);
var skipIndex = -1; // Keep track of where the utf8 sentinel was found var skipIndex = -1; // Keep track of where the utf8 sentinel was found
@@ -102,9 +108,10 @@ var parseValues = function parseQueryStringValues(str, options) {
val = isArray(val) ? [val] : val; val = isArray(val) ? [val] : val;
} }
if (has.call(obj, key)) { var existing = has.call(obj, key);
if (existing && options.duplicates === 'combine') {
obj[key] = utils.combine(obj[key], val); obj[key] = utils.combine(obj[key], val);
} else { } else if (!existing || options.duplicates === 'last') {
obj[key] = val; obj[key] = val;
} }
} }
@@ -120,24 +127,27 @@ var parseObject = function (chain, val, options, valuesParsed) {
var root = chain[i]; var root = chain[i];
if (root === '[]' && options.parseArrays) { if (root === '[]' && options.parseArrays) {
obj = [].concat(leaf); obj = options.allowEmptyArrays && (leaf === '' || (options.strictNullHandling && leaf === null))
? []
: [].concat(leaf);
} else { } else {
obj = options.plainObjects ? Object.create(null) : {}; obj = options.plainObjects ? Object.create(null) : {};
var cleanRoot = root.charAt(0) === '[' && root.charAt(root.length - 1) === ']' ? root.slice(1, -1) : root; var cleanRoot = root.charAt(0) === '[' && root.charAt(root.length - 1) === ']' ? root.slice(1, -1) : root;
var index = parseInt(cleanRoot, 10); var decodedRoot = options.decodeDotInKeys ? cleanRoot.replace(/%2E/g, '.') : cleanRoot;
if (!options.parseArrays && cleanRoot === '') { var index = parseInt(decodedRoot, 10);
if (!options.parseArrays && decodedRoot === '') {
obj = { 0: leaf }; obj = { 0: leaf };
} else if ( } else if (
!isNaN(index) !isNaN(index)
&& root !== cleanRoot && root !== decodedRoot
&& String(index) === cleanRoot && String(index) === decodedRoot
&& index >= 0 && index >= 0
&& (options.parseArrays && index <= options.arrayLimit) && (options.parseArrays && index <= options.arrayLimit)
) { ) {
obj = []; obj = [];
obj[index] = leaf; obj[index] = leaf;
} else if (cleanRoot !== '__proto__') { } else if (decodedRoot !== '__proto__') {
obj[cleanRoot] = leaf; obj[decodedRoot] = leaf;
} }
} }
@@ -192,9 +202,12 @@ var parseKeys = function parseQueryStringKeys(givenKey, val, options, valuesPars
keys.push(segment[1]); keys.push(segment[1]);
} }
// If there's a remainder, just add whatever is left // If there's a remainder, check strictDepth option for throw, else just add whatever is left
if (segment) { if (segment) {
if (options.strictDepth === true) {
throw new RangeError('Input depth exceeded depth option of ' + options.depth + ' and strictDepth is true');
}
keys.push('[' + key.slice(segment.index) + ']'); keys.push('[' + key.slice(segment.index) + ']');
} }
@@ -206,7 +219,15 @@ var normalizeParseOptions = function normalizeParseOptions(opts) {
return defaults; return defaults;
} }
if (opts.decoder !== null && opts.decoder !== undefined && typeof opts.decoder !== 'function') { if (typeof opts.allowEmptyArrays !== 'undefined' && typeof opts.allowEmptyArrays !== 'boolean') {
throw new TypeError('`allowEmptyArrays` option can only be `true` or `false`, when provided');
}
if (typeof opts.decodeDotInKeys !== 'undefined' && typeof opts.decodeDotInKeys !== 'boolean') {
throw new TypeError('`decodeDotInKeys` option can only be `true` or `false`, when provided');
}
if (opts.decoder !== null && typeof opts.decoder !== 'undefined' && typeof opts.decoder !== 'function') {
throw new TypeError('Decoder has to be a function.'); throw new TypeError('Decoder has to be a function.');
} }
@@ -215,23 +236,35 @@ var normalizeParseOptions = function normalizeParseOptions(opts) {
} }
var charset = typeof opts.charset === 'undefined' ? defaults.charset : opts.charset; var charset = typeof opts.charset === 'undefined' ? defaults.charset : opts.charset;
var duplicates = typeof opts.duplicates === 'undefined' ? defaults.duplicates : opts.duplicates;
if (duplicates !== 'combine' && duplicates !== 'first' && duplicates !== 'last') {
throw new TypeError('The duplicates option must be either combine, first, or last');
}
var allowDots = typeof opts.allowDots === 'undefined' ? opts.decodeDotInKeys === true ? true : defaults.allowDots : !!opts.allowDots;
return { return {
allowDots: typeof opts.allowDots === 'undefined' ? defaults.allowDots : !!opts.allowDots, allowDots: allowDots,
allowEmptyArrays: typeof opts.allowEmptyArrays === 'boolean' ? !!opts.allowEmptyArrays : defaults.allowEmptyArrays,
allowPrototypes: typeof opts.allowPrototypes === 'boolean' ? opts.allowPrototypes : defaults.allowPrototypes, allowPrototypes: typeof opts.allowPrototypes === 'boolean' ? opts.allowPrototypes : defaults.allowPrototypes,
allowSparse: typeof opts.allowSparse === 'boolean' ? opts.allowSparse : defaults.allowSparse, allowSparse: typeof opts.allowSparse === 'boolean' ? opts.allowSparse : defaults.allowSparse,
arrayLimit: typeof opts.arrayLimit === 'number' ? opts.arrayLimit : defaults.arrayLimit, arrayLimit: typeof opts.arrayLimit === 'number' ? opts.arrayLimit : defaults.arrayLimit,
charset: charset, charset: charset,
charsetSentinel: typeof opts.charsetSentinel === 'boolean' ? opts.charsetSentinel : defaults.charsetSentinel, charsetSentinel: typeof opts.charsetSentinel === 'boolean' ? opts.charsetSentinel : defaults.charsetSentinel,
comma: typeof opts.comma === 'boolean' ? opts.comma : defaults.comma, comma: typeof opts.comma === 'boolean' ? opts.comma : defaults.comma,
decodeDotInKeys: typeof opts.decodeDotInKeys === 'boolean' ? opts.decodeDotInKeys : defaults.decodeDotInKeys,
decoder: typeof opts.decoder === 'function' ? opts.decoder : defaults.decoder, decoder: typeof opts.decoder === 'function' ? opts.decoder : defaults.decoder,
delimiter: typeof opts.delimiter === 'string' || utils.isRegExp(opts.delimiter) ? opts.delimiter : defaults.delimiter, delimiter: typeof opts.delimiter === 'string' || utils.isRegExp(opts.delimiter) ? opts.delimiter : defaults.delimiter,
// eslint-disable-next-line no-implicit-coercion, no-extra-parens // eslint-disable-next-line no-implicit-coercion, no-extra-parens
depth: (typeof opts.depth === 'number' || opts.depth === false) ? +opts.depth : defaults.depth, depth: (typeof opts.depth === 'number' || opts.depth === false) ? +opts.depth : defaults.depth,
duplicates: duplicates,
ignoreQueryPrefix: opts.ignoreQueryPrefix === true, ignoreQueryPrefix: opts.ignoreQueryPrefix === true,
interpretNumericEntities: typeof opts.interpretNumericEntities === 'boolean' ? opts.interpretNumericEntities : defaults.interpretNumericEntities, interpretNumericEntities: typeof opts.interpretNumericEntities === 'boolean' ? opts.interpretNumericEntities : defaults.interpretNumericEntities,
parameterLimit: typeof opts.parameterLimit === 'number' ? opts.parameterLimit : defaults.parameterLimit, parameterLimit: typeof opts.parameterLimit === 'number' ? opts.parameterLimit : defaults.parameterLimit,
parseArrays: opts.parseArrays !== false, parseArrays: opts.parseArrays !== false,
plainObjects: typeof opts.plainObjects === 'boolean' ? opts.plainObjects : defaults.plainObjects, plainObjects: typeof opts.plainObjects === 'boolean' ? opts.plainObjects : defaults.plainObjects,
strictDepth: typeof opts.strictDepth === 'boolean' ? !!opts.strictDepth : defaults.strictDepth,
strictNullHandling: typeof opts.strictNullHandling === 'boolean' ? opts.strictNullHandling : defaults.strictNullHandling strictNullHandling: typeof opts.strictNullHandling === 'boolean' ? opts.strictNullHandling : defaults.strictNullHandling
}; };
}; };

81
node_modules/qs/lib/stringify.js generated vendored
View File

@@ -19,7 +19,6 @@ var arrayPrefixGenerators = {
}; };
var isArray = Array.isArray; var isArray = Array.isArray;
var split = String.prototype.split;
var push = Array.prototype.push; var push = Array.prototype.push;
var pushToArray = function (arr, valueOrArray) { var pushToArray = function (arr, valueOrArray) {
push.apply(arr, isArray(valueOrArray) ? valueOrArray : [valueOrArray]); push.apply(arr, isArray(valueOrArray) ? valueOrArray : [valueOrArray]);
@@ -31,10 +30,13 @@ var defaultFormat = formats['default'];
var defaults = { var defaults = {
addQueryPrefix: false, addQueryPrefix: false,
allowDots: false, allowDots: false,
allowEmptyArrays: false,
arrayFormat: 'indices',
charset: 'utf-8', charset: 'utf-8',
charsetSentinel: false, charsetSentinel: false,
delimiter: '&', delimiter: '&',
encode: true, encode: true,
encodeDotInKeys: false,
encoder: utils.encode, encoder: utils.encode,
encodeValuesOnly: false, encodeValuesOnly: false,
format: defaultFormat, format: defaultFormat,
@@ -63,8 +65,10 @@ var stringify = function stringify(
prefix, prefix,
generateArrayPrefix, generateArrayPrefix,
commaRoundTrip, commaRoundTrip,
allowEmptyArrays,
strictNullHandling, strictNullHandling,
skipNulls, skipNulls,
encodeDotInKeys,
encoder, encoder,
filter, filter,
sort, sort,
@@ -121,14 +125,6 @@ var stringify = function stringify(
if (isNonNullishPrimitive(obj) || utils.isBuffer(obj)) { if (isNonNullishPrimitive(obj) || utils.isBuffer(obj)) {
if (encoder) { if (encoder) {
var keyValue = encodeValuesOnly ? prefix : encoder(prefix, defaults.encoder, charset, 'key', format); var keyValue = encodeValuesOnly ? prefix : encoder(prefix, defaults.encoder, charset, 'key', format);
if (generateArrayPrefix === 'comma' && encodeValuesOnly) {
var valuesArray = split.call(String(obj), ',');
var valuesJoined = '';
for (var i = 0; i < valuesArray.length; ++i) {
valuesJoined += (i === 0 ? '' : ',') + formatter(encoder(valuesArray[i], defaults.encoder, charset, 'value', format));
}
return [formatter(keyValue) + (commaRoundTrip && isArray(obj) && valuesArray.length === 1 ? '[]' : '') + '=' + valuesJoined];
}
return [formatter(keyValue) + '=' + formatter(encoder(obj, defaults.encoder, charset, 'value', format))]; return [formatter(keyValue) + '=' + formatter(encoder(obj, defaults.encoder, charset, 'value', format))];
} }
return [formatter(prefix) + '=' + formatter(String(obj))]; return [formatter(prefix) + '=' + formatter(String(obj))];
@@ -143,6 +139,9 @@ var stringify = function stringify(
var objKeys; var objKeys;
if (generateArrayPrefix === 'comma' && isArray(obj)) { if (generateArrayPrefix === 'comma' && isArray(obj)) {
// we need to join elements in // we need to join elements in
if (encodeValuesOnly && encoder) {
obj = utils.maybeMap(obj, encoder);
}
objKeys = [{ value: obj.length > 0 ? obj.join(',') || null : void undefined }]; objKeys = [{ value: obj.length > 0 ? obj.join(',') || null : void undefined }];
} else if (isArray(filter)) { } else if (isArray(filter)) {
objKeys = filter; objKeys = filter;
@@ -151,7 +150,13 @@ var stringify = function stringify(
objKeys = sort ? keys.sort(sort) : keys; objKeys = sort ? keys.sort(sort) : keys;
} }
var adjustedPrefix = commaRoundTrip && isArray(obj) && obj.length === 1 ? prefix + '[]' : prefix; var encodedPrefix = encodeDotInKeys ? prefix.replace(/\./g, '%2E') : prefix;
var adjustedPrefix = commaRoundTrip && isArray(obj) && obj.length === 1 ? encodedPrefix + '[]' : encodedPrefix;
if (allowEmptyArrays && isArray(obj) && obj.length === 0) {
return adjustedPrefix + '[]';
}
for (var j = 0; j < objKeys.length; ++j) { for (var j = 0; j < objKeys.length; ++j) {
var key = objKeys[j]; var key = objKeys[j];
@@ -161,9 +166,10 @@ var stringify = function stringify(
continue; continue;
} }
var encodedKey = allowDots && encodeDotInKeys ? key.replace(/\./g, '%2E') : key;
var keyPrefix = isArray(obj) var keyPrefix = isArray(obj)
? typeof generateArrayPrefix === 'function' ? generateArrayPrefix(adjustedPrefix, key) : adjustedPrefix ? typeof generateArrayPrefix === 'function' ? generateArrayPrefix(adjustedPrefix, encodedKey) : adjustedPrefix
: adjustedPrefix + (allowDots ? '.' + key : '[' + key + ']'); : adjustedPrefix + (allowDots ? '.' + encodedKey : '[' + encodedKey + ']');
sideChannel.set(object, step); sideChannel.set(object, step);
var valueSideChannel = getSideChannel(); var valueSideChannel = getSideChannel();
@@ -173,9 +179,11 @@ var stringify = function stringify(
keyPrefix, keyPrefix,
generateArrayPrefix, generateArrayPrefix,
commaRoundTrip, commaRoundTrip,
allowEmptyArrays,
strictNullHandling, strictNullHandling,
skipNulls, skipNulls,
encoder, encodeDotInKeys,
generateArrayPrefix === 'comma' && encodeValuesOnly && isArray(obj) ? null : encoder,
filter, filter,
sort, sort,
allowDots, allowDots,
@@ -196,6 +204,14 @@ var normalizeStringifyOptions = function normalizeStringifyOptions(opts) {
return defaults; return defaults;
} }
if (typeof opts.allowEmptyArrays !== 'undefined' && typeof opts.allowEmptyArrays !== 'boolean') {
throw new TypeError('`allowEmptyArrays` option can only be `true` or `false`, when provided');
}
if (typeof opts.encodeDotInKeys !== 'undefined' && typeof opts.encodeDotInKeys !== 'boolean') {
throw new TypeError('`encodeDotInKeys` option can only be `true` or `false`, when provided');
}
if (opts.encoder !== null && typeof opts.encoder !== 'undefined' && typeof opts.encoder !== 'function') { if (opts.encoder !== null && typeof opts.encoder !== 'undefined' && typeof opts.encoder !== 'function') {
throw new TypeError('Encoder has to be a function.'); throw new TypeError('Encoder has to be a function.');
} }
@@ -219,13 +235,32 @@ var normalizeStringifyOptions = function normalizeStringifyOptions(opts) {
filter = opts.filter; filter = opts.filter;
} }
var arrayFormat;
if (opts.arrayFormat in arrayPrefixGenerators) {
arrayFormat = opts.arrayFormat;
} else if ('indices' in opts) {
arrayFormat = opts.indices ? 'indices' : 'repeat';
} else {
arrayFormat = defaults.arrayFormat;
}
if ('commaRoundTrip' in opts && typeof opts.commaRoundTrip !== 'boolean') {
throw new TypeError('`commaRoundTrip` must be a boolean, or absent');
}
var allowDots = typeof opts.allowDots === 'undefined' ? opts.encodeDotInKeys === true ? true : defaults.allowDots : !!opts.allowDots;
return { return {
addQueryPrefix: typeof opts.addQueryPrefix === 'boolean' ? opts.addQueryPrefix : defaults.addQueryPrefix, addQueryPrefix: typeof opts.addQueryPrefix === 'boolean' ? opts.addQueryPrefix : defaults.addQueryPrefix,
allowDots: typeof opts.allowDots === 'undefined' ? defaults.allowDots : !!opts.allowDots, allowDots: allowDots,
allowEmptyArrays: typeof opts.allowEmptyArrays === 'boolean' ? !!opts.allowEmptyArrays : defaults.allowEmptyArrays,
arrayFormat: arrayFormat,
charset: charset, charset: charset,
charsetSentinel: typeof opts.charsetSentinel === 'boolean' ? opts.charsetSentinel : defaults.charsetSentinel, charsetSentinel: typeof opts.charsetSentinel === 'boolean' ? opts.charsetSentinel : defaults.charsetSentinel,
commaRoundTrip: opts.commaRoundTrip,
delimiter: typeof opts.delimiter === 'undefined' ? defaults.delimiter : opts.delimiter, delimiter: typeof opts.delimiter === 'undefined' ? defaults.delimiter : opts.delimiter,
encode: typeof opts.encode === 'boolean' ? opts.encode : defaults.encode, encode: typeof opts.encode === 'boolean' ? opts.encode : defaults.encode,
encodeDotInKeys: typeof opts.encodeDotInKeys === 'boolean' ? opts.encodeDotInKeys : defaults.encodeDotInKeys,
encoder: typeof opts.encoder === 'function' ? opts.encoder : defaults.encoder, encoder: typeof opts.encoder === 'function' ? opts.encoder : defaults.encoder,
encodeValuesOnly: typeof opts.encodeValuesOnly === 'boolean' ? opts.encodeValuesOnly : defaults.encodeValuesOnly, encodeValuesOnly: typeof opts.encodeValuesOnly === 'boolean' ? opts.encodeValuesOnly : defaults.encodeValuesOnly,
filter: filter, filter: filter,
@@ -259,20 +294,8 @@ module.exports = function (object, opts) {
return ''; return '';
} }
var arrayFormat; var generateArrayPrefix = arrayPrefixGenerators[options.arrayFormat];
if (opts && opts.arrayFormat in arrayPrefixGenerators) { var commaRoundTrip = generateArrayPrefix === 'comma' && options.commaRoundTrip;
arrayFormat = opts.arrayFormat;
} else if (opts && 'indices' in opts) {
arrayFormat = opts.indices ? 'indices' : 'repeat';
} else {
arrayFormat = 'indices';
}
var generateArrayPrefix = arrayPrefixGenerators[arrayFormat];
if (opts && 'commaRoundTrip' in opts && typeof opts.commaRoundTrip !== 'boolean') {
throw new TypeError('`commaRoundTrip` must be a boolean, or absent');
}
var commaRoundTrip = generateArrayPrefix === 'comma' && opts && opts.commaRoundTrip;
if (!objKeys) { if (!objKeys) {
objKeys = Object.keys(obj); objKeys = Object.keys(obj);
@@ -294,8 +317,10 @@ module.exports = function (object, opts) {
key, key,
generateArrayPrefix, generateArrayPrefix,
commaRoundTrip, commaRoundTrip,
options.allowEmptyArrays,
options.strictNullHandling, options.strictNullHandling,
options.skipNulls, options.skipNulls,
options.encodeDotInKeys,
options.encode ? options.encoder : null, options.encode ? options.encoder : null,
options.filter, options.filter,
options.sort, options.sort,

31
node_modules/qs/lib/utils.js generated vendored
View File

@@ -122,6 +122,10 @@ var decode = function (str, decoder, charset) {
} }
}; };
var limit = 1024;
/* eslint operator-linebreak: [2, "before"] */
var encode = function encode(str, defaultEncoder, charset, kind, format) { var encode = function encode(str, defaultEncoder, charset, kind, format) {
// This code was originally written by Brian White (mscdex) for the io.js core querystring library. // This code was originally written by Brian White (mscdex) for the io.js core querystring library.
// It has been adapted here for stricter adherence to RFC 3986 // It has been adapted here for stricter adherence to RFC 3986
@@ -143,9 +147,12 @@ var encode = function encode(str, defaultEncoder, charset, kind, format) {
} }
var out = ''; var out = '';
for (var i = 0; i < string.length; ++i) { for (var j = 0; j < string.length; j += limit) {
var c = string.charCodeAt(i); var segment = string.length >= limit ? string.slice(j, j + limit) : string;
var arr = [];
for (var i = 0; i < segment.length; ++i) {
var c = segment.charCodeAt(i);
if ( if (
c === 0x2D // - c === 0x2D // -
|| c === 0x2E // . || c === 0x2E // .
@@ -156,34 +163,40 @@ var encode = function encode(str, defaultEncoder, charset, kind, format) {
|| (c >= 0x61 && c <= 0x7A) // A-Z || (c >= 0x61 && c <= 0x7A) // A-Z
|| (format === formats.RFC1738 && (c === 0x28 || c === 0x29)) // ( ) || (format === formats.RFC1738 && (c === 0x28 || c === 0x29)) // ( )
) { ) {
out += string.charAt(i); arr[arr.length] = segment.charAt(i);
continue; continue;
} }
if (c < 0x80) { if (c < 0x80) {
out = out + hexTable[c]; arr[arr.length] = hexTable[c];
continue; continue;
} }
if (c < 0x800) { if (c < 0x800) {
out = out + (hexTable[0xC0 | (c >> 6)] + hexTable[0x80 | (c & 0x3F)]); arr[arr.length] = hexTable[0xC0 | (c >> 6)]
+ hexTable[0x80 | (c & 0x3F)];
continue; continue;
} }
if (c < 0xD800 || c >= 0xE000) { if (c < 0xD800 || c >= 0xE000) {
out = out + (hexTable[0xE0 | (c >> 12)] + hexTable[0x80 | ((c >> 6) & 0x3F)] + hexTable[0x80 | (c & 0x3F)]); arr[arr.length] = hexTable[0xE0 | (c >> 12)]
+ hexTable[0x80 | ((c >> 6) & 0x3F)]
+ hexTable[0x80 | (c & 0x3F)];
continue; continue;
} }
i += 1; i += 1;
c = 0x10000 + (((c & 0x3FF) << 10) | (string.charCodeAt(i) & 0x3FF)); c = 0x10000 + (((c & 0x3FF) << 10) | (segment.charCodeAt(i) & 0x3FF));
/* eslint operator-linebreak: [2, "before"] */
out += hexTable[0xF0 | (c >> 18)] arr[arr.length] = hexTable[0xF0 | (c >> 18)]
+ hexTable[0x80 | ((c >> 12) & 0x3F)] + hexTable[0x80 | ((c >> 12) & 0x3F)]
+ hexTable[0x80 | ((c >> 6) & 0x3F)] + hexTable[0x80 | ((c >> 6) & 0x3F)]
+ hexTable[0x80 | (c & 0x3F)]; + hexTable[0x80 | (c & 0x3F)];
} }
out += arr.join('');
}
return out; return out;
}; };

38
node_modules/qs/package.json generated vendored
View File

@@ -2,7 +2,7 @@
"name": "qs", "name": "qs",
"description": "A querystring parser that supports nesting and arrays, with a depth limit", "description": "A querystring parser that supports nesting and arrays, with a depth limit",
"homepage": "https://github.com/ljharb/qs", "homepage": "https://github.com/ljharb/qs",
"version": "6.11.0", "version": "6.13.0",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/ljharb/qs.git" "url": "https://github.com/ljharb/qs.git"
@@ -11,6 +11,7 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
}, },
"main": "lib/index.js", "main": "lib/index.js",
"sideEffects": false,
"contributors": [ "contributors": [
{ {
"name": "Jordan Harband", "name": "Jordan Harband",
@@ -30,40 +31,51 @@
"node": ">=0.6" "node": ">=0.6"
}, },
"dependencies": { "dependencies": {
"side-channel": "^1.0.4" "side-channel": "^1.0.6"
}, },
"devDependencies": { "devDependencies": {
"@ljharb/eslint-config": "^21.0.0", "@browserify/envify": "^6.0.0",
"aud": "^2.0.0", "@browserify/uglifyify": "^6.0.0",
"@ljharb/eslint-config": "^21.1.1",
"browserify": "^16.5.2", "browserify": "^16.5.2",
"bundle-collapser": "^1.4.0",
"common-shakeify": "~1.0.0",
"eclint": "^2.8.1", "eclint": "^2.8.1",
"es-value-fixtures": "^1.4.2",
"eslint": "=8.8.0", "eslint": "=8.8.0",
"evalmd": "^0.0.19", "evalmd": "^0.0.19",
"for-each": "^0.3.3", "for-each": "^0.3.3",
"glob": "=10.3.7",
"has-override-mistake": "^1.0.1",
"has-property-descriptors": "^1.0.2",
"has-symbols": "^1.0.3", "has-symbols": "^1.0.3",
"iconv-lite": "^0.5.1", "iconv-lite": "^0.5.1",
"in-publish": "^2.0.1", "in-publish": "^2.0.1",
"jackspeak": "=2.1.1",
"mkdirp": "^0.5.5", "mkdirp": "^0.5.5",
"npmignore": "^0.3.0", "mock-property": "^1.0.3",
"module-deps": "^6.2.3",
"npmignore": "^0.3.1",
"nyc": "^10.3.2", "nyc": "^10.3.2",
"object-inspect": "^1.12.2", "object-inspect": "^1.13.2",
"qs-iconv": "^1.0.4", "qs-iconv": "^1.0.4",
"safe-publish-latest": "^2.0.0", "safe-publish-latest": "^2.0.0",
"safer-buffer": "^2.1.2", "safer-buffer": "^2.1.2",
"tape": "^5.5.3" "tape": "^5.8.1",
"unassertify": "^3.0.1"
}, },
"scripts": { "scripts": {
"prepack": "npmignore --auto --commentLines=autogenerated", "prepack": "npmignore --auto --commentLines=autogenerated && npm run dist",
"prepublishOnly": "safe-publish-latest && npm run dist", "prepublishOnly": "safe-publish-latest",
"prepublish": "not-in-publish || npm run prepublishOnly", "prepublish": "not-in-publish || npm run prepublishOnly",
"pretest": "npm run --silent readme && npm run --silent lint", "pretest": "npm run --silent readme && npm run --silent lint",
"test": "npm run tests-only", "test": "npm run tests-only",
"tests-only": "nyc tape 'test/**/*.js'", "tests-only": "nyc tape 'test/**/*.js'",
"posttest": "aud --production", "posttest": "npx npm@'>=10.2' audit --production",
"readme": "evalmd README.md", "readme": "evalmd README.md",
"postlint": "eclint check $(git ls-files | xargs find 2> /dev/null | grep -vE 'node_modules|\\.git' | grep -v dist/)", "postlint": "eclint check $(git ls-files | xargs find 2> /dev/null | grep -vE 'node_modules|\\.git' | grep -v dist/)",
"lint": "eslint --ext=js,mjs .", "lint": "eslint --ext=js,mjs .",
"dist": "mkdirp dist && browserify --standalone Qs lib/index.js > dist/qs.js" "dist": "mkdirp dist && browserify --standalone Qs -g unassertify -g @browserify/envify -g [@browserify/uglifyify --mangle.keep_fnames --compress.keep_fnames --format.indent_level=1 --compress.arrows=false --compress.passes=4 --compress.typeofs=false] -p common-shakeify -p bundle-collapser/plugin lib/index.js > dist/qs.js"
}, },
"license": "BSD-3-Clause", "license": "BSD-3-Clause",
"publishConfig": { "publishConfig": {
@@ -71,7 +83,9 @@
"!dist/*", "!dist/*",
"bower.json", "bower.json",
"component.json", "component.json",
".github/workflows" ".github/workflows",
"logos",
"tea.yaml"
] ]
} }
} }

385
node_modules/qs/test/parse.js generated vendored
View File

@@ -1,10 +1,17 @@
'use strict'; 'use strict';
var test = require('tape'); var test = require('tape');
var hasPropertyDescriptors = require('has-property-descriptors')();
var iconv = require('iconv-lite');
var mockProperty = require('mock-property');
var hasOverrideMistake = require('has-override-mistake')();
var SaferBuffer = require('safer-buffer').Buffer;
var v = require('es-value-fixtures');
var inspect = require('object-inspect');
var emptyTestCases = require('./empty-keys-cases').emptyTestCases;
var qs = require('../'); var qs = require('../');
var utils = require('../lib/utils'); var utils = require('../lib/utils');
var iconv = require('iconv-lite');
var SaferBuffer = require('safer-buffer').Buffer;
test('parse()', function (t) { test('parse()', function (t) {
t.test('parses a simple string', function (st) { t.test('parses a simple string', function (st) {
@@ -32,41 +39,156 @@ test('parse()', function (t) {
st.end(); st.end();
}); });
t.test('arrayFormat: brackets allows only explicit arrays', function (st) { t.test('comma: false', function (st) {
st.deepEqual(qs.parse('a[]=b&a[]=c', { arrayFormat: 'brackets' }), { a: ['b', 'c'] }); st.deepEqual(qs.parse('a[]=b&a[]=c'), { a: ['b', 'c'] });
st.deepEqual(qs.parse('a[0]=b&a[1]=c', { arrayFormat: 'brackets' }), { a: ['b', 'c'] }); st.deepEqual(qs.parse('a[0]=b&a[1]=c'), { a: ['b', 'c'] });
st.deepEqual(qs.parse('a=b,c', { arrayFormat: 'brackets' }), { a: 'b,c' }); st.deepEqual(qs.parse('a=b,c'), { a: 'b,c' });
st.deepEqual(qs.parse('a=b&a=c', { arrayFormat: 'brackets' }), { a: ['b', 'c'] }); st.deepEqual(qs.parse('a=b&a=c'), { a: ['b', 'c'] });
st.end(); st.end();
}); });
t.test('arrayFormat: indices allows only indexed arrays', function (st) { t.test('comma: true', function (st) {
st.deepEqual(qs.parse('a[]=b&a[]=c', { arrayFormat: 'indices' }), { a: ['b', 'c'] }); st.deepEqual(qs.parse('a[]=b&a[]=c', { comma: true }), { a: ['b', 'c'] });
st.deepEqual(qs.parse('a[0]=b&a[1]=c', { arrayFormat: 'indices' }), { a: ['b', 'c'] }); st.deepEqual(qs.parse('a[0]=b&a[1]=c', { comma: true }), { a: ['b', 'c'] });
st.deepEqual(qs.parse('a=b,c', { arrayFormat: 'indices' }), { a: 'b,c' }); st.deepEqual(qs.parse('a=b,c', { comma: true }), { a: ['b', 'c'] });
st.deepEqual(qs.parse('a=b&a=c', { arrayFormat: 'indices' }), { a: ['b', 'c'] }); st.deepEqual(qs.parse('a=b&a=c', { comma: true }), { a: ['b', 'c'] });
st.end();
});
t.test('arrayFormat: comma allows only comma-separated arrays', function (st) {
st.deepEqual(qs.parse('a[]=b&a[]=c', { arrayFormat: 'comma' }), { a: ['b', 'c'] });
st.deepEqual(qs.parse('a[0]=b&a[1]=c', { arrayFormat: 'comma' }), { a: ['b', 'c'] });
st.deepEqual(qs.parse('a=b,c', { arrayFormat: 'comma' }), { a: 'b,c' });
st.deepEqual(qs.parse('a=b&a=c', { arrayFormat: 'comma' }), { a: ['b', 'c'] });
st.end();
});
t.test('arrayFormat: repeat allows only repeated values', function (st) {
st.deepEqual(qs.parse('a[]=b&a[]=c', { arrayFormat: 'repeat' }), { a: ['b', 'c'] });
st.deepEqual(qs.parse('a[0]=b&a[1]=c', { arrayFormat: 'repeat' }), { a: ['b', 'c'] });
st.deepEqual(qs.parse('a=b,c', { arrayFormat: 'repeat' }), { a: 'b,c' });
st.deepEqual(qs.parse('a=b&a=c', { arrayFormat: 'repeat' }), { a: ['b', 'c'] });
st.end(); st.end();
}); });
t.test('allows enabling dot notation', function (st) { t.test('allows enabling dot notation', function (st) {
st.deepEqual(qs.parse('a.b=c'), { 'a.b': 'c' }); st.deepEqual(qs.parse('a.b=c'), { 'a.b': 'c' });
st.deepEqual(qs.parse('a.b=c', { allowDots: true }), { a: { b: 'c' } }); st.deepEqual(qs.parse('a.b=c', { allowDots: true }), { a: { b: 'c' } });
st.end();
});
t.test('decode dot keys correctly', function (st) {
st.deepEqual(
qs.parse('name%252Eobj.first=John&name%252Eobj.last=Doe', { allowDots: false, decodeDotInKeys: false }),
{ 'name%2Eobj.first': 'John', 'name%2Eobj.last': 'Doe' },
'with allowDots false and decodeDotInKeys false'
);
st.deepEqual(
qs.parse('name.obj.first=John&name.obj.last=Doe', { allowDots: true, decodeDotInKeys: false }),
{ name: { obj: { first: 'John', last: 'Doe' } } },
'with allowDots false and decodeDotInKeys false'
);
st.deepEqual(
qs.parse('name%252Eobj.first=John&name%252Eobj.last=Doe', { allowDots: true, decodeDotInKeys: false }),
{ 'name%2Eobj': { first: 'John', last: 'Doe' } },
'with allowDots true and decodeDotInKeys false'
);
st.deepEqual(
qs.parse('name%252Eobj.first=John&name%252Eobj.last=Doe', { allowDots: true, decodeDotInKeys: true }),
{ 'name.obj': { first: 'John', last: 'Doe' } },
'with allowDots true and decodeDotInKeys true'
);
st.deepEqual(
qs.parse(
'name%252Eobj%252Esubobject.first%252Egodly%252Ename=John&name%252Eobj%252Esubobject.last=Doe',
{ allowDots: false, decodeDotInKeys: false }
),
{ 'name%2Eobj%2Esubobject.first%2Egodly%2Ename': 'John', 'name%2Eobj%2Esubobject.last': 'Doe' },
'with allowDots false and decodeDotInKeys false'
);
st.deepEqual(
qs.parse(
'name.obj.subobject.first.godly.name=John&name.obj.subobject.last=Doe',
{ allowDots: true, decodeDotInKeys: false }
),
{ name: { obj: { subobject: { first: { godly: { name: 'John' } }, last: 'Doe' } } } },
'with allowDots true and decodeDotInKeys false'
);
st.deepEqual(
qs.parse(
'name%252Eobj%252Esubobject.first%252Egodly%252Ename=John&name%252Eobj%252Esubobject.last=Doe',
{ allowDots: true, decodeDotInKeys: true }
),
{ 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } },
'with allowDots true and decodeDotInKeys true'
);
st.deepEqual(
qs.parse('name%252Eobj.first=John&name%252Eobj.last=Doe'),
{ 'name%2Eobj.first': 'John', 'name%2Eobj.last': 'Doe' },
'with allowDots and decodeDotInKeys undefined'
);
st.end();
});
t.test('should decode dot in key of object, and allow enabling dot notation when decodeDotInKeys is set to true and allowDots is undefined', function (st) {
st.deepEqual(
qs.parse(
'name%252Eobj%252Esubobject.first%252Egodly%252Ename=John&name%252Eobj%252Esubobject.last=Doe',
{ decodeDotInKeys: true }
),
{ 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } },
'with allowDots undefined and decodeDotInKeys true'
);
st.end();
});
t.test('should throw when decodeDotInKeys is not of type boolean', function (st) {
st['throws'](
function () { qs.parse('foo[]&bar=baz', { decodeDotInKeys: 'foobar' }); },
TypeError
);
st['throws'](
function () { qs.parse('foo[]&bar=baz', { decodeDotInKeys: 0 }); },
TypeError
);
st['throws'](
function () { qs.parse('foo[]&bar=baz', { decodeDotInKeys: NaN }); },
TypeError
);
st['throws'](
function () { qs.parse('foo[]&bar=baz', { decodeDotInKeys: null }); },
TypeError
);
st.end();
});
t.test('allows empty arrays in obj values', function (st) {
st.deepEqual(qs.parse('foo[]&bar=baz', { allowEmptyArrays: true }), { foo: [], bar: 'baz' });
st.deepEqual(qs.parse('foo[]&bar=baz', { allowEmptyArrays: false }), { foo: [''], bar: 'baz' });
st.end();
});
t.test('should throw when allowEmptyArrays is not of type boolean', function (st) {
st['throws'](
function () { qs.parse('foo[]&bar=baz', { allowEmptyArrays: 'foobar' }); },
TypeError
);
st['throws'](
function () { qs.parse('foo[]&bar=baz', { allowEmptyArrays: 0 }); },
TypeError
);
st['throws'](
function () { qs.parse('foo[]&bar=baz', { allowEmptyArrays: NaN }); },
TypeError
);
st['throws'](
function () { qs.parse('foo[]&bar=baz', { allowEmptyArrays: null }); },
TypeError
);
st.end();
});
t.test('allowEmptyArrays + strictNullHandling', function (st) {
st.deepEqual(
qs.parse('testEmptyArray[]', { strictNullHandling: true, allowEmptyArrays: true }),
{ testEmptyArray: [] }
);
st.end(); st.end();
}); });
@@ -322,14 +444,14 @@ test('parse()', function (t) {
}); });
t.test('should not throw when a native prototype has an enumerable property', function (st) { t.test('should not throw when a native prototype has an enumerable property', function (st) {
Object.prototype.crash = ''; st.intercept(Object.prototype, 'crash', { value: '' });
Array.prototype.crash = ''; st.intercept(Array.prototype, 'crash', { value: '' });
st.doesNotThrow(qs.parse.bind(null, 'a=b')); st.doesNotThrow(qs.parse.bind(null, 'a=b'));
st.deepEqual(qs.parse('a=b'), { a: 'b' }); st.deepEqual(qs.parse('a=b'), { a: 'b' });
st.doesNotThrow(qs.parse.bind(null, 'a[][b]=c')); st.doesNotThrow(qs.parse.bind(null, 'a[][b]=c'));
st.deepEqual(qs.parse('a[][b]=c'), { a: [{ b: 'c' }] }); st.deepEqual(qs.parse('a[][b]=c'), { a: [{ b: 'c' }] });
delete Object.prototype.crash;
delete Array.prototype.crash;
st.end(); st.end();
}); });
@@ -360,8 +482,14 @@ test('parse()', function (t) {
t.test('allows overriding array limit', function (st) { t.test('allows overriding array limit', function (st) {
st.deepEqual(qs.parse('a[0]=b', { arrayLimit: -1 }), { a: { 0: 'b' } }); st.deepEqual(qs.parse('a[0]=b', { arrayLimit: -1 }), { a: { 0: 'b' } });
st.deepEqual(qs.parse('a[0]=b', { arrayLimit: 0 }), { a: ['b'] });
st.deepEqual(qs.parse('a[-1]=b', { arrayLimit: -1 }), { a: { '-1': 'b' } }); st.deepEqual(qs.parse('a[-1]=b', { arrayLimit: -1 }), { a: { '-1': 'b' } });
st.deepEqual(qs.parse('a[-1]=b', { arrayLimit: 0 }), { a: { '-1': 'b' } });
st.deepEqual(qs.parse('a[0]=b&a[1]=c', { arrayLimit: -1 }), { a: { 0: 'b', 1: 'c' } });
st.deepEqual(qs.parse('a[0]=b&a[1]=c', { arrayLimit: 0 }), { a: { 0: 'b', 1: 'c' } }); st.deepEqual(qs.parse('a[0]=b&a[1]=c', { arrayLimit: 0 }), { a: { 0: 'b', 1: 'c' } });
st.end(); st.end();
}); });
@@ -452,6 +580,15 @@ test('parse()', function (t) {
st.end(); st.end();
}); });
t.test('parses url-encoded brackets holds array of arrays when having two parts of strings with comma as array divider', function (st) {
st.deepEqual(qs.parse('foo%5B%5D=1,2,3&foo%5B%5D=4,5,6', { comma: true }), { foo: [['1', '2', '3'], ['4', '5', '6']] });
st.deepEqual(qs.parse('foo%5B%5D=1,2,3&foo%5B%5D=', { comma: true }), { foo: [['1', '2', '3'], ''] });
st.deepEqual(qs.parse('foo%5B%5D=1,2,3&foo%5B%5D=,', { comma: true }), { foo: [['1', '2', '3'], ['', '']] });
st.deepEqual(qs.parse('foo%5B%5D=1,2,3&foo%5B%5D=a', { comma: true }), { foo: [['1', '2', '3'], 'a'] });
st.end();
});
t.test('parses comma delimited array while having percent-encoded comma treated as normal text', function (st) { t.test('parses comma delimited array while having percent-encoded comma treated as normal text', function (st) {
st.deepEqual(qs.parse('foo=a%2Cb', { comma: true }), { foo: 'a,b' }); st.deepEqual(qs.parse('foo=a%2Cb', { comma: true }), { foo: 'a,b' });
st.deepEqual(qs.parse('foo=a%2C%20b,d', { comma: true }), { foo: ['a, b', 'd'] }); st.deepEqual(qs.parse('foo=a%2C%20b,d', { comma: true }), { foo: ['a, b', 'd'] });
@@ -499,10 +636,12 @@ test('parse()', function (t) {
}); });
t.test('does not blow up when Buffer global is missing', function (st) { t.test('does not blow up when Buffer global is missing', function (st) {
var tempBuffer = global.Buffer; var restore = mockProperty(global, 'Buffer', { 'delete': true });
delete global.Buffer;
var result = qs.parse('a=b&c=d'); var result = qs.parse('a=b&c=d');
global.Buffer = tempBuffer;
restore();
st.deepEqual(result, { a: 'b', c: 'd' }); st.deepEqual(result, { a: 'b', c: 'd' });
st.end(); st.end();
}); });
@@ -601,6 +740,34 @@ test('parse()', function (t) {
st.end(); st.end();
}); });
t.test('does not crash when the global Object prototype is frozen', { skip: !hasPropertyDescriptors || !hasOverrideMistake }, function (st) {
// We can't actually freeze the global Object prototype as that will interfere with other tests, and once an object is frozen, it
// can't be unfrozen. Instead, we add a new non-writable property to simulate this.
st.teardown(mockProperty(Object.prototype, 'frozenProp', { value: 'foo', nonWritable: true, nonEnumerable: true }));
st['throws'](
function () {
var obj = {};
obj.frozenProp = 'bar';
},
// node < 6 has a different error message
/^TypeError: Cannot assign to read only property 'frozenProp' of (?:object '#<Object>'|#<Object>)/,
'regular assignment of an inherited non-writable property throws'
);
var parsed;
st.doesNotThrow(
function () {
parsed = qs.parse('frozenProp', { allowPrototypes: false });
},
'parsing a nonwritable Object.prototype property does not throw'
);
st.deepEqual(parsed, {}, 'bare "frozenProp" results in {}');
st.end();
});
t.test('params starting with a closing bracket', function (st) { t.test('params starting with a closing bracket', function (st) {
st.deepEqual(qs.parse(']=toString'), { ']': 'toString' }); st.deepEqual(qs.parse(']=toString'), { ']': 'toString' });
st.deepEqual(qs.parse(']]=toString'), { ']]': 'toString' }); st.deepEqual(qs.parse(']]=toString'), { ']]': 'toString' });
@@ -853,3 +1020,151 @@ test('parse()', function (t) {
t.end(); t.end();
}); });
test('parses empty keys', function (t) {
emptyTestCases.forEach(function (testCase) {
t.test('skips empty string key with ' + testCase.input, function (st) {
st.deepEqual(qs.parse(testCase.input), testCase.noEmptyKeys);
st.end();
});
});
});
test('`duplicates` option', function (t) {
v.nonStrings.concat('not a valid option').forEach(function (invalidOption) {
if (typeof invalidOption !== 'undefined') {
t['throws'](
function () { qs.parse('', { duplicates: invalidOption }); },
TypeError,
'throws on invalid option: ' + inspect(invalidOption)
);
}
});
t.deepEqual(
qs.parse('foo=bar&foo=baz'),
{ foo: ['bar', 'baz'] },
'duplicates: default, combine'
);
t.deepEqual(
qs.parse('foo=bar&foo=baz', { duplicates: 'combine' }),
{ foo: ['bar', 'baz'] },
'duplicates: combine'
);
t.deepEqual(
qs.parse('foo=bar&foo=baz', { duplicates: 'first' }),
{ foo: 'bar' },
'duplicates: first'
);
t.deepEqual(
qs.parse('foo=bar&foo=baz', { duplicates: 'last' }),
{ foo: 'baz' },
'duplicates: last'
);
t.end();
});
test('qs strictDepth option - throw cases', function (t) {
t.test('throws an exception when depth exceeds the limit with strictDepth: true', function (st) {
st['throws'](
function () {
qs.parse('a[b][c][d][e][f][g][h][i]=j', { depth: 1, strictDepth: true });
},
RangeError,
'Should throw RangeError'
);
st.end();
});
t.test('throws an exception for multiple nested arrays with strictDepth: true', function (st) {
st['throws'](
function () {
qs.parse('a[0][1][2][3][4]=b', { depth: 3, strictDepth: true });
},
RangeError,
'Should throw RangeError'
);
st.end();
});
t.test('throws an exception for nested objects and arrays with strictDepth: true', function (st) {
st['throws'](
function () {
qs.parse('a[b][c][0][d][e]=f', { depth: 3, strictDepth: true });
},
RangeError,
'Should throw RangeError'
);
st.end();
});
t.test('throws an exception for different types of values with strictDepth: true', function (st) {
st['throws'](
function () {
qs.parse('a[b][c][d][e]=true&a[b][c][d][f]=42', { depth: 3, strictDepth: true });
},
RangeError,
'Should throw RangeError'
);
st.end();
});
});
test('qs strictDepth option - non-throw cases', function (t) {
t.test('when depth is 0 and strictDepth true, do not throw', function (st) {
st.doesNotThrow(
function () {
qs.parse('a[b][c][d][e]=true&a[b][c][d][f]=42', { depth: 0, strictDepth: true });
},
RangeError,
'Should not throw RangeError'
);
st.end();
});
t.test('parses successfully when depth is within the limit with strictDepth: true', function (st) {
st.doesNotThrow(
function () {
var result = qs.parse('a[b]=c', { depth: 1, strictDepth: true });
st.deepEqual(result, { a: { b: 'c' } }, 'Should parse correctly');
}
);
st.end();
});
t.test('does not throw an exception when depth exceeds the limit with strictDepth: false', function (st) {
st.doesNotThrow(
function () {
var result = qs.parse('a[b][c][d][e][f][g][h][i]=j', { depth: 1 });
st.deepEqual(result, { a: { b: { '[c][d][e][f][g][h][i]': 'j' } } }, 'Should parse with depth limit');
}
);
st.end();
});
t.test('parses successfully when depth is within the limit with strictDepth: false', function (st) {
st.doesNotThrow(
function () {
var result = qs.parse('a[b]=c', { depth: 1 });
st.deepEqual(result, { a: { b: 'c' } }, 'Should parse correctly');
}
);
st.end();
});
t.test('does not throw when depth is exactly at the limit with strictDepth: true', function (st) {
st.doesNotThrow(
function () {
var result = qs.parse('a[b][c]=d', { depth: 2, strictDepth: true });
st.deepEqual(result, { a: { b: { c: 'd' } } }, 'Should parse correctly');
}
);
st.end();
});
});

483
node_modules/qs/test/stringify.js generated vendored
View File

@@ -6,6 +6,8 @@ var utils = require('../lib/utils');
var iconv = require('iconv-lite'); var iconv = require('iconv-lite');
var SaferBuffer = require('safer-buffer').Buffer; var SaferBuffer = require('safer-buffer').Buffer;
var hasSymbols = require('has-symbols'); var hasSymbols = require('has-symbols');
var mockProperty = require('mock-property');
var emptyTestCases = require('./empty-keys-cases').emptyTestCases;
var hasBigInt = typeof BigInt === 'function'; var hasBigInt = typeof BigInt === 'function';
test('stringify()', function (t) { test('stringify()', function (t) {
@@ -63,6 +65,138 @@ test('stringify()', function (t) {
st.end(); st.end();
}); });
t.test('encodes dot in key of object when encodeDotInKeys and allowDots is provided', function (st) {
st.equal(
qs.stringify(
{ 'name.obj': { first: 'John', last: 'Doe' } },
{ allowDots: false, encodeDotInKeys: false }
),
'name.obj%5Bfirst%5D=John&name.obj%5Blast%5D=Doe',
'with allowDots false and encodeDotInKeys false'
);
st.equal(
qs.stringify(
{ 'name.obj': { first: 'John', last: 'Doe' } },
{ allowDots: true, encodeDotInKeys: false }
),
'name.obj.first=John&name.obj.last=Doe',
'with allowDots true and encodeDotInKeys false'
);
st.equal(
qs.stringify(
{ 'name.obj': { first: 'John', last: 'Doe' } },
{ allowDots: false, encodeDotInKeys: true }
),
'name%252Eobj%5Bfirst%5D=John&name%252Eobj%5Blast%5D=Doe',
'with allowDots false and encodeDotInKeys true'
);
st.equal(
qs.stringify(
{ 'name.obj': { first: 'John', last: 'Doe' } },
{ allowDots: true, encodeDotInKeys: true }
),
'name%252Eobj.first=John&name%252Eobj.last=Doe',
'with allowDots true and encodeDotInKeys true'
);
st.equal(
qs.stringify(
{ 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } },
{ allowDots: false, encodeDotInKeys: false }
),
'name.obj.subobject%5Bfirst.godly.name%5D=John&name.obj.subobject%5Blast%5D=Doe',
'with allowDots false and encodeDotInKeys false'
);
st.equal(
qs.stringify(
{ 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } },
{ allowDots: true, encodeDotInKeys: false }
),
'name.obj.subobject.first.godly.name=John&name.obj.subobject.last=Doe',
'with allowDots false and encodeDotInKeys false'
);
st.equal(
qs.stringify(
{ 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } },
{ allowDots: false, encodeDotInKeys: true }
),
'name%252Eobj%252Esubobject%5Bfirst.godly.name%5D=John&name%252Eobj%252Esubobject%5Blast%5D=Doe',
'with allowDots false and encodeDotInKeys true'
);
st.equal(
qs.stringify(
{ 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } },
{ allowDots: true, encodeDotInKeys: true }
),
'name%252Eobj%252Esubobject.first%252Egodly%252Ename=John&name%252Eobj%252Esubobject.last=Doe',
'with allowDots true and encodeDotInKeys true'
);
st.end();
});
t.test('should encode dot in key of object, and automatically set allowDots to `true` when encodeDotInKeys is true and allowDots in undefined', function (st) {
st.equal(
qs.stringify(
{ 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } },
{ encodeDotInKeys: true }
),
'name%252Eobj%252Esubobject.first%252Egodly%252Ename=John&name%252Eobj%252Esubobject.last=Doe',
'with allowDots undefined and encodeDotInKeys true'
);
st.end();
});
t.test('should encode dot in key of object when encodeDotInKeys and allowDots is provided, and nothing else when encodeValuesOnly is provided', function (st) {
st.equal(
qs.stringify({ 'name.obj': { first: 'John', last: 'Doe' } }, {
encodeDotInKeys: true, allowDots: true, encodeValuesOnly: true
}),
'name%2Eobj.first=John&name%2Eobj.last=Doe'
);
st.equal(
qs.stringify({ 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } }, { allowDots: true, encodeDotInKeys: true, encodeValuesOnly: true }),
'name%2Eobj%2Esubobject.first%2Egodly%2Ename=John&name%2Eobj%2Esubobject.last=Doe'
);
st.end();
});
t.test('throws when `commaRoundTrip` is not a boolean', function (st) {
st['throws'](
function () { qs.stringify({}, { commaRoundTrip: 'not a boolean' }); },
TypeError,
'throws when `commaRoundTrip` is not a boolean'
);
st.end();
});
t.test('throws when `encodeDotInKeys` is not a boolean', function (st) {
st['throws'](
function () { qs.stringify({ a: [], b: 'zz' }, { encodeDotInKeys: 'foobar' }); },
TypeError
);
st['throws'](
function () { qs.stringify({ a: [], b: 'zz' }, { encodeDotInKeys: 0 }); },
TypeError
);
st['throws'](
function () { qs.stringify({ a: [], b: 'zz' }, { encodeDotInKeys: NaN }); },
TypeError
);
st['throws'](
function () { qs.stringify({ a: [], b: 'zz' }, { encodeDotInKeys: null }); },
TypeError
);
st.end();
});
t.test('adds query prefix', function (st) { t.test('adds query prefix', function (st) {
st.equal(qs.stringify({ a: 'b' }, { addQueryPrefix: true }), '?a=b'); st.equal(qs.stringify({ a: 'b' }, { addQueryPrefix: true }), '?a=b');
st.end(); st.end();
@@ -86,7 +220,7 @@ test('stringify()', function (t) {
st.end(); st.end();
}); });
t.test('stringifies a nested object with dots notation', function (st) { t.test('`allowDots` option: stringifies a nested object with dots notation', function (st) {
st.equal(qs.stringify({ a: { b: 'c' } }, { allowDots: true }), 'a.b=c'); st.equal(qs.stringify({ a: { b: 'c' } }, { allowDots: true }), 'a.b=c');
st.equal(qs.stringify({ a: { b: { c: { d: 'e' } } } }, { allowDots: true }), 'a.b.c.d=e'); st.equal(qs.stringify({ a: { b: { c: { d: 'e' } } } }, { allowDots: true }), 'a.b.c.d=e');
st.end(); st.end();
@@ -108,6 +242,11 @@ test('stringify()', function (t) {
'a=b%2Cc%2Cd', 'a=b%2Cc%2Cd',
'comma => comma' 'comma => comma'
); );
st.equal(
qs.stringify({ a: ['b', 'c', 'd'] }, { arrayFormat: 'comma', commaRoundTrip: true }),
'a=b%2Cc%2Cd',
'comma round trip => comma'
);
st.equal( st.equal(
qs.stringify({ a: ['b', 'c', 'd'] }), qs.stringify({ a: ['b', 'c', 'd'] }),
'a%5B0%5D=b&a%5B1%5D=c&a%5B2%5D=d', 'a%5B0%5D=b&a%5B1%5D=c&a%5B2%5D=d',
@@ -116,18 +255,75 @@ test('stringify()', function (t) {
st.end(); st.end();
}); });
t.test('omits nulls when asked', function (st) { t.test('`skipNulls` option', function (st) {
st.equal(qs.stringify({ a: 'b', c: null }, { skipNulls: true }), 'a=b'); st.equal(
st.end(); qs.stringify({ a: 'b', c: null }, { skipNulls: true }),
}); 'a=b',
'omits nulls when asked'
);
st.equal(
qs.stringify({ a: { b: 'c', d: null } }, { skipNulls: true }),
'a%5Bb%5D=c',
'omits nested nulls when asked'
);
t.test('omits nested nulls when asked', function (st) {
st.equal(qs.stringify({ a: { b: 'c', d: null } }, { skipNulls: true }), 'a%5Bb%5D=c');
st.end(); st.end();
}); });
t.test('omits array indices when asked', function (st) { t.test('omits array indices when asked', function (st) {
st.equal(qs.stringify({ a: ['b', 'c', 'd'] }, { indices: false }), 'a=b&a=c&a=d'); st.equal(qs.stringify({ a: ['b', 'c', 'd'] }, { indices: false }), 'a=b&a=c&a=d');
st.end();
});
t.test('omits object key/value pair when value is empty array', function (st) {
st.equal(qs.stringify({ a: [], b: 'zz' }), 'b=zz');
st.end();
});
t.test('should not omit object key/value pair when value is empty array and when asked', function (st) {
st.equal(qs.stringify({ a: [], b: 'zz' }), 'b=zz');
st.equal(qs.stringify({ a: [], b: 'zz' }, { allowEmptyArrays: false }), 'b=zz');
st.equal(qs.stringify({ a: [], b: 'zz' }, { allowEmptyArrays: true }), 'a[]&b=zz');
st.end();
});
t.test('should throw when allowEmptyArrays is not of type boolean', function (st) {
st['throws'](
function () { qs.stringify({ a: [], b: 'zz' }, { allowEmptyArrays: 'foobar' }); },
TypeError
);
st['throws'](
function () { qs.stringify({ a: [], b: 'zz' }, { allowEmptyArrays: 0 }); },
TypeError
);
st['throws'](
function () { qs.stringify({ a: [], b: 'zz' }, { allowEmptyArrays: NaN }); },
TypeError
);
st['throws'](
function () { qs.stringify({ a: [], b: 'zz' }, { allowEmptyArrays: null }); },
TypeError
);
st.end();
});
t.test('allowEmptyArrays + strictNullHandling', function (st) {
st.equal(
qs.stringify(
{ testEmptyArray: [] },
{ strictNullHandling: true, allowEmptyArrays: true }
),
'testEmptyArray[]'
);
st.end(); st.end();
}); });
@@ -155,11 +351,22 @@ test('stringify()', function (t) {
s2t.equal(qs.stringify({ a: ['c', 'd'] }, { encodeValuesOnly: true, arrayFormat: 'indices' }), 'a[0]=c&a[1]=d'); s2t.equal(qs.stringify({ a: ['c', 'd'] }, { encodeValuesOnly: true, arrayFormat: 'indices' }), 'a[0]=c&a[1]=d');
s2t.equal(qs.stringify({ a: ['c', 'd'] }, { encodeValuesOnly: true, arrayFormat: 'brackets' }), 'a[]=c&a[]=d'); s2t.equal(qs.stringify({ a: ['c', 'd'] }, { encodeValuesOnly: true, arrayFormat: 'brackets' }), 'a[]=c&a[]=d');
s2t.equal(qs.stringify({ a: ['c', 'd'] }, { encodeValuesOnly: true, arrayFormat: 'comma' }), 'a=c,d'); s2t.equal(qs.stringify({ a: ['c', 'd'] }, { encodeValuesOnly: true, arrayFormat: 'comma' }), 'a=c,d');
s2t.equal(qs.stringify({ a: ['c', 'd'] }, { encodeValuesOnly: true, arrayFormat: 'comma', commaRoundTrip: true }), 'a=c,d');
s2t.equal(qs.stringify({ a: ['c', 'd'] }, { encodeValuesOnly: true }), 'a[0]=c&a[1]=d'); s2t.equal(qs.stringify({ a: ['c', 'd'] }, { encodeValuesOnly: true }), 'a[0]=c&a[1]=d');
s2t.end(); s2t.end();
}); });
st.test('array with multiple items with a comma inside', function (s2t) {
s2t.equal(qs.stringify({ a: ['c,d', 'e'] }, { encodeValuesOnly: true, arrayFormat: 'comma' }), 'a=c%2Cd,e');
s2t.equal(qs.stringify({ a: ['c,d', 'e'] }, { arrayFormat: 'comma' }), 'a=c%2Cd%2Ce');
s2t.equal(qs.stringify({ a: ['c,d', 'e'] }, { encodeValuesOnly: true, arrayFormat: 'comma', commaRoundTrip: true }), 'a=c%2Cd,e');
s2t.equal(qs.stringify({ a: ['c,d', 'e'] }, { arrayFormat: 'comma', commaRoundTrip: true }), 'a=c%2Cd%2Ce');
s2t.end();
});
st.end(); st.end();
}); });
@@ -171,6 +378,44 @@ test('stringify()', function (t) {
st.end(); st.end();
}); });
t.test('stringifies comma and empty array values', function (st) {
st.equal(qs.stringify({ a: [',', '', 'c,d%'] }, { encode: false, arrayFormat: 'indices' }), 'a[0]=,&a[1]=&a[2]=c,d%');
st.equal(qs.stringify({ a: [',', '', 'c,d%'] }, { encode: false, arrayFormat: 'brackets' }), 'a[]=,&a[]=&a[]=c,d%');
st.equal(qs.stringify({ a: [',', '', 'c,d%'] }, { encode: false, arrayFormat: 'comma' }), 'a=,,,c,d%');
st.equal(qs.stringify({ a: [',', '', 'c,d%'] }, { encode: false, arrayFormat: 'repeat' }), 'a=,&a=&a=c,d%');
st.equal(qs.stringify({ a: [',', '', 'c,d%'] }, { encode: true, encodeValuesOnly: true, arrayFormat: 'indices' }), 'a[0]=%2C&a[1]=&a[2]=c%2Cd%25');
st.equal(qs.stringify({ a: [',', '', 'c,d%'] }, { encode: true, encodeValuesOnly: true, arrayFormat: 'brackets' }), 'a[]=%2C&a[]=&a[]=c%2Cd%25');
st.equal(qs.stringify({ a: [',', '', 'c,d%'] }, { encode: true, encodeValuesOnly: true, arrayFormat: 'comma' }), 'a=%2C,,c%2Cd%25');
st.equal(qs.stringify({ a: [',', '', 'c,d%'] }, { encode: true, encodeValuesOnly: true, arrayFormat: 'repeat' }), 'a=%2C&a=&a=c%2Cd%25');
st.equal(qs.stringify({ a: [',', '', 'c,d%'] }, { encode: true, encodeValuesOnly: false, arrayFormat: 'indices' }), 'a%5B0%5D=%2C&a%5B1%5D=&a%5B2%5D=c%2Cd%25');
st.equal(qs.stringify({ a: [',', '', 'c,d%'] }, { encode: true, encodeValuesOnly: false, arrayFormat: 'brackets' }), 'a%5B%5D=%2C&a%5B%5D=&a%5B%5D=c%2Cd%25');
st.equal(qs.stringify({ a: [',', '', 'c,d%'] }, { encode: true, encodeValuesOnly: false, arrayFormat: 'comma' }), 'a=%2C%2C%2Cc%2Cd%25');
st.equal(qs.stringify({ a: [',', '', 'c,d%'] }, { encode: true, encodeValuesOnly: false, arrayFormat: 'repeat' }), 'a=%2C&a=&a=c%2Cd%25');
st.end();
});
t.test('stringifies comma and empty non-array values', function (st) {
st.equal(qs.stringify({ a: ',', b: '', c: 'c,d%' }, { encode: false, arrayFormat: 'indices' }), 'a=,&b=&c=c,d%');
st.equal(qs.stringify({ a: ',', b: '', c: 'c,d%' }, { encode: false, arrayFormat: 'brackets' }), 'a=,&b=&c=c,d%');
st.equal(qs.stringify({ a: ',', b: '', c: 'c,d%' }, { encode: false, arrayFormat: 'comma' }), 'a=,&b=&c=c,d%');
st.equal(qs.stringify({ a: ',', b: '', c: 'c,d%' }, { encode: false, arrayFormat: 'repeat' }), 'a=,&b=&c=c,d%');
st.equal(qs.stringify({ a: ',', b: '', c: 'c,d%' }, { encode: true, encodeValuesOnly: true, arrayFormat: 'indices' }), 'a=%2C&b=&c=c%2Cd%25');
st.equal(qs.stringify({ a: ',', b: '', c: 'c,d%' }, { encode: true, encodeValuesOnly: true, arrayFormat: 'brackets' }), 'a=%2C&b=&c=c%2Cd%25');
st.equal(qs.stringify({ a: ',', b: '', c: 'c,d%' }, { encode: true, encodeValuesOnly: true, arrayFormat: 'comma' }), 'a=%2C&b=&c=c%2Cd%25');
st.equal(qs.stringify({ a: ',', b: '', c: 'c,d%' }, { encode: true, encodeValuesOnly: true, arrayFormat: 'repeat' }), 'a=%2C&b=&c=c%2Cd%25');
st.equal(qs.stringify({ a: ',', b: '', c: 'c,d%' }, { encode: true, encodeValuesOnly: false, arrayFormat: 'indices' }), 'a=%2C&b=&c=c%2Cd%25');
st.equal(qs.stringify({ a: ',', b: '', c: 'c,d%' }, { encode: true, encodeValuesOnly: false, arrayFormat: 'brackets' }), 'a=%2C&b=&c=c%2Cd%25');
st.equal(qs.stringify({ a: ',', b: '', c: 'c,d%' }, { encode: true, encodeValuesOnly: false, arrayFormat: 'comma' }), 'a=%2C&b=&c=c%2Cd%25');
st.equal(qs.stringify({ a: ',', b: '', c: 'c,d%' }, { encode: true, encodeValuesOnly: false, arrayFormat: 'repeat' }), 'a=%2C&b=&c=c%2Cd%25');
st.end();
});
t.test('stringifies a nested array value with dots notation', function (st) { t.test('stringifies a nested array value with dots notation', function (st) {
st.equal( st.equal(
qs.stringify( qs.stringify(
@@ -209,36 +454,44 @@ test('stringify()', function (t) {
t.test('stringifies an object inside an array', function (st) { t.test('stringifies an object inside an array', function (st) {
st.equal( st.equal(
qs.stringify({ a: [{ b: 'c' }] }, { arrayFormat: 'indices' }), qs.stringify({ a: [{ b: 'c' }] }, { arrayFormat: 'indices', encodeValuesOnly: true }),
'a%5B0%5D%5Bb%5D=c', // a[0][b]=c 'a[0][b]=c',
'indices => brackets' 'indices => indices'
); );
st.equal( st.equal(
qs.stringify({ a: [{ b: 'c' }] }, { arrayFormat: 'brackets' }), qs.stringify({ a: [{ b: 'c' }] }, { arrayFormat: 'repeat', encodeValuesOnly: true }),
'a%5B%5D%5Bb%5D=c', // a[][b]=c 'a[b]=c',
'repeat => repeat'
);
st.equal(
qs.stringify({ a: [{ b: 'c' }] }, { arrayFormat: 'brackets', encodeValuesOnly: true }),
'a[][b]=c',
'brackets => brackets' 'brackets => brackets'
); );
st.equal( st.equal(
qs.stringify({ a: [{ b: 'c' }] }), qs.stringify({ a: [{ b: 'c' }] }, { encodeValuesOnly: true }),
'a%5B0%5D%5Bb%5D=c', 'a[0][b]=c',
'default => indices' 'default => indices'
); );
st.equal( st.equal(
qs.stringify({ a: [{ b: { c: [1] } }] }, { arrayFormat: 'indices' }), qs.stringify({ a: [{ b: { c: [1] } }] }, { arrayFormat: 'indices', encodeValuesOnly: true }),
'a%5B0%5D%5Bb%5D%5Bc%5D%5B0%5D=1', 'a[0][b][c][0]=1',
'indices => indices' 'indices => indices'
); );
st.equal( st.equal(
qs.stringify({ a: [{ b: { c: [1] } }] }, { arrayFormat: 'brackets' }), qs.stringify({ a: [{ b: { c: [1] } }] }, { arrayFormat: 'repeat', encodeValuesOnly: true }),
'a%5B%5D%5Bb%5D%5Bc%5D%5B%5D=1', 'a[b][c]=1',
'repeat => repeat'
);
st.equal(
qs.stringify({ a: [{ b: { c: [1] } }] }, { arrayFormat: 'brackets', encodeValuesOnly: true }),
'a[][b][c][]=1',
'brackets => brackets' 'brackets => brackets'
); );
st.equal( st.equal(
qs.stringify({ a: [{ b: { c: [1] } }] }), qs.stringify({ a: [{ b: { c: [1] } }] }, { encodeValuesOnly: true }),
'a%5B0%5D%5Bb%5D%5Bc%5D%5B0%5D=1', 'a[0][b][c][0]=1',
'default => indices' 'default => indices'
); );
@@ -340,17 +593,17 @@ test('stringify()', function (t) {
st.end(); st.end();
}); });
t.test('uses indices notation for arrays when no arrayFormat=indices', function (st) { t.test('uses indices notation for arrays when arrayFormat=indices', function (st) {
st.equal(qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'indices' }), 'a%5B0%5D=b&a%5B1%5D=c'); st.equal(qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'indices' }), 'a%5B0%5D=b&a%5B1%5D=c');
st.end(); st.end();
}); });
t.test('uses repeat notation for arrays when no arrayFormat=repeat', function (st) { t.test('uses repeat notation for arrays when arrayFormat=repeat', function (st) {
st.equal(qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'repeat' }), 'a=b&a=c'); st.equal(qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'repeat' }), 'a=b&a=c');
st.end(); st.end();
}); });
t.test('uses brackets notation for arrays when no arrayFormat=brackets', function (st) { t.test('uses brackets notation for arrays when arrayFormat=brackets', function (st) {
st.equal(qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'brackets' }), 'a%5B%5D=b&a%5B%5D=c'); st.equal(qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'brackets' }), 'a%5B%5D=b&a%5B%5D=c');
st.end(); st.end();
}); });
@@ -447,10 +700,11 @@ test('stringify()', function (t) {
}); });
t.test('skips properties that are part of the object prototype', function (st) { t.test('skips properties that are part of the object prototype', function (st) {
Object.prototype.crash = 'test'; st.intercept(Object.prototype, 'crash', { value: 'test' });
st.equal(qs.stringify({ a: 'b' }), 'a=b'); st.equal(qs.stringify({ a: 'b' }), 'a=b');
st.equal(qs.stringify({ a: { b: 'c' } }), 'a%5Bb%5D=c'); st.equal(qs.stringify({ a: { b: 'c' } }), 'a%5Bb%5D=c');
delete Object.prototype.crash;
st.end(); st.end();
}); });
@@ -474,10 +728,12 @@ test('stringify()', function (t) {
}); });
t.test('does not blow up when Buffer global is missing', function (st) { t.test('does not blow up when Buffer global is missing', function (st) {
var tempBuffer = global.Buffer; var restore = mockProperty(global, 'Buffer', { 'delete': true });
delete global.Buffer;
var result = qs.stringify({ a: 'b', c: 'd' }); var result = qs.stringify({ a: 'b', c: 'd' });
global.Buffer = tempBuffer;
restore();
st.equal(result, 'a=b&c=d'); st.equal(result, 'a=b&c=d');
st.end(); st.end();
}); });
@@ -526,9 +782,17 @@ test('stringify()', function (t) {
}; };
st.equal( st.equal(
qs.stringify({ filters: { $and: [p1, p2] } }, { encodeValuesOnly: true }), qs.stringify({ filters: { $and: [p1, p2] } }, { encodeValuesOnly: true, arrayFormat: 'indices' }),
'filters[$and][0][function]=gte&filters[$and][0][arguments][0][function]=hour_of_day&filters[$and][0][arguments][1]=0&filters[$and][1][function]=lte&filters[$and][1][arguments][0][function]=hour_of_day&filters[$and][1][arguments][1]=23' 'filters[$and][0][function]=gte&filters[$and][0][arguments][0][function]=hour_of_day&filters[$and][0][arguments][1]=0&filters[$and][1][function]=lte&filters[$and][1][arguments][0][function]=hour_of_day&filters[$and][1][arguments][1]=23'
); );
st.equal(
qs.stringify({ filters: { $and: [p1, p2] } }, { encodeValuesOnly: true, arrayFormat: 'brackets' }),
'filters[$and][][function]=gte&filters[$and][][arguments][][function]=hour_of_day&filters[$and][][arguments][]=0&filters[$and][][function]=lte&filters[$and][][arguments][][function]=hour_of_day&filters[$and][][arguments][]=23'
);
st.equal(
qs.stringify({ filters: { $and: [p1, p2] } }, { encodeValuesOnly: true, arrayFormat: 'repeat' }),
'filters[$and][function]=gte&filters[$and][arguments][function]=hour_of_day&filters[$and][arguments]=0&filters[$and][function]=lte&filters[$and][arguments][function]=hour_of_day&filters[$and][arguments]=23'
);
st.end(); st.end();
}); });
@@ -641,13 +905,28 @@ test('stringify()', function (t) {
st.end(); st.end();
}); });
t.test('receives the default encoder as a second argument', function (st) {
st.plan(8);
qs.stringify({ a: 1, b: new Date(), c: true, d: [1] }, {
encoder: function (str) {
st.match(typeof str, /^(?:string|number|boolean)$/);
return '';
}
});
st.end();
});
t.test('receives the default encoder as a second argument', function (st) { t.test('receives the default encoder as a second argument', function (st) {
st.plan(2); st.plan(2);
qs.stringify({ a: 1 }, { qs.stringify({ a: 1 }, {
encoder: function (str, defaultEncoder) { encoder: function (str, defaultEncoder) {
st.equal(defaultEncoder, utils.encode); st.equal(defaultEncoder, utils.encode);
} }
}); });
st.end(); st.end();
}); });
@@ -775,16 +1054,53 @@ test('stringify()', function (t) {
st.equal( st.equal(
qs.stringify( qs.stringify(
{ a: 'b', c: ['d', 'e=f'], f: [['g'], ['h']] }, { a: 'b', c: ['d', 'e=f'], f: [['g'], ['h']] },
{ encodeValuesOnly: true } { encodeValuesOnly: true, arrayFormat: 'indices' }
), ),
'a=b&c[0]=d&c[1]=e%3Df&f[0][0]=g&f[1][0]=h' 'a=b&c[0]=d&c[1]=e%3Df&f[0][0]=g&f[1][0]=h',
'encodeValuesOnly + indices'
); );
st.equal( st.equal(
qs.stringify( qs.stringify(
{ a: 'b', c: ['d', 'e'], f: [['g'], ['h']] } { a: 'b', c: ['d', 'e=f'], f: [['g'], ['h']] },
{ encodeValuesOnly: true, arrayFormat: 'brackets' }
), ),
'a=b&c%5B0%5D=d&c%5B1%5D=e&f%5B0%5D%5B0%5D=g&f%5B1%5D%5B0%5D=h' 'a=b&c[]=d&c[]=e%3Df&f[][]=g&f[][]=h',
'encodeValuesOnly + brackets'
); );
st.equal(
qs.stringify(
{ a: 'b', c: ['d', 'e=f'], f: [['g'], ['h']] },
{ encodeValuesOnly: true, arrayFormat: 'repeat' }
),
'a=b&c=d&c=e%3Df&f=g&f=h',
'encodeValuesOnly + repeat'
);
st.equal(
qs.stringify(
{ a: 'b', c: ['d', 'e'], f: [['g'], ['h']] },
{ arrayFormat: 'indices' }
),
'a=b&c%5B0%5D=d&c%5B1%5D=e&f%5B0%5D%5B0%5D=g&f%5B1%5D%5B0%5D=h',
'no encodeValuesOnly + indices'
);
st.equal(
qs.stringify(
{ a: 'b', c: ['d', 'e'], f: [['g'], ['h']] },
{ arrayFormat: 'brackets' }
),
'a=b&c%5B%5D=d&c%5B%5D=e&f%5B%5D%5B%5D=g&f%5B%5D%5B%5D=h',
'no encodeValuesOnly + brackets'
);
st.equal(
qs.stringify(
{ a: 'b', c: ['d', 'e'], f: [['g'], ['h']] },
{ arrayFormat: 'repeat' }
),
'a=b&c=d&c=e&f=g&f=h',
'no encodeValuesOnly + repeat'
);
st.end(); st.end();
}); });
@@ -821,13 +1137,19 @@ test('stringify()', function (t) {
st.end(); st.end();
}); });
t.test('adds the right sentinel when instructed to and the charset is utf-8', function (st) { t.test('`charsetSentinel` option', function (st) {
st.equal(qs.stringify({ a: 'æ' }, { charsetSentinel: true, charset: 'utf-8' }), 'utf8=%E2%9C%93&a=%C3%A6'); st.equal(
st.end(); qs.stringify({ a: 'æ' }, { charsetSentinel: true, charset: 'utf-8' }),
}); 'utf8=%E2%9C%93&a=%C3%A6',
'adds the right sentinel when instructed to and the charset is utf-8'
);
st.equal(
qs.stringify({ a: 'æ' }, { charsetSentinel: true, charset: 'iso-8859-1' }),
'utf8=%26%2310003%3B&a=%E6',
'adds the right sentinel when instructed to and the charset is iso-8859-1'
);
t.test('adds the right sentinel when instructed to and the charset is iso-8859-1', function (st) {
st.equal(qs.stringify({ a: 'æ' }, { charsetSentinel: true, charset: 'iso-8859-1' }), 'utf8=%26%2310003%3B&a=%E6');
st.end(); st.end();
}); });
@@ -878,13 +1200,15 @@ test('stringify()', function (t) {
var withArray = { a: { b: [{ c: 'd', e: 'f' }] } }; var withArray = { a: { b: [{ c: 'd', e: 'f' }] } };
st.equal(qs.stringify(obj, { encode: false }), 'a[b][c]=d&a[b][e]=f', 'no array, no arrayFormat'); st.equal(qs.stringify(obj, { encode: false }), 'a[b][c]=d&a[b][e]=f', 'no array, no arrayFormat');
st.equal(qs.stringify(obj, { encode: false, arrayFormat: 'bracket' }), 'a[b][c]=d&a[b][e]=f', 'no array, bracket'); st.equal(qs.stringify(obj, { encode: false, arrayFormat: 'brackets' }), 'a[b][c]=d&a[b][e]=f', 'no array, bracket');
st.equal(qs.stringify(obj, { encode: false, arrayFormat: 'indices' }), 'a[b][c]=d&a[b][e]=f', 'no array, indices'); st.equal(qs.stringify(obj, { encode: false, arrayFormat: 'indices' }), 'a[b][c]=d&a[b][e]=f', 'no array, indices');
st.equal(qs.stringify(obj, { encode: false, arrayFormat: 'repeat' }), 'a[b][c]=d&a[b][e]=f', 'no array, repeat');
st.equal(qs.stringify(obj, { encode: false, arrayFormat: 'comma' }), 'a[b][c]=d&a[b][e]=f', 'no array, comma'); st.equal(qs.stringify(obj, { encode: false, arrayFormat: 'comma' }), 'a[b][c]=d&a[b][e]=f', 'no array, comma');
st.equal(qs.stringify(withArray, { encode: false }), 'a[b][0][c]=d&a[b][0][e]=f', 'array, no arrayFormat'); st.equal(qs.stringify(withArray, { encode: false }), 'a[b][0][c]=d&a[b][0][e]=f', 'array, no arrayFormat');
st.equal(qs.stringify(withArray, { encode: false, arrayFormat: 'bracket' }), 'a[b][0][c]=d&a[b][0][e]=f', 'array, bracket'); st.equal(qs.stringify(withArray, { encode: false, arrayFormat: 'brackets' }), 'a[b][][c]=d&a[b][][e]=f', 'array, bracket');
st.equal(qs.stringify(withArray, { encode: false, arrayFormat: 'indices' }), 'a[b][0][c]=d&a[b][0][e]=f', 'array, indices'); st.equal(qs.stringify(withArray, { encode: false, arrayFormat: 'indices' }), 'a[b][0][c]=d&a[b][0][e]=f', 'array, indices');
st.equal(qs.stringify(withArray, { encode: false, arrayFormat: 'repeat' }), 'a[b][c]=d&a[b][e]=f', 'array, repeat');
st.equal( st.equal(
qs.stringify(withArray, { encode: false, arrayFormat: 'comma' }), qs.stringify(withArray, { encode: false, arrayFormat: 'comma' }),
'???', '???',
@@ -897,13 +1221,78 @@ test('stringify()', function (t) {
t.test('stringifies sparse arrays', function (st) { t.test('stringifies sparse arrays', function (st) {
/* eslint no-sparse-arrays: 0 */ /* eslint no-sparse-arrays: 0 */
st.equal(qs.stringify({ a: [, '2', , , '1'] }, { encodeValuesOnly: true }), 'a[1]=2&a[4]=1'); st.equal(qs.stringify({ a: [, '2', , , '1'] }, { encodeValuesOnly: true, arrayFormat: 'indices' }), 'a[1]=2&a[4]=1');
st.equal(qs.stringify({ a: [, { b: [, , { c: '1' }] }] }, { encodeValuesOnly: true }), 'a[1][b][2][c]=1'); st.equal(qs.stringify({ a: [, '2', , , '1'] }, { encodeValuesOnly: true, arrayFormat: 'brackets' }), 'a[]=2&a[]=1');
st.equal(qs.stringify({ a: [, [, , [, , , { c: '1' }]]] }, { encodeValuesOnly: true }), 'a[1][2][3][c]=1'); st.equal(qs.stringify({ a: [, '2', , , '1'] }, { encodeValuesOnly: true, arrayFormat: 'repeat' }), 'a=2&a=1');
st.equal(qs.stringify({ a: [, [, , [, , , { c: [, '1'] }]]] }, { encodeValuesOnly: true }), 'a[1][2][3][c][1]=1');
st.equal(qs.stringify({ a: [, { b: [, , { c: '1' }] }] }, { encodeValuesOnly: true, arrayFormat: 'indices' }), 'a[1][b][2][c]=1');
st.equal(qs.stringify({ a: [, { b: [, , { c: '1' }] }] }, { encodeValuesOnly: true, arrayFormat: 'brackets' }), 'a[][b][][c]=1');
st.equal(qs.stringify({ a: [, { b: [, , { c: '1' }] }] }, { encodeValuesOnly: true, arrayFormat: 'repeat' }), 'a[b][c]=1');
st.equal(qs.stringify({ a: [, [, , [, , , { c: '1' }]]] }, { encodeValuesOnly: true, arrayFormat: 'indices' }), 'a[1][2][3][c]=1');
st.equal(qs.stringify({ a: [, [, , [, , , { c: '1' }]]] }, { encodeValuesOnly: true, arrayFormat: 'brackets' }), 'a[][][][c]=1');
st.equal(qs.stringify({ a: [, [, , [, , , { c: '1' }]]] }, { encodeValuesOnly: true, arrayFormat: 'repeat' }), 'a[c]=1');
st.equal(qs.stringify({ a: [, [, , [, , , { c: [, '1'] }]]] }, { encodeValuesOnly: true, arrayFormat: 'indices' }), 'a[1][2][3][c][1]=1');
st.equal(qs.stringify({ a: [, [, , [, , , { c: [, '1'] }]]] }, { encodeValuesOnly: true, arrayFormat: 'brackets' }), 'a[][][][c][]=1');
st.equal(qs.stringify({ a: [, [, , [, , , { c: [, '1'] }]]] }, { encodeValuesOnly: true, arrayFormat: 'repeat' }), 'a[c]=1');
st.end();
});
t.test('encodes a very long string', function (st) {
var chars = [];
var expected = [];
for (var i = 0; i < 5e3; i++) {
chars.push(' ' + i);
expected.push('%20' + i);
}
var obj = {
foo: chars.join('')
};
st.equal(
qs.stringify(obj, { arrayFormat: 'bracket', charset: 'utf-8' }),
'foo=' + expected.join('')
);
st.end(); st.end();
}); });
t.end(); t.end();
}); });
test('stringifies empty keys', function (t) {
emptyTestCases.forEach(function (testCase) {
t.test('stringifies an object with empty string key with ' + testCase.input, function (st) {
st.deepEqual(
qs.stringify(testCase.withEmptyKeys, { encode: false, arrayFormat: 'indices' }),
testCase.stringifyOutput.indices,
'test case: ' + testCase.input + ', indices'
);
st.deepEqual(
qs.stringify(testCase.withEmptyKeys, { encode: false, arrayFormat: 'brackets' }),
testCase.stringifyOutput.brackets,
'test case: ' + testCase.input + ', brackets'
);
st.deepEqual(
qs.stringify(testCase.withEmptyKeys, { encode: false, arrayFormat: 'repeat' }),
testCase.stringifyOutput.repeat,
'test case: ' + testCase.input + ', repeat'
);
st.end();
});
});
t.test('edge case with object/arrays', function (st) {
st.deepEqual(qs.stringify({ '': { '': [2, 3] } }, { encode: false }), '[][0]=2&[][1]=3');
st.deepEqual(qs.stringify({ '': { '': [2, 3], a: 2 } }, { encode: false }), '[][0]=2&[][1]=3&[a]=2');
st.deepEqual(qs.stringify({ '': { '': [2, 3] } }, { encode: false, arrayFormat: 'indices' }), '[][0]=2&[][1]=3');
st.deepEqual(qs.stringify({ '': { '': [2, 3], a: 2 } }, { encode: false, arrayFormat: 'indices' }), '[][0]=2&[][1]=3&[a]=2');
st.end();
});
});

5
node_modules/send/HISTORY.md generated vendored
View File

@@ -1,3 +1,8 @@
0.19.0 / 2024-09-10
===================
* Remove link renderization in html while redirecting
0.18.0 / 2022-03-23 0.18.0 / 2022-03-23
=================== ===================

3
node_modules/send/index.js generated vendored
View File

@@ -482,8 +482,7 @@ SendStream.prototype.redirect = function redirect (path) {
} }
var loc = encodeUrl(collapseLeadingSlashes(this.path + '/')) var loc = encodeUrl(collapseLeadingSlashes(this.path + '/'))
var doc = createHtmlDocument('Redirecting', 'Redirecting to <a href="' + escapeHtml(loc) + '">' + var doc = createHtmlDocument('Redirecting', 'Redirecting to ' + escapeHtml(loc))
escapeHtml(loc) + '</a>')
// redirect // redirect
res.statusCode = 301 res.statusCode = 301

2
node_modules/send/package.json generated vendored
View File

@@ -1,7 +1,7 @@
{ {
"name": "send", "name": "send",
"description": "Better streaming static file server with Range and conditional-GET support", "description": "Better streaming static file server with Range and conditional-GET support",
"version": "0.18.0", "version": "0.19.0",
"author": "TJ Holowaychuk <tj@vision-media.ca>", "author": "TJ Holowaychuk <tj@vision-media.ca>",
"contributors": [ "contributors": [
"Douglas Christopher Wilson <doug@somethingdoug.com>", "Douglas Christopher Wilson <doug@somethingdoug.com>",

16
node_modules/serve-static/HISTORY.md generated vendored
View File

@@ -1,3 +1,19 @@
1.16.2 / 2024-09-11
===================
* deps: encodeurl@~2.0.0
1.16.1 / 2024-09-11
===================
* deps: send@0.19.0
1.16.0 / 2024-09-10
===================
* Remove link renderization in html while redirecting
1.15.0 / 2022-03-24 1.15.0 / 2022-03-24
=================== ===================

3
node_modules/serve-static/index.js generated vendored
View File

@@ -195,8 +195,7 @@ function createRedirectDirectoryListener () {
// reformat the URL // reformat the URL
var loc = encodeUrl(url.format(originalUrl)) var loc = encodeUrl(url.format(originalUrl))
var doc = createHtmlDocument('Redirecting', 'Redirecting to <a href="' + escapeHtml(loc) + '">' + var doc = createHtmlDocument('Redirecting', 'Redirecting to ' + escapeHtml(loc))
escapeHtml(loc) + '</a>')
// send redirect response // send redirect response
res.statusCode = 301 res.statusCode = 301

View File

@@ -1,15 +1,15 @@
{ {
"name": "serve-static", "name": "serve-static",
"description": "Serve static files", "description": "Serve static files",
"version": "1.15.0", "version": "1.16.2",
"author": "Douglas Christopher Wilson <doug@somethingdoug.com>", "author": "Douglas Christopher Wilson <doug@somethingdoug.com>",
"license": "MIT", "license": "MIT",
"repository": "expressjs/serve-static", "repository": "expressjs/serve-static",
"dependencies": { "dependencies": {
"encodeurl": "~1.0.2", "encodeurl": "~2.0.0",
"escape-html": "~1.0.3", "escape-html": "~1.0.3",
"parseurl": "~1.3.3", "parseurl": "~1.3.3",
"send": "0.18.0" "send": "0.19.0"
}, },
"devDependencies": { "devDependencies": {
"eslint": "7.32.0", "eslint": "7.32.0",

1577
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,20 +1,23 @@
{ {
"name": "app_sigma", "name": "app_sigma",
"version": "1.0.0", "version": "1.0.0",
"description": "", "description": "APLICACION SIGMA",
"main": "src/app.js", "main": "src/app.js",
"scripts": { "scripts": {
"dev": "nodemon src/app.js", "dev": "nodemon src/app.js",
"start": "node src/app.js" "start": "node src/app.js",
"build-linux": "pkg . --targets node18-linux-x64 --output /home/pablinux/NetBeansProjects/facturacion/public/app_sigma",
"build-win": "pkg . --targets node18-win-x64 --output /home/pablinux/NetBeansProjects/facturacion/SIGMA_WINDOWS/COMPLEMENTOS/public/app_sigma.exe",
"build-mac": "pkg . --targets node18-macos-x64 --output /home/pablinux/NetBeansProjects/facturacion/SIGMA_MAC/public/app_sigma"
}, },
"keywords": [], "keywords": [],
"author": "Pablinux", "author": "Pablinux",
"license": "ISC", "license": "ISC",
"devDependencies": { "devDependencies": {
"nodemon": "^3.1.4" "nodemon": "^3.1.4",
"pkg": "^5.8.1"
}, },
"dependencies": { "dependencies": {
"axios": "^1.7.2",
"cors": "^2.8.5", "cors": "^2.8.5",
"ejs": "^3.0.2", "ejs": "^3.0.2",
"express": "^4.18.2", "express": "^4.18.2",
@@ -24,10 +27,24 @@
"jsonwebtoken": "^9.0.2", "jsonwebtoken": "^9.0.2",
"morgan": "^1.10.0", "morgan": "^1.10.0",
"mysql": "^2.18.1", "mysql": "^2.18.1",
"node-fetch": "^2.7.0",
"nodejs-base64": "^2.0.0", "nodejs-base64": "^2.0.0",
"swagger-jsdoc": "^6.2.8", "swagger-jsdoc": "^6.2.8",
"swagger-ui-express": "^5.0.1", "swagger-ui-express": "^5.0.1",
"telegraf": "^3.37.0", "telegraf": "^3.37.0",
"uuid": "^9.0.1" "uuid": "^9.0.1"
},
"bin": "src/app.js",
"pkg": {
"targets": [
"node18-linux-x64",
"node18-macos-x64",
"node18-win-x64"
],
"assets": [
"src/config.js",
"src/views/**/*",
"src/public/**/*"
]
} }
} }

View File

@@ -5,13 +5,12 @@ const config = {
user: 'admin', user: 'admin',
pswd: 'Dx.1706%', pswd: 'Dx.1706%',
db_a: 'TELCOTRONICS', db_a: 'TELCOTRONICS',
//db_a: 'facturacion',
debg: false, debg: false,
sock: '/' sock: '/'
}, },
dir:{ dir:{
root_dir: '/home/pablinux/Projects/Node/APP-SIGMA-WEB/src/public/files/', root_dir: '/home/pablinux/Projects/Node/APP-SIGMA-WEB/src/public/files/',
path_dir: __dirname, path_dir: process.cwd(), // usa el path del ejecutable real
}, },
sesion:{ sesion:{
id:"", id:"",
@@ -22,7 +21,7 @@ const config = {
}, },
sessionStorage:{ sessionStorage:{
secretSession: "Microbot%", secretSession: "Microbot%",
cockie:false,//se envia por https cookie: false // CORREGIDO
}, },
origin:{ origin:{
whiteList : ['https://factura-e.net','https://app.factura-e.net'], whiteList : ['https://factura-e.net','https://app.factura-e.net'],
@@ -34,6 +33,6 @@ const config = {
server:{ server:{
port:3001 port:3001
} }
} }
module.exports = config; module.exports = config;

View File

@@ -1,5 +1,5 @@
const controlador = {}; const controlador = {};
const axios = require('axios').default; //const axios = require('axios').default;
controlador.verClientesJsonApp = (req, res) => { controlador.verClientesJsonApp = (req, res) => {
req.getConnection((err, conn) => { req.getConnection((err, conn) => {
@@ -173,35 +173,59 @@ controlador.buscarCli_sri = (req, res) => {
switch (selc) { switch (selc) {
case 0: case 0:
axios.post(arrayUrl[selc] + "?ruc=" + idCli) fetch(arrayUrl[selc] + "?ruc=" + idCli, {
.then(function (resp_sri) { method: 'POST',
//console.log(resp_sri.data); })
//var consulta = {"resp_consulta":resp_sri}; .then(resp => resp.text()) // Si esperas JSON, usa .json() en su lugar
var json = { nombre: "NOMBRE", empresa: "empresa", direccion: "Santo Domingo" }; .then(data => {
var consulta = { "resp_consulta": json }; // Aquí puedes usar la respuesta real si lo deseas: console.log(data);
const json = { nombre: "NOMBRE", empresa: "empresa", direccion: "Santo Domingo" };
const consulta = { "resp_consulta": json };
res.json(json); res.json(json);
})
.catch(error => {
console.error("Error al hacer fetch:", error);
res.status(500).json({ error: 'Error al consultar servicio remoto' });
}); });
break; break;
case 1: case 1:
axios({ fetch(arrayUrl[selc] + "?ID_CLIENTE=" + idCli, {
method: 'POST', method: 'POST',
url: arrayUrl[selc]+"?ID_CLIENTE="+idCli,
}) })
.then(function (resp_sri) { .then(function (resp_sri) {
console.log(resp_sri.data); return resp_sri.json(); // Parsea la respuesta como JSON
res.json(resp_sri.data); })
.then(function (data) {
console.log(data);
// Asumiendo que 'res' es el objeto de respuesta de Express o similar,
// puedes enviarle los datos directamente.
// Si 'res' no está disponible en este contexto, necesitarás ajustar esta línea.
// Por ejemplo, si estás en el lado del cliente, solo necesitarías 'console.log(data)'.
res.json(data);
})
.catch(function (error) {
console.error('Hubo un problema con la petición Fetch:', error);
}); });
break; break;
case 2: case 2:
axios.post(arrayUrl[selc] + "?ruc=" + idCli) fetch(arrayUrl[selc] + "?ruc=" + idCli, {
method: 'POST', // fetch por defecto es GET, así que especificamos POST
})
.then(function (resp_sri) { .then(function (resp_sri) {
console.log(resp_sri.data); return resp_sri.text(); // Usamos .text() porque la respuesta se va a dividir por '***'
var data_toArray = resp_sri.data; })
.then(function (data_toArray) {
console.log(data_toArray);
let arr = data_toArray.split('***'); let arr = data_toArray.split('***');
console.log(arr); console.log(arr);
var obj_json = { nombre: arr[1], empresa: arr[2], direccion: arr[9] }; var obj_json = { nombre: arr[1], empresa: arr[2], direccion: arr[9] };
//var consulta = {"resp_consulta":json}; res.json(obj_json); // Enviamos el JSON al cliente
res.json(obj_json); })
.catch(function (error) {
console.error('Hubo un problema con la petición Fetch:', error);
// Podrías enviar un error al cliente si 'res' está disponible
// res.status(500).send('Error en la consulta');
}); });
break; break;
@@ -235,33 +259,43 @@ controlador.api_consultaCliente = (req, res) => {
console.log("Encontrado en Servidor Local:"); console.log("Encontrado en Servidor Local:");
res.json(rows); res.json(rows);
} else { } else {
axios.post(arrayUrl[1] + "?ID_CLIENTE=" + idCli) fetch(arrayUrl[1] + "?ID_CLIENTE=" + idCli, {
method: 'POST', // Especificamos el método POST
})
.then(function (resp_sri) { .then(function (resp_sri) {
// Si esperamos un array de objetos JSON, usamos .json()
return resp_sri.json();
})
.then(function (resp) {
console.log("Encontrado en Servidor SRI:"); console.log("Encontrado en Servidor SRI:");
console.log(resp_sri.data); console.log(resp);
var resp = resp_sri.data;
if (resp.length > 0) { if (resp.length > 0) {
var obj_json = { var obj_json = {
nombre: resp[0].CLI_NOMBRE, nombre: resp[0].CLI_NOMBRE,
nombre_comercial: resp[0].CLI_NOMBRE, nombre_comercial: resp[0].CLI_NOMBRE, // Se mantiene si es el mismo valor
direccion: resp[0].CLI_DIRECCION, direccion: resp[0].CLI_DIRECCION,
ciudad:"", telefono: ciudad: "", // Este campo parece venir vacío, se mantiene
resp[0].CLI_TELEFONOS, telefono: resp[0].CLI_TELEFONOS,
email: resp[0].CLI_EMAIL }; email: resp[0].CLI_EMAIL
res.json([obj_json]); };
res.json([obj_json]); // Enviamos un array con el objeto JSON
} else { } else {
res.json({ "RESP": "DATA NO ENCONTRADA" }); res.json({ "RESP": "DATA NO ENCONTRADA" });
//axios.post(arrayUrl[1] + "?ID_CLIENTE=" + idCli).then(function (resp_sri) {}); // La línea comentada de Axios que hacía otra petición sin efecto se omite aquí.
} }
}).catch(function (err) { })
console.log(err); .catch(function (err) {
console.error("Hubo un error con la petición Fetch:", err);
// Puedes enviar un error al cliente si lo consideras necesario, por ejemplo:
// res.status(500).json({ "RESP": "ERROR EN EL SERVIDOR" });
}); });
} }
}); });
}); });
} }
async function consulta_clientes(idCli) { /*async function consulta_clientes(idCli) {
if (false) { if (false) {
axios.post(arrayUrl[1] + "?ID_CLIENTE=" + idCli) axios.post(arrayUrl[1] + "?ID_CLIENTE=" + idCli)
.then(function (resp_sri) { .then(function (resp_sri) {
@@ -277,7 +311,7 @@ async function consulta_clientes(idCli) {
console.log(err); console.log(err);
}); });
} }
} }*/
module.exports = controlador; module.exports = controlador;

View File

@@ -1,5 +1,5 @@
const controlador = {}; const controlador = {};
const axios = require('axios').default; //const axios = require('axios').default;
const jwt = require('jsonwebtoken'); const jwt = require('jsonwebtoken');
const config = require('../config'); const config = require('../config');
const { base64encode, base64decode } = require('nodejs-base64'); const { base64encode, base64decode } = require('nodejs-base64');

View File

@@ -133,7 +133,8 @@ controlador.guardarItems = (req, res) => {
let json = JSON.parse(data.json_item); let json = JSON.parse(data.json_item);
//let json = parse.Items; //let json = parse.Items;
//console.log(json.length); //console.log(json.length);
for (var i = 0; i < json.length; i++) { //solucion cancelado
/*for (var i = 0; i < json.length; i++) {
var item = json[i]; var item = json[i];
//console.log(item); //console.log(item);
@@ -142,7 +143,17 @@ controlador.guardarItems = (req, res) => {
console.log(item); console.log(item);
});//set ? => data });//set ? => data
}); });
}*/
//solucion sujerida por IA
req.getConnection((err, conn) => {
for (let i = 0; i < json.length; i++) {
conn.query('INSERT INTO productos_cloud set ?', [json[i]], (err, rows) => {
// opcional: manejo de error
console.log("Si no funciona aqui esta el error");
});
} }
});
res.json("'resp':'ok'"); res.json("'resp':'ok'");
}; };

View File

@@ -338,7 +338,9 @@
gap: 20px; gap: 20px;
margin-top: 30px; margin-top: 30px;
} }
#toping{
font-size: 9px;
}
.texto_obsv { .texto_obsv {

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -31,7 +31,10 @@ function render_tabla_items(lista_items) {
let fila = `<tr> let fila = `<tr>
<td>${lista_items[key].codigo}</td> <td>${lista_items[key].codigo}</td>
<td>${lista_items[key].cantidad}</td> <td>${lista_items[key].cantidad}</td>
<td>${lista_items[key].nombre}</td> <td>
<div>${lista_items[key].nombre}</div>
<span id="toping">${lista_items[key].toping}</span>
</td>
<td>${Number(lista_items[key].precio).toFixed(2)}</td> <td>${Number(lista_items[key].precio).toFixed(2)}</td>
<td> <td>
<div class="estado ACTIVO label_text" onclick="add_toping('${lista_items[key].codigo}')"> <div class="estado ACTIVO label_text" onclick="add_toping('${lista_items[key].codigo}')">
@@ -111,7 +114,7 @@ function add_toping(cod) {
<div class="topping_container"> <div class="topping_container">
<div class="select_topping"> <div class="select_topping">
<select> <select>
<option value="Término Crudo">Término Crudo</option> <option value="Opcion">Término Crudo</option>
<option value="Término Medio">Término Medio</option> <option value="Término Medio">Término Medio</option>
<option value="Término Casi Cocido">Término Casi Cocido</option> <option value="Término Casi Cocido">Término Casi Cocido</option>
</select> </select>
@@ -140,8 +143,11 @@ function add_topingLista(codItems) {
pos = lista_items.indexOf(element);//posicion del vector pos = lista_items.indexOf(element);//posicion del vector
element.toping = topin_obs; element.toping = topin_obs;
console.log("Agregando Tp: " + topin_obs); console.log("Agregando Tp: " + topin_obs);
// Parámetros de splice: (índice_inicio, cantidad_a_eliminar, elementos_a_añadir...)
lista_items.splice(pos, 1,element);
} }
}); });
// Parámetros de splice: (índice_inicio, cantidad_a_eliminar, elementos_a_añadir...)
//lista_items.splice(pos, 1); //lista_items.splice(pos, 1);
render_tabla_items(lista_items); render_tabla_items(lista_items);
window.dialog.close(); window.dialog.close();
@@ -192,7 +198,7 @@ function enviar_pedidoLista() {
precio: lista_items[key].precio, precio: lista_items[key].precio,
descuento: "0", // valor fijo descuento: "0", // valor fijo
gp_precio: lista_items[key].grupo_precio, gp_precio: lista_items[key].grupo_precio,
topings: "Agregado un toping de prueba", topings: lista_items[key].toping ? lista_items[key].toping : "",
} }
itemCart.push(obj_item); itemCart.push(obj_item);
} }
@@ -203,7 +209,7 @@ function enviar_pedidoLista() {
"estado": "ACTIVO", "estado": "ACTIVO",
"valor": document.getElementById("total").innerText, "valor": document.getElementById("total").innerText,
"iva": document.getElementById("iva").innerText, "iva": document.getElementById("iva").innerText,
"plataforma": "WEB-MOVIL", "plataforma": "WEB-MOVIL RESTAURANT",
"items": itemCart, "items": itemCart,
"origen": mesa_nom, "origen": mesa_nom,
}; };

View File

@@ -96,7 +96,7 @@
</label> </label>
</div> </div>
<div class="user" id="user_avatar"> <div class="user" id="user_avatar">
<img src="../img/usuario2.jpeg" alt="usr"> <img src="../img/usuario-icon.png" alt="usr">
</div> </div>
</div> </div>
<!---******** CONTENIDO PARA RENDERIZAR ********---> <!---******** CONTENIDO PARA RENDERIZAR ********--->