Skip to content

Commit 8c953bd

Browse files
committed
feat(request): CHECKOUT-2738 Add RequestSender
1 parent f4fb86e commit 8c953bd

22 files changed

+4671
-0
lines changed

.editorconfig

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
root = true
2+
3+
[*]
4+
charset = utf-8
5+
end_of_line = lf
6+
indent_size = 4
7+
indent_style = space
8+
insert_final_newline = true
9+
trim_trailing_whitespace = true
10+
11+
[*.md]
12+
trim_trailing_whitespace = false

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
*.log
2+
/coverage
3+
/node_modules

.travis.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
language: node_js
2+
3+
node_js: 6
4+
5+
cache: yarn
6+
7+
dist: trusty
8+
9+
sudo: false
10+
11+
before_install:
12+
- curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version 0.27.5
13+
- export PATH=$HOME/.yarn/bin:$PATH
14+
15+
script: yarn travis

commit-validation.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"scopes": [
3+
"common",
4+
"request"
5+
]
6+
}

eslintrc.json

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
"parser": "typescript-eslint-parser",
3+
"env": {
4+
"browser": true,
5+
"es6": true,
6+
"jest": true
7+
},
8+
"extends": "airbnb/base",
9+
"parserOptions": {
10+
"ecmaFeatures": {
11+
"experimentalObjectRestSpread": true
12+
}
13+
},
14+
"rules": {
15+
"consistent-return": "off",
16+
"indent": [2, 4],
17+
"max-len": [0],
18+
"no-console": "off",
19+
"no-param-reassign": [2, { "props": false }],
20+
"no-throw-literal": [0],
21+
"no-shadow": "off",
22+
"no-unused-expressions": "off",
23+
"no-use-before-define": [2, "nofunc"],
24+
"quote-props": [2, "consistent-as-needed"],
25+
"valid-jsdoc": [
26+
2,
27+
{
28+
"requireParamDescription": false,
29+
"requireReturnDescription": false
30+
}
31+
]
32+
}
33+
}

jest-config.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
module.exports = {
2+
browser: true,
3+
transform: {
4+
'\\.(ts|js)$': '<rootDir>/node_modules/ts-jest/preprocessor.js',
5+
},
6+
moduleFileExtensions: [
7+
'ts',
8+
'tsx',
9+
'js',
10+
'jsx',
11+
'json',
12+
],
13+
testRegex: '.*\\.spec.(js|ts)$',
14+
setupTestFrameworkScriptFile: '<rootDir>/jest-setup.js',
15+
collectCoverageFrom: [
16+
'src/**/*.{js,ts}',
17+
],
18+
coveragePathIgnorePatterns: [
19+
'\\.mock\\.(js|ts)$',
20+
'\\.typedef\\.(js|ts)$',
21+
],
22+
coverageThreshold: {
23+
global: {
24+
branches: 80,
25+
functions: 80,
26+
lines: 80,
27+
statements: 80,
28+
},
29+
},
30+
};

jest-setup.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
beforeAll(() => {
2+
expect.hasAssertions();
3+
});

package.json

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
{
2+
"name": "@bigcommerce/request-sender",
3+
"version": "0.0.0",
4+
"main": "lib/index.js",
5+
"files": [
6+
"lib/"
7+
],
8+
"engines": {
9+
"node": "^6.10.0",
10+
"yarn": "^0.27.5"
11+
},
12+
"repository": {
13+
"type": "git",
14+
"url": "git://github.com/bigcommerce/request-sender-js.git"
15+
},
16+
"author": "BigCommerce",
17+
"bugs": {
18+
"url": "https://github.com/bigcommerce/request-sender-js/issues"
19+
},
20+
"homepage": "https://github.com/bigcommerce/request-sender-js",
21+
"scripts": {
22+
"prebuild": "yarn lint && yarn test",
23+
"build": "yarn compile",
24+
"precompile": "rm -rf lib",
25+
"compile": "tsc --outDir lib",
26+
"compile:watch": "yarn compile -- --watch",
27+
"lint": "eslint src --config eslintrc.json",
28+
"prerelease": "git fetch --tags && yarn validate-dependencies && yarn validate-commits && yarn build",
29+
"release": "git add dist lib && standard-version -a",
30+
"test": "jest --config jest-config.js",
31+
"test:coverage": "yarn test -- --coverage",
32+
"test:series": "yarn test -- --runInBand",
33+
"test:watch": "yarn test -- --watch",
34+
"travis": "yarn lint && yarn test:series -- --coverage",
35+
"validate-commits": "validate-commits",
36+
"validate-dependencies": "yarn install --check-files --frozen-lockfile"
37+
},
38+
"dependencies": {
39+
"is-promise": "^2.1.0",
40+
"js-cookie": "^2.1.4",
41+
"query-string": "^5.0.0",
42+
"tslib": "^1.8.0"
43+
},
44+
"devDependencies": {
45+
"eslint": "2.8.0",
46+
"eslint-config-airbnb": "6.0.2",
47+
"eslint-plugin-react": "4.1.0",
48+
"jest": "^21.2.1",
49+
"standard-version": "^4.2.0",
50+
"ts-jest": "^21.2.3",
51+
"ts-loader": "^3.2.0",
52+
"typescript": "^2.6.2",
53+
"typescript-eslint-parser": "^9.0.1",
54+
"validate-commits": "git+ssh://git@github.com/bigcommerce-labs/validate-commits.git#1.1.0"
55+
}
56+
}

src/index.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import * as cookie from 'js-cookie';
2+
import RequestFactory from './request-factory';
3+
import RequestSender from './request-sender';
4+
import PayloadTransformer from './payload-transformer';
5+
import Timeout from './timeout';
6+
7+
/**
8+
* @return {RequestSender}
9+
*/
10+
export function createRequestSender() {
11+
return new RequestSender(
12+
new RequestFactory(),
13+
new PayloadTransformer(),
14+
cookie
15+
);
16+
}
17+
18+
/**
19+
* @param {number} [delay]
20+
* @return {Timeout}
21+
*/
22+
export function createTimeout(delay) {
23+
return new Timeout(delay);
24+
}

src/payload-transformer.js

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
const JSON_CONTENT_TYPE_REGEXP = /application\/(\w+\+)?json/;
2+
3+
export default class PayloadTransformer {
4+
/**
5+
* @param {RequestOptions} options
6+
* @returns {any}
7+
*/
8+
toRequestBody(options) {
9+
const contentType = this._getHeader(options.headers, 'Content-Type');
10+
11+
if (options.body && JSON_CONTENT_TYPE_REGEXP.test(contentType)) {
12+
return JSON.stringify(options.body);
13+
}
14+
15+
return options.body;
16+
}
17+
18+
/**
19+
* @param {XMLHttpRequest} xhr
20+
* @returns {Response}
21+
*/
22+
toResponse(xhr) {
23+
const headers = this._parseResponseHeaders(xhr.getAllResponseHeaders());
24+
const body = this._parseResponseBody('response' in xhr ? xhr.response : xhr.responseText, headers);
25+
26+
return {
27+
body,
28+
headers,
29+
status: xhr.status,
30+
statusText: xhr.statusText,
31+
};
32+
}
33+
34+
/**
35+
* @private
36+
* @param {string} body
37+
* @param {Object} headers
38+
* @return {any}
39+
*/
40+
_parseResponseBody(body, headers) {
41+
const contentType = this._getHeader(headers, 'Content-Type');
42+
43+
if (body && JSON_CONTENT_TYPE_REGEXP.test(contentType)) {
44+
return JSON.parse(body);
45+
}
46+
47+
return body;
48+
}
49+
50+
/**
51+
* @private
52+
* @param {string} rawHeaders
53+
* @return {Object}
54+
*/
55+
_parseResponseHeaders(rawHeaders) {
56+
const lines = rawHeaders ? rawHeaders.replace(/\r?\n[\t ]+/g, ' ').split(/\r?\n/) : [];
57+
58+
return lines.reduce((headers, line) => {
59+
const parts = line.split(':');
60+
const key = parts.shift().trim();
61+
62+
if (!key) {
63+
return headers;
64+
}
65+
66+
return {
67+
...headers,
68+
[key.toLowerCase()]: parts.join(':').trim(),
69+
};
70+
}, {});
71+
}
72+
73+
/**
74+
* @private
75+
* @param {Object} headers
76+
* @param {string} key
77+
* @return {string}
78+
*/
79+
_getHeader(headers, key) {
80+
if (!headers || !key) {
81+
return '';
82+
}
83+
84+
return headers[key] || headers[key.toLowerCase()] || '';
85+
}
86+
}

0 commit comments

Comments
 (0)