Follow xo linter rules more strictly (#829)

Co-authored-by: Moni <40552237+NotMoni@users.noreply.github.com>
This commit is contained in:
Antoni Kepinski 2020-05-25 17:11:56 +02:00 committed by GitHub
parent b3878b9a3e
commit fa627f4b0c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 268 additions and 211 deletions

199
README.md
View File

@ -154,9 +154,12 @@ NOTE: The documentation below is up-to-date with `3.x` releases, if you are usin
```js
const fetch = require('node-fetch');
fetch('https://github.com/')
.then(res => res.text())
.then(body => console.log(body));
(async () => {
const response = await fetch('https://github.com/');
const body = await response.text();
console.log(body);
})();
```
### JSON
@ -164,9 +167,12 @@ fetch('https://github.com/')
```js
const fetch = require('node-fetch');
fetch('https://api.github.com/users/github')
.then(res => res.json())
.then(json => console.log(json));
(async () => {
const response = await fetch('https://api.github.com/users/github');
const json = await response.json();
console.log(json);
})();
```
### Simple Post
@ -174,9 +180,12 @@ fetch('https://api.github.com/users/github')
```js
const fetch = require('node-fetch');
fetch('https://httpbin.org/post', {method: 'POST', body: 'a=1'})
.then(res => res.json()) // expecting a json response
.then(json => console.log(json));
(async () => {
const response = await fetch('https://httpbin.org/post', {method: 'POST', body: 'a=1'});
const json = await response.json();
console.log(json);
})();
```
### Post with JSON
@ -184,15 +193,18 @@ fetch('https://httpbin.org/post', {method: 'POST', body: 'a=1'})
```js
const fetch = require('node-fetch');
const body = {a: 1};
(async () => {
const body = {a: 1};
fetch('https://httpbin.org/post', {
method: 'post',
body: JSON.stringify(body),
headers: {'Content-Type': 'application/json'}
})
.then(res => res.json())
.then(json => console.log(json));
const response = await fetch('https://httpbin.org/post', {
method: 'post',
body: JSON.stringify(body),
headers: {'Content-Type': 'application/json'}
});
const json = await response.json();
console.log(json);
})();
```
### Post with form parameters
@ -207,21 +219,28 @@ const fetch = require('node-fetch');
const params = new URLSearchParams();
params.append('a', 1);
fetch('https://httpbin.org/post', {method: 'POST', body: params})
.then(res => res.json())
.then(json => console.log(json));
(async () => {
const response = await fetch('https://httpbin.org/post', {method: 'POST', body: params});
const json = await response.json();
console.log(json);
})();
```
### Handling exceptions
NOTE: 3xx-5xx responses are _NOT_ exceptions, and should be handled in `then()`, see the next section.
Adding a catch to the fetch promise chain will catch _all_ exceptions, such as errors originating from node core libraries, like network errors, and operational errors which are instances of FetchError. See the [error handling document][error-handling.md] for more details.
Wrapping the fetch function into a `try/catch` block will catch _all_ exceptions, such as errors originating from node core libraries, like network errors, and operational errors which are instances of FetchError. See the [error handling document][error-handling.md] for more details.
```js
const fetch = require('node-fetch');
fetch('https://domain.invalid/').catch(err => console.error(err));
try {
fetch('https://domain.invalid/');
} catch (error) {
console.log(error);
}
```
### Handling client and server errors
@ -231,7 +250,7 @@ It is common to create a helper function to check that the response contains no
```js
const fetch = require('node-fetch');
function checkStatus(res) {
const checkStatus = res => {
if (res.ok) {
// res.status >= 200 && res.status < 300
return res;
@ -240,9 +259,12 @@ function checkStatus(res) {
}
}
fetch('https://httpbin.org/status/400')
.then(checkStatus)
.then(res => console.log('will not get here...'));
(async () => {
const response = await fetch('https://httpbin.org/status/400');
const data = checkStatus(response);
console.log(data); //=> MyCustomError
})();
```
### Handling cookies
@ -260,14 +282,15 @@ const util = require('util');
const fs = require('fs');
const streamPipeline = util.promisify(require('stream').pipeline);
fetch('https://assets-cdn.github.com/images/modules/logos_page/Octocat.png')
.then(res => {
if (!res.ok) {
throw new Error(`unexpected response ${res.statusText}`);
}
(async () => {
const response = await fetch('https://assets-cdn.github.com/images/modules/logos_page/Octocat.png');
if (response.ok) {
return streamPipeline(res.body, fs.createWriteStream('./octocat.png'));
});
}
throw new Error(`unexpected response ${res.statusText}`);
})();
```
### Buffer
@ -278,12 +301,13 @@ If you prefer to cache binary data in full, use buffer(). (NOTE: buffer() is a `
const fetch = require('node-fetch');
const fileType = require('file-type');
fetch('https://octodex.github.com/images/Fintechtocat.png')
.then(res => res.buffer())
.then(buffer => fileType.fromBuffer(buffer))
.then(type => {
console.log(type);
});
(async () => {
const response = await fetch('https://octodex.github.com/images/Fintechtocat.png');
const buffer = await response.buffer();
const type = fileType.fromBuffer(buffer)
console.log(type);
})();
```
### Accessing Headers and other Meta data
@ -291,13 +315,15 @@ fetch('https://octodex.github.com/images/Fintechtocat.png')
```js
const fetch = require('node-fetch');
fetch('https://github.com/').then(res => {
(async () => {
const response = await fetch('https://github.com/');
console.log(res.ok);
console.log(res.status);
console.log(res.statusText);
console.log(res.headers.raw());
console.log(res.headers.get('content-type'));
});
})();
```
### Extract Set-Cookie Header
@ -307,10 +333,12 @@ Unlike browsers, you can access raw `Set-Cookie` headers manually using `Headers
```js
const fetch = require('node-fetch');
fetch('https://example.com').then(res => {
// returns an array of values, instead of a string of comma-separated values
(async () => {
const response = await fetch('https://example.com');
// Returns an array of values, instead of a string of comma-separated values
console.log(res.headers.raw()['set-cookie']);
});
})();
```
### Post data using a file stream
@ -321,9 +349,12 @@ const fetch = require('node-fetch');
const stream = createReadStream('input.txt');
fetch('https://httpbin.org/post', {method: 'POST', body: stream})
.then(res => res.json())
.then(json => console.log(json));
(async () => {
const response = await fetch('https://httpbin.org/post', {method: 'POST', body: stream});
const json = await response.json();
console.log(json)
})();
```
### Post with form-data (detect multipart)
@ -335,9 +366,12 @@ const FormData = require('form-data');
const form = new FormData();
form.append('a', 1);
fetch('https://httpbin.org/post', {method: 'POST', body: form})
.then(res => res.json())
.then(json => console.log(json));
(async () => {
const response = await fetch('https://httpbin.org/post', {method: 'POST', body: form});
const json = await response.json();
console.log(json)
})();
// OR, using custom headers
// NOTE: getHeaders() is non-standard API
@ -348,9 +382,12 @@ const options = {
headers: form.getHeaders()
};
fetch('https://httpbin.org/post', options)
.then(res => res.json())
.then(json => console.log(json));
(async () => {
const response = await fetch('https://httpbin.org/post', options);
const json = await response.json();
console.log(json)
})();
```
### Request cancellation with AbortSignal
@ -368,24 +405,23 @@ const timeout = setTimeout(() => {
controller.abort();
}, 150);
fetch('https://example.com', {signal: controller.signal})
.then(res => res.json())
.then(
data => {
useData(data);
},
err => {
if (err.name === 'AbortError') {
console.log('request was aborted');
}
(async () => {
try {
const response = await fetch('https://example.com', {signal: controller.signal});
const data = await response.json();
useData(data);
} catch (error) {
if (error.name === 'AbortError') {
console.log('request was aborted');
}
)
.finally(() => {
} finally {
clearTimeout(timeout);
});
}
})();
```
See [test cases](https://github.com/node-fetch/node-fetch/blob/master/test/test.js) for more examples.
See [test cases](https://github.com/node-fetch/node-fetch/blob/master/test/) for more examples.
## API
@ -409,10 +445,10 @@ The default values are shown after each option key.
{
// These properties are part of the Fetch Standard
method: 'GET',
headers: {}, // request headers. format is the identical to that accepted by the Headers constructor (see below)
body: null, // request body. can be null, a string, a Buffer, a Blob, or a Node.js Readable stream
redirect: 'follow', // set to `manual` to extract redirect headers, `error` to reject redirect
signal: null, // pass an instance of AbortSignal to optionally abort requests
headers: {}, // Request headers. format is the identical to that accepted by the Headers constructor (see below)
body: null, // Request body. can be null, a string, a Buffer, a Blob, or a Node.js Readable stream
redirect: 'follow', // Set to `manual` to extract redirect headers, `error` to reject redirect
signal: null, // Pass an instance of AbortSignal to optionally abort requests
// The following properties are node-fetch extensions
follow: 20, // maximum redirect count. 0 to not follow redirect
@ -484,14 +520,15 @@ The recommended way to fix this problem is to resolve cloned response in paralle
```js
const fetch = require('node-fetch');
fetch('https://example.com').then(res => {
const r1 = res.clone();
(async () => {
const response = await fetch('https://example.com');
const r1 = await response.clone();
return Promise.all([res.json(), r1.text()]).then(results => {
console.log(results[0]);
console.log(results[1]);
});
});
})();
```
If for some reason you don't like the solution above, since `3.x` you are able to modify the `highWaterMark` option:
@ -499,10 +536,14 @@ If for some reason you don't like the solution above, since `3.x` you are able t
```js
const fetch = require('node-fetch');
fetch('https://example.com', {
// About 1MB
highWaterMark: 1024 * 1024
}).then(res => res.clone().buffer());
(async () => {
const response = await fetch('https://example.com', {
// About 1MB
highWaterMark: 1024 * 1024
});
return res.clone().buffer();
})();
```
<a id="class-request"></a>

View File

@ -11,22 +11,26 @@ The basics:
```js
const fetch = required('node-fetch');
fetch(url, {signal}).catch(error => {
if (error.name === 'AbortError') {
console.log('request was aborted');
}
});
(async () => {
try {
await fetch(url, {signal});
} catch (error) {
if (error.name === 'AbortError') {
console.log('request was aborted');
}
}
})();
```
- All [operational errors][joyent-guide] *other than aborted requests* are rejected with a [FetchError](https://github.com/node-fetch/node-fetch/blob/master/README.md#class-fetcherror). You can handle them all through the promise `catch` clause.
- All [operational errors][joyent-guide] *other than aborted requests* are rejected with a [FetchError](https://github.com/node-fetch/node-fetch/blob/master/README.md#class-fetcherror). You can handle them all through the `try/catch` block or promise `catch` clause.
- All errors come with an `err.message` detailing the cause of errors.
- All errors come with an `error.message` detailing the cause of errors.
- All errors originating from `node-fetch` are marked with a custom `err.type`.
- All errors originating from Node.js core are marked with `err.type = 'system'`, and in addition contain an `err.code` and an `err.errno` for error handling. These are aliases for error codes thrown by Node.js core.
- All errors originating from Node.js core are marked with `error.type = 'system'`, and in addition contain an `error.code` and an `error.errno` for error handling. These are aliases for error codes thrown by Node.js core.
- [Programmer errors][joyent-guide] are either thrown as soon as possible, or rejected with default `Error` with `err.message` for ease of troubleshooting.
- [Programmer errors][joyent-guide] are either thrown as soon as possible, or rejected with default `Error` with `error.message` for ease of troubleshooting.
List of error types:

View File

@ -1,27 +1,39 @@
const fetch = require('node-fetch');
// Plain text or HTML
fetch('https://github.com/')
.then(res => res.text())
.then(body => console.log(body));
(async () => {
const response = await fetch('https://github.com/');
const body = await response.text();
console.log(body);
})();
// JSON
fetch('https://api.github.com/users/github')
.then(res => res.json())
.then(json => console.log(json));
(async () => {
const response = await fetch('https://github.com/');
const json = await response.json();
console.log(json);
})();
// Simple Post
fetch('https://httpbin.org/post', {method: 'POST', body: 'a=1'})
.then(res => res.json())
.then(json => console.log(json));
(async () => {
const response = await fetch('https://httpbin.org/post', {method: 'POST', body: 'a=1'});
const json = await response.json();
console.log(json);
})();
// Post with JSON
const body = {a: 1};
(async () => {
const body = {a: 1};
fetch('https://httpbin.org/post', {
method: 'post',
body: JSON.stringify(body),
headers: {'Content-Type': 'application/json'}
})
.then(res => res.json())
.then(json => console.log(json));
const response = await fetch('https://httpbin.org/post', {
method: 'post',
body: JSON.stringify(body),
headers: {'Content-Type': 'application/json'}
});
const json = await response.json();
console.log(json);
})();

View File

@ -88,11 +88,6 @@
],
"rules": {
"complexity": 0,
"promise/prefer-await-to-then": 0,
"no-mixed-operators": 0,
"no-negated-condition": 0,
"unicorn/prevent-abbreviations": 0,
"@typescript-eslint/prefer-readonly-parameter-types": 0,
"import/extensions": 0,
"import/no-useless-path-segments": 0,
"unicorn/import-index": 0,
@ -113,7 +108,10 @@
"max-nested-callbacks": 0,
"no-unused-expressions": 0,
"new-cap": 0,
"guard-for-in": 0
"guard-for-in": 0,
"unicorn/prevent-abbreviations": 0,
"promise/prefer-await-to-then": 0,
"ava/no-import-test-files": 0
}
},
{

View File

@ -10,7 +10,7 @@ import {types} from 'util';
import Blob from 'fetch-blob';
import FetchError from './errors/fetch-error.js';
import {isBlob, isURLSearchParams, isAbortError} from './utils/is.js';
import {isBlob, isURLSearchParameters, isAbortError} from './utils/is.js';
const INTERNALS = Symbol('Body internals');
@ -30,8 +30,8 @@ export default class Body {
if (body === null) {
// Body is undefined or null
body = null;
} else if (isURLSearchParams(body)) {
// Body is a URLSearchParams
} else if (isURLSearchParameters(body)) {
// Body is a URLSearchParams
body = Buffer.from(body.toString());
} else if (isBlob(body)) {
// Body is blob
@ -81,8 +81,9 @@ export default class Body {
*
* @return Promise
*/
arrayBuffer() {
return consumeBody.call(this).then(({buffer, byteOffset, byteLength}) => buffer.slice(byteOffset, byteOffset + byteLength));
async arrayBuffer() {
const {buffer, byteOffset, byteLength} = await consumeBody(this);
return buffer.slice(byteOffset, byteOffset + byteLength);
}
/**
@ -90,12 +91,14 @@ export default class Body {
*
* @return Promise
*/
blob() {
const ct = this.headers && this.headers.get('content-type') || this[INTERNALS].body && this[INTERNALS].body.type || '';
return consumeBody.call(this).then(buf => new Blob([], {
async blob() {
const ct = (this.headers && this.headers.get('content-type')) || (this[INTERNALS].body && this[INTERNALS].body.type) || '';
const buf = await consumeBody(this);
return new Blob([], {
type: ct.toLowerCase(),
buffer: buf
}));
});
}
/**
@ -103,8 +106,9 @@ export default class Body {
*
* @return Promise
*/
json() {
return consumeBody.call(this).then(buffer => JSON.parse(buffer.toString()));
async json() {
const buffer = await consumeBody(this);
return JSON.parse(buffer.toString());
}
/**
@ -112,8 +116,9 @@ export default class Body {
*
* @return Promise
*/
text() {
return consumeBody.call(this).then(buffer => buffer.toString());
async text() {
const buffer = await consumeBody(this);
return buffer.toString();
}
/**
@ -122,7 +127,7 @@ export default class Body {
* @return Promise
*/
buffer() {
return consumeBody.call(this);
return consumeBody(this);
}
}
@ -143,18 +148,18 @@ Object.defineProperties(Body.prototype, {
*
* @return Promise
*/
function consumeBody() {
if (this[INTERNALS].disturbed) {
return Body.Promise.reject(new TypeError(`body used already for: ${this.url}`));
const consumeBody = data => {
if (data[INTERNALS].disturbed) {
return Body.Promise.reject(new TypeError(`body used already for: ${data.url}`));
}
this[INTERNALS].disturbed = true;
data[INTERNALS].disturbed = true;
if (this[INTERNALS].error) {
return Body.Promise.reject(this[INTERNALS].error);
if (data[INTERNALS].error) {
return Body.Promise.reject(data[INTERNALS].error);
}
let {body} = this;
let {body} = data;
// Body is null
if (body === null) {
@ -171,7 +176,7 @@ function consumeBody() {
return Body.Promise.resolve(body);
}
// istanbul ignore if: should never happen
/* c8 ignore next 3 */
if (!(body instanceof Stream)) {
return Body.Promise.resolve(Buffer.alloc(0));
}
@ -188,9 +193,9 @@ function consumeBody() {
return;
}
if (this.size && accumBytes + chunk.length > this.size) {
if (data.size && accumBytes + chunk.length > data.size) {
abort = true;
reject(new FetchError(`content size at ${this.url} over limit: ${this.size}`, 'max-size'));
reject(new FetchError(`content size at ${data.url} over limit: ${data.size}`, 'max-size'));
return;
}
@ -206,7 +211,7 @@ function consumeBody() {
reject(err);
} else {
// Other errors, such as incorrect content-encoding
reject(new FetchError(`Invalid response body while trying to fetch ${this.url}: ${err.message}`, 'system', err));
reject(new FetchError(`Invalid response body while trying to fetch ${data.url}: ${err.message}`, 'system', err));
}
} else {
if (abort) {
@ -217,12 +222,12 @@ function consumeBody() {
resolve(Buffer.concat(accum, accumBytes));
} catch (error) {
// Handle streams that have accumulated too much data (issue #414)
reject(new FetchError(`Could not create Buffer from response body for ${this.url}: ${error.message}`, 'system', error));
reject(new FetchError(`Could not create Buffer from response body for ${data.url}: ${error.message}`, 'system', error));
}
}
});
});
}
};
/**
* Clone body given Res/Req instance
@ -231,7 +236,7 @@ function consumeBody() {
* @param String highWaterMark highWaterMark for both PassThrough body streams
* @return Mixed
*/
export function clone(instance, highWaterMark) {
export const clone = (instance, highWaterMark) => {
let p1;
let p2;
let {body} = instance;
@ -255,7 +260,7 @@ export function clone(instance, highWaterMark) {
}
return body;
}
};
/**
* Performs the operation "extract a `Content-Type` value from |object|" as
@ -267,7 +272,7 @@ export function clone(instance, highWaterMark) {
* @param {any} body Any options.body input
* @returns {string | null}
*/
export function extractContentType(body) {
export const extractContentType = body => {
// Body is null or undefined
if (body === null) {
return null;
@ -279,7 +284,7 @@ export function extractContentType(body) {
}
// Body is a URLSearchParams
if (isURLSearchParams(body)) {
if (isURLSearchParameters(body)) {
return 'application/x-www-form-urlencoded;charset=UTF-8';
}
@ -305,7 +310,7 @@ export function extractContentType(body) {
// Body constructor defaults other things to string
return 'text/plain;charset=UTF-8';
}
};
/**
* The Fetch Standard treats this as if "total bytes" is a property on the body.
@ -316,7 +321,7 @@ export function extractContentType(body) {
* @param {any} obj.body Body object from the Body instance.
* @returns {number | null}
*/
export function getTotalBytes({body}) {
export const getTotalBytes = ({body}) => {
// Body is null or undefined
if (body === null) {
return 0;
@ -339,7 +344,7 @@ export function getTotalBytes({body}) {
// Body is stream
return null;
}
};
/**
* Write a Body to a Node.js WritableStream (e.g. http.Request) object.
@ -348,7 +353,7 @@ export function getTotalBytes({body}) {
* @param obj.body Body object from the Body instance.
* @returns {void}
*/
export function writeToStream(dest, {body}) {
export const writeToStream = (dest, {body}) => {
if (body === null) {
// Body is null
dest.end();
@ -363,7 +368,7 @@ export function writeToStream(dest, {body}) {
// Body is stream
body.pipe(dest);
}
}
};
// Expose Promise
Body.Promise = global.Promise;

View File

@ -56,7 +56,10 @@ export default class Headers extends URLSearchParams {
} else if (typeof init === 'object' && !types.isBoxedPrimitive(init)) {
const method = init[Symbol.iterator];
// eslint-disable-next-line no-eq-null, eqeqeq
if (method != null) {
if (method == null) {
// Record<ByteString, ByteString>
result.push(...Object.entries(init));
} else {
if (typeof method !== 'function') {
throw new TypeError('Header pairs must be iterable');
}
@ -79,9 +82,6 @@ export default class Headers extends URLSearchParams {
return [...pair];
});
} else {
// Record<ByteString, ByteString>
result.push(...Object.entries(init));
}
} else {
throw new TypeError('Failed to construct \'Headers\': The provided value is not of type \'(sequence<sequence<ByteString>> or record<ByteString, ByteString>)');
@ -137,6 +137,7 @@ export default class Headers extends URLSearchParams {
return Reflect.get(target, p, receiver);
}
}
/* c8 ignore next */
});
}
@ -193,9 +194,9 @@ export default class Headers extends URLSearchParams {
* @returns {Record<string, string[]>}
*/
raw() {
return [...this.keys()].reduce((res, key) => {
res[key] = this.getAll(key);
return res;
return [...this.keys()].reduce((result, key) => {
result[key] = this.getAll(key);
return result;
}, {});
}
@ -203,17 +204,17 @@ export default class Headers extends URLSearchParams {
* For better console.log(headers) and also to convert Headers into Node.js Request compatible format
*/
[Symbol.for('nodejs.util.inspect.custom')]() {
return [...this.keys()].reduce((res, key) => {
return [...this.keys()].reduce((result, key) => {
const values = this.getAll(key);
// Http.request() only supports string as Host header.
// This hack makes specifying custom Host header possible.
if (key === 'host') {
res[key] = values[0];
result[key] = values[0];
} else {
res[key] = values.length > 1 ? values : values[0];
result[key] = values.length > 1 ? values : values[0];
}
return res;
return result;
}, {});
}
}
@ -224,9 +225,9 @@ export default class Headers extends URLSearchParams {
*/
Object.defineProperties(
Headers.prototype,
['get', 'entries', 'forEach', 'values'].reduce((res, property) => {
res[property] = {enumerable: true};
return res;
['get', 'entries', 'forEach', 'values'].reduce((result, property) => {
result[property] = {enumerable: true};
return result;
}, {})
);

View File

@ -29,7 +29,7 @@ export {Headers, Request, Response, FetchError, AbortError, isRedirect};
* @param Object opts Fetch options
* @return Promise
*/
export default function fetch(url, options_) {
const fetch = (url, options_) => {
// Allow custom promise
if (!fetch.Promise) {
throw new Error('native promise missing, set fetch.Promise to your favorite alternative');
@ -41,8 +41,8 @@ export default function fetch(url, options_) {
// If valid data uri
if (dataUriRegex.test(url)) {
const data = dataURIToBuffer(url);
const res = new Response(data, {headers: {'Content-Type': data.type}});
return fetch.Promise.resolve(res);
const response = new Response(data, {headers: {'Content-Type': data.type}});
return fetch.Promise.resolve(response);
}
// If invalid data uri
@ -94,24 +94,24 @@ export default function fetch(url, options_) {
signal.addEventListener('abort', abortAndFinalize);
}
function finalize() {
const finalize = () => {
request_.abort();
if (signal) {
signal.removeEventListener('abort', abortAndFinalize);
}
}
};
request_.on('error', err => {
reject(new FetchError(`request to ${request.url} failed, reason: ${err.message}`, 'system', err));
finalize();
});
request_.on('response', res => {
request_.on('response', response_ => {
request_.setTimeout(0);
const headers = fromRawHeaders(res.rawHeaders);
const headers = fromRawHeaders(response_.rawHeaders);
// HTTP fetch step 5
if (isRedirect(res.statusCode)) {
if (isRedirect(response_.statusCode)) {
// HTTP fetch step 5.2
const location = headers.get('Location');
@ -130,10 +130,9 @@ export default function fetch(url, options_) {
// Handle corrupted header
try {
headers.set('Location', locationURL);
/* c8 ignore next 3 */
} catch (error) {
/* c8 ignore next */
reject(error);
/* c8 ignore next */
}
}
@ -165,14 +164,14 @@ export default function fetch(url, options_) {
};
// HTTP-redirect fetch step 9
if (res.statusCode !== 303 && request.body && getTotalBytes(request) === null) {
if (response_.statusCode !== 303 && request.body && getTotalBytes(request) === null) {
reject(new FetchError('Cannot follow redirect with body being a readable stream', 'unsupported-redirect'));
finalize();
return;
}
// HTTP-redirect fetch step 11
if (res.statusCode === 303 || ((res.statusCode === 301 || res.statusCode === 302) && request.method === 'POST')) {
if (response_.statusCode === 303 || ((response_.statusCode === 301 || response_.statusCode === 302) && request.method === 'POST')) {
requestOptions.method = 'GET';
requestOptions.body = undefined;
requestOptions.headers.delete('content-length');
@ -190,20 +189,20 @@ export default function fetch(url, options_) {
}
// Prepare response
res.once('end', () => {
response_.once('end', () => {
if (signal) {
signal.removeEventListener('abort', abortAndFinalize);
}
});
let body = pump(res, new PassThrough(), error => {
let body = pump(response_, new PassThrough(), error => {
reject(error);
});
const responseOptions = {
url: request.url,
status: res.statusCode,
statusText: res.statusMessage,
status: response_.statusCode,
statusText: response_.statusMessage,
headers,
size: request.size,
counter: request.counter,
@ -221,7 +220,7 @@ export default function fetch(url, options_) {
// 3. no Content-Encoding header
// 4. no content response (204)
// 5. content not modified response (304)
if (!request.compress || request.method === 'HEAD' || codings === null || res.statusCode === 204 || res.statusCode === 304) {
if (!request.compress || request.method === 'HEAD' || codings === null || response_.statusCode === 204 || response_.statusCode === 304) {
response = new Response(body, responseOptions);
resolve(response);
return;
@ -251,7 +250,7 @@ export default function fetch(url, options_) {
if (codings === 'deflate' || codings === 'x-deflate') {
// Handle the infamous raw deflate response from old servers
// a hack for old IIS and Apache servers
const raw = pump(res, new PassThrough(), error => {
const raw = pump(response_, new PassThrough(), error => {
reject(error);
});
raw.once('data', chunk => {
@ -289,7 +288,9 @@ export default function fetch(url, options_) {
writeToStream(request_, request);
});
}
};
export default fetch;
// Expose Promise
fetch.Promise = global.Promise;

View File

@ -21,12 +21,12 @@ const INTERNALS = Symbol('Request internals');
* @param {*} obj
* @return {boolean}
*/
function isRequest(object) {
const isRequest = object => {
return (
typeof object === 'object' &&
typeof object[INTERNALS] === 'object'
);
}
};
/**
* Wrapper around `new URL` to handle relative URLs (https://github.com/nodejs/node/issues/12682)
@ -34,7 +34,7 @@ function isRequest(object) {
* @param {string} urlStr
* @return {void}
*/
function parseURL(urlString) {
const parseURL = urlString => {
/*
Check whether the URL is absolute or not
@ -46,7 +46,7 @@ function parseURL(urlString) {
}
throw new TypeError('Only absolute URLs are supported');
}
};
/**
* Request class
@ -60,7 +60,9 @@ export default class Request extends Body {
let parsedURL;
// Normalize input and force URL to be encoded as UTF-8 (https://github.com/bitinn/node-fetch/issues/245)
if (!isRequest(input)) {
if (isRequest(input)) {
parsedURL = parseURL(input.url);
} else {
if (input && input.href) {
// In order to support Node.js' Url objects; though WHATWG's URL objects
// will fall into this branch also (since their `toString()` will return
@ -72,21 +74,18 @@ export default class Request extends Body {
}
input = {};
} else {
parsedURL = parseURL(input.url);
}
let method = init.method || input.method || 'GET';
method = method.toUpperCase();
// eslint-disable-next-line no-eq-null, eqeqeq
if ((init.body != null || isRequest(input) && input.body !== null) &&
if (((init.body != null || isRequest(input)) && input.body !== null) &&
(method === 'GET' || method === 'HEAD')) {
throw new TypeError('Request with GET/HEAD method cannot have body');
}
// eslint-disable-next-line no-eq-null, eqeqeq
const inputBody = init.body != null ?
const inputBody = init.body ?
init.body :
(isRequest(input) && input.body !== null ?
clone(input) :
@ -125,12 +124,8 @@ export default class Request extends Body {
};
// Node-fetch-only options
this.follow = init.follow !== undefined ?
init.follow : (input.follow !== undefined ?
input.follow : 20);
this.compress = init.compress !== undefined ?
init.compress : (input.compress !== undefined ?
input.compress : true);
this.follow = init.follow === undefined ? (input.follow === undefined ? 20 : input.follow) : init.follow;
this.compress = init.compress === undefined ? (input.compress === undefined ? true : input.compress) : init.compress;
this.counter = init.counter || input.counter || 0;
this.agent = init.agent || input.agent;
this.highWaterMark = init.highWaterMark || input.highWaterMark || 16384;
@ -185,7 +180,7 @@ Object.defineProperties(Request.prototype, {
* @param Request A Request instance
* @return Object The options object to be passed to http.request
*/
export function getNodeRequestOptions(request) {
export const getNodeRequestOptions = request => {
const {parsedURL} = request[INTERNALS];
const headers = new Headers(request[INTERNALS].headers);
@ -256,4 +251,4 @@ export function getNodeRequestOptions(request) {
};
return requestOptions;
}
};

View File

@ -1,4 +1,4 @@
export function getSearch(parsedURL) {
export const getSearch = parsedURL => {
if (parsedURL.search) {
return parsedURL.search;
}
@ -6,4 +6,4 @@ export function getSearch(parsedURL) {
const lastOffset = parsedURL.href.length - 1;
const hash = parsedURL.hash || (parsedURL.href[lastOffset] === '#' ? '#' : '');
return parsedURL.href[lastOffset - hash.length] === '?' ? '?' : '';
}
};

View File

@ -6,6 +6,6 @@ const redirectStatus = new Set([301, 302, 303, 307, 308]);
* @param {number} code - Status code
* @return {boolean}
*/
export function isRedirect(code) {
export const isRedirect = code => {
return redirectStatus.has(code);
}
};

View File

@ -13,7 +13,7 @@ const NAME = Symbol.toStringTag;
* @param {*} obj
* @return {boolean}
*/
export function isURLSearchParams(object) {
export const isURLSearchParameters = object => {
return (
typeof object === 'object' &&
typeof object.append === 'function' &&
@ -25,7 +25,7 @@ export function isURLSearchParams(object) {
typeof object.sort === 'function' &&
object[NAME] === 'URLSearchParams'
);
}
};
/**
* Check if `obj` is a W3C `Blob` object (which `File` inherits from)
@ -33,7 +33,7 @@ export function isURLSearchParams(object) {
* @param {*} obj
* @return {boolean}
*/
export function isBlob(object) {
export const isBlob = object => {
return (
typeof object === 'object' &&
typeof object.arrayBuffer === 'function' &&
@ -42,7 +42,7 @@ export function isBlob(object) {
typeof object.constructor === 'function' &&
/^(Blob|File)$/.test(object[NAME])
);
}
};
/**
* Check if `obj` is an instance of AbortSignal.
@ -50,12 +50,12 @@ export function isBlob(object) {
* @param {*} obj
* @return {boolean}
*/
export function isAbortSignal(object) {
export const isAbortSignal = object => {
return (
typeof object === 'object' &&
object[NAME] === 'AbortSignal'
);
}
};
/**
* Check if `obj` is an instance of AbortError.
@ -63,6 +63,6 @@ export function isAbortSignal(object) {
* @param {*} obj
* @return {boolean}
*/
export function isAbortError(object) {
export const isAbortError = object => {
return object[NAME] === 'AbortError';
}
};

View File

@ -1766,7 +1766,7 @@ describe('node-fetch', () => {
it('should not timeout on cloning response without consuming one of the streams when the response size is double the custom large highWaterMark - 1', function () {
this.timeout(300);
const url = local.mockResponse(res => {
res.end(crypto.randomBytes(2 * 512 * 1024 - 1));
res.end(crypto.randomBytes((2 * 512 * 1024) - 1));
});
return expect(
fetch(url, {highWaterMark: 512 * 1024}).then(res => res.clone().buffer())