Skip to content

Commit 4841822

Browse files
committed
Shave 100b off to offset new features
1 parent a7c8255 commit 4841822

File tree

3 files changed

+119
-109
lines changed

3 files changed

+119
-109
lines changed

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,14 @@
5454
"license": "Apache-2.0",
5555
"homepage": "https://github.com/developit/redaxios",
5656
"devDependencies": {
57+
"@types/jest": "^26.0.4",
5758
"core-js": "2.6.11",
5859
"eslint": "^6.8.0",
5960
"eslint-config-developit": "^1.1.1",
6061
"eslint-config-prettier": "6.11.0",
6162
"file-loader": "^5.0.2",
6263
"isomorphic-fetch": "^2.2.1",
63-
"jest": "^24.9.0",
64-
"karmatic": "^1.4.0",
64+
"karmatic": "^2.1.0",
6565
"microbundle": "^0.11.0",
6666
"prettier": "2.0.5",
6767
"sinon": "^8.0.4",

src/index.js

Lines changed: 64 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -54,70 +54,44 @@
5454
* @property {boolean} bodyUsed
5555
*/
5656

57+
/**
58+
* @typedef BodylessMethod
59+
* @type {<T=any>(url: string, config?: Options) => Promise<Response<T>>}
60+
*/
61+
62+
/**
63+
* @typedef BodyMethod
64+
* @type {<T=any>(url: string, body?: any, config?: Options) => Promise<Response<T>>}
65+
*/
66+
5767
/** */
5868
export default (function create(/** @type {Options} */ defaults) {
5969
defaults = defaults || {};
6070

61-
/**
62-
* Creates a request factory bound to the given HTTP method.
63-
* @private
64-
* @template T
65-
* @param {string} method
66-
* @returns {<T=any>(url: string, config?: Options) => Promise<Response<T>>}
67-
*/
68-
function createBodylessMethod(method) {
69-
return (url, config) => redaxios(url, Object.assign({ method }, config));
70-
}
71-
72-
/**
73-
* Creates a request factory bound to the given HTTP method.
74-
* @private
75-
* @template T
76-
* @param {string} method
77-
* @returns {<T=any>(url: string, body?: any, config?: Options) => Promise<Response<T>>}
78-
*/
79-
function createBodyMethod(method) {
80-
return (url, data, config) => redaxios(url, Object.assign({ method, data }, config));
81-
}
82-
83-
// /**
84-
// * Builds request url based on query string parameters
85-
// * @private
86-
// * @param {string} url
87-
// * @param {Record<string,string>|URLSearchParams} [params]
88-
// * @param {function} [serializer]
89-
// * @returns {string}
90-
// */
91-
// function buildUrl(url, params, serializer) {
92-
// const serializedParams = serializer ? serializer(params) : new URLSearchParams(params);
93-
// const divider = ~url.indexOf('?') ? '&' : '?';
94-
// return url + divider + serializedParams;
95-
// }
96-
9771
/**
9872
* @public
9973
* @template T
10074
* @type {(<T = any>(config?: Options) => Promise<Response<T>>) | (<T = any>(url: string, config?: Options) => Promise<Response<T>>)}
10175
*/
10276
redaxios.request = redaxios;
10377

104-
/** @public */
105-
redaxios.get = createBodylessMethod('get');
78+
/** @public @type {BodylessMethod} */
79+
redaxios.get = (url, config) => redaxios(url, config, 'get');
10680

107-
/** @public */
108-
redaxios.delete = createBodylessMethod('delete');
81+
/** @public @type {BodylessMethod} */
82+
redaxios.delete = (url, config) => redaxios(url, config, 'delete');
10983

110-
/** @public */
111-
redaxios.options = createBodylessMethod('options');
84+
/** @public @type {BodylessMethod} */
85+
redaxios.options = (url, config) => redaxios(url, config, 'options');
11286

113-
/** @public */
114-
redaxios.post = createBodyMethod('post');
87+
/** @public @type {BodyMethod} */
88+
redaxios.post = (url, data, config) => redaxios(url, config, 'post', data);
11589

116-
/** @public */
117-
redaxios.put = createBodyMethod('put');
90+
/** @public @type {BodyMethod} */
91+
redaxios.put = (url, data, config) => redaxios(url, config, 'put', data);
11892

119-
/** @public */
120-
redaxios.patch = createBodyMethod('patch');
93+
/** @public @type {BodyMethod} */
94+
redaxios.patch = (url, data, config) => redaxios(url, config, 'patch', data);
12195

12296
/** @public */
12397
redaxios.all = Promise.all;
@@ -133,35 +107,32 @@ export default (function create(/** @type {Options} */ defaults) {
133107
return fn.apply(this, results);
134108
};
135109
};
110+
// 3b smaller:
111+
// redaxios.spread = (fn) => /** @type {any} */ (fn.apply.bind(fn, fn));
136112

137113
/**
138114
* @private
139115
* @param {Record<string,any>} opts
140-
* @param {Record<string,any>} overrides
116+
* @param {Record<string,any>} [overrides]
141117
* @param {boolean} [lowerCase]
142-
* @returns {Record<string,any>}
118+
* @returns {Partial<opts>}
143119
*/
144120
function deepMerge(opts, overrides, lowerCase) {
121+
let out = {},
122+
i;
145123
if (Array.isArray(opts)) {
146124
return opts.concat(overrides);
147125
}
148-
if (overrides && typeof overrides == 'object') {
149-
let out = /** @type {Record<string,any>} */ ({}),
150-
i;
151-
if (opts) {
152-
for (i in opts) {
153-
let key = lowerCase ? i.toLowerCase() : i;
154-
out[key] = opts[i];
155-
}
156-
}
157-
for (i in overrides) {
158-
let key = lowerCase ? i.toLowerCase() : i;
159-
if (key === 'headers') lowerCase = true;
160-
out[key] = i in out ? deepMerge(out[key], overrides[i], lowerCase) : overrides[i];
161-
}
162-
return out;
126+
for (i in opts) {
127+
const key = lowerCase ? i.toLowerCase() : i;
128+
out[key] = opts[i];
129+
}
130+
for (i in overrides) {
131+
const key = lowerCase ? i.toLowerCase() : i;
132+
const value = /** @type {any} */ (overrides)[i];
133+
out[key] = key in out && typeof value == 'object' ? deepMerge(out[key], value, key === 'headers') : value;
163134
}
164-
return overrides;
135+
return out;
165136
}
166137

167138
/**
@@ -170,56 +141,40 @@ export default (function create(/** @type {Options} */ defaults) {
170141
* @template T
171142
* @param {string | Options} url
172143
* @param {Options} [config]
144+
* @param {any} [_method]
145+
* @param {any} [_data]
173146
* @returns {Promise<Response<T>>}
174147
*/
175-
function redaxios(url, config) {
148+
function redaxios(url, config, _method, _data) {
176149
if (typeof url !== 'string') {
177150
config = url;
178151
url = config.url;
179152
}
180153

181-
const userConfig = /** @type {Options} */ (config || {});
182-
183-
const response = /** @type {Response<any>} */ ({ config: userConfig });
184-
185-
/**
186-
* @type {Options}
187-
*/
188-
const options = deepMerge(defaults, userConfig);
154+
const response = /** @type {Response<any>} */ ({ config });
189155

190-
let data = options.data;
156+
/** @type {Options} */
157+
const options = deepMerge(defaults, config);
191158

192-
/**
193-
* @type {{'Content-Type':'application/json';Authorization: string} & Headers}
194-
*/
159+
/** @type {Headers} */
195160
const customHeaders = {};
196161

197-
if (options.transformRequest) {
198-
for (let i = 0; i < options.transformRequest.length; i++) {
199-
let r = options.transformRequest[i](data, options.headers);
200-
if (r !== undefined) {
201-
data = r;
202-
}
203-
}
204-
}
162+
let data = _data || options.data;
163+
164+
(options.transformRequest || []).map((f) => {
165+
data = f(data, options.headers) || data;
166+
});
205167

206168
if (data && typeof data === 'object' && typeof data.append !== 'function') {
207169
data = JSON.stringify(data);
208-
customHeaders['Content-Type'] = 'application/json';
170+
customHeaders['content-type'] = 'application/json';
209171
}
210172

211-
if (options.xsrfCookieName) {
212-
let parts = document.cookie.split(/ *[;=] */);
213-
for (let i = 0; i < parts.length; i += 2) {
214-
if (parts[i] == options.xsrfCookieName) {
215-
customHeaders[options.xsrfHeaderName] = decodeURIComponent(parts[i + 1]);
216-
break;
217-
}
218-
}
219-
}
173+
const m = document.cookie.match(RegExp('(^|; )' + options.xsrfCookieName + '=([^;]*)'));
174+
if (m) customHeaders[options.xsrfHeaderName] = m[2];
220175

221176
if (options.auth) {
222-
customHeaders.Authorization = options.auth;
177+
customHeaders.authorization = options.auth;
223178
}
224179

225180
if (options.baseURL) {
@@ -237,21 +192,23 @@ export default (function create(/** @type {Options} */ defaults) {
237192
const fetchFunc = options.fetch || fetch;
238193

239194
return fetchFunc(url, {
240-
method: options.method,
195+
method: _method || options.method,
241196
body: data,
242197
headers: deepMerge(options.headers, customHeaders, true),
243198
credentials: options.withCredentials ? 'include' : undefined
244199
}).then((res) => {
245-
let i;
246-
for (i in res) {
200+
for (const i in res) {
247201
if (typeof res[i] != 'function') response[i] = res[i];
248202
}
249-
if (!(options.validateStatus ? options.validateStatus(res.status) : res.ok)) {
250-
return Promise.reject(res);
203+
204+
const ok = options.validateStatus ? options.validateStatus(res.status) : res.ok;
205+
if (!ok) return Promise.reject(response);
206+
207+
if (options.responseType == 'stream') {
208+
response.data = res.body;
209+
return response;
251210
}
252-
const withData =
253-
options.responseType === 'stream' ? Promise.resolve(res.body) : res[options.responseType || 'text']();
254-
return withData.then((data) => {
211+
return res[options.responseType || 'text']().then((data) => {
255212
response.data = data;
256213
return response;
257214
});
@@ -262,7 +219,7 @@ export default (function create(/** @type {Options} */ defaults) {
262219
* @public
263220
* @type {AbortController}
264221
*/
265-
redaxios.CancelToken = /** @type {any} */ (typeof AbortController === 'function' ? AbortController : Object);
222+
redaxios.CancelToken = /** @type {any} */ (typeof AbortController == 'function' ? AbortController : Object);
266223

267224
/**
268225
* @public

test/index.test.js

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,59 @@ describe('redaxios', () => {
7676
}
7777
});
7878

79+
it('should merge headers case-insensitively', async () => {
80+
const oldFetch = window.fetch;
81+
try {
82+
const fetch = (window.fetch = jasmine.createSpy('fetch').and.returnValue(
83+
Promise.resolve({
84+
ok: true,
85+
status: 200,
86+
text: () => Promise.resolve('yep')
87+
})
88+
));
89+
await axios('/', { headers: { 'x-foo': '2' } });
90+
expect(fetch.calls.first().args[1].headers).toEqual({
91+
'x-foo': '2'
92+
});
93+
94+
fetch.calls.reset();
95+
96+
await axios('/', { headers: { 'x-foo': '2', 'X-Foo': '4' } });
97+
expect(fetch.calls.first().args[1].headers).toEqual({
98+
'x-foo': '4'
99+
});
100+
101+
fetch.calls.reset();
102+
103+
const request = axios.create({
104+
headers: {
105+
'Base-Upper': 'base',
106+
'base-lower': 'base'
107+
}
108+
});
109+
await request('/');
110+
expect(fetch.calls.first().args[1].headers).toEqual({
111+
'base-upper': 'base',
112+
'base-lower': 'base'
113+
});
114+
115+
fetch.calls.reset();
116+
117+
await request('/', {
118+
headers: {
119+
'base-upper': 'replaced',
120+
'BASE-LOWER': 'replaced'
121+
}
122+
});
123+
expect(fetch.calls.first().args[1].headers).toEqual({
124+
'base-upper': 'replaced',
125+
'base-lower': 'replaced'
126+
});
127+
} finally {
128+
window.fetch = oldFetch;
129+
}
130+
});
131+
79132
it('should issue POST requests', async () => {
80133
const oldFetch = window.fetch;
81134
try {

0 commit comments

Comments
 (0)