Skip to content

Commit 82e108d

Browse files
committed
Initial commit!
0 parents  commit 82e108d

File tree

10 files changed

+352
-0
lines changed

10 files changed

+352
-0
lines changed

.babelrc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"presets": ["es2015", "stage-0"]
3+
}

.editorconfig

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
root = true
2+
3+
[*]
4+
indent_style = tab
5+
end_of_line = lf
6+
charset = utf-8
7+
trim_trailing_whitespace = true
8+
insert_final_newline = true
9+
10+
[{package.json,.*rc,*.yml}]
11+
indent_style = space
12+
indent_size = 2
13+
14+
[*.md]
15+
trim_trailing_whitespace = false
16+
indent_style = space
17+
indent_size = 2

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/dist
2+
/test-reports
3+
/node_modules
4+
/npm-debug.log
5+
.DS_Store

.travis.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
language: node_js
2+
node_js:
3+
- 6

LICENSE.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2017 Jason Miller
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
<p align="center">
2+
<img src="https://i.imgur.com/JaXEFNp.png" width="300" height="300" alt="unfetch">
3+
<br>
4+
<a href="https://www.npmjs.org/package/unfetch"><img src="https://img.shields.io/npm/v/unfetch.svg?style=flat" alt="npm"></a> <a href="https://travis-ci.org/developit/unfetch"><img src="https://travis-ci.org/developit/unfetch.svg?branch=master" alt="travis"></a>
5+
</p>
6+
7+
# unfetch
8+
9+
> Tiny 500b fetch "barely-polyfill"
10+
11+
- **Tiny:** weighs about **500 bytes** gzipped
12+
- **Minimal:** just `fetch()` with headers and text/json/xml responses
13+
- **Familiar:** a subset of the full API
14+
- **Supported:** supports IE8+ (<abbr title="Bring Your Own Promises">BYOP</abbr>)
15+
- **Standalone:** one function, no dependencies
16+
17+
> 🤔 **What's Missing?**
18+
>
19+
> - Uses simple Arrays instead of Iterables, since Arrays _are_ iterables
20+
> - No streaming, just Promisifies existing XMLHttpRequest response bodies
21+
> - Bare-bones `.blob()` implementation - just proxies `xhr.response`
22+
23+
* * *
24+
25+
## Table of Contents
26+
27+
- [Install](#install)
28+
- [Usage](#usage)
29+
- [Examples & Demos](#examples--demos)
30+
- [API](#api)
31+
- [Contribute](#contribute)
32+
- [License](#license)
33+
34+
* * *
35+
36+
## Install
37+
38+
This project uses [node](http://nodejs.org) and [npm](https://npmjs.com). Go check them out if you don't have them locally installed.
39+
40+
```sh
41+
$ npm install --save unfetch
42+
```
43+
44+
Then with a module bundler like [rollup](http://rollupjs.org/) or [webpack](https://webpack.js.org/), use as you would anything else:
45+
46+
```javascript
47+
// using ES6 modules
48+
import fetch from 'unfetch'
49+
50+
// using CommonJS modules
51+
var fetch = require('unfetch')
52+
```
53+
54+
The [UMD](https://github.com/umdjs/umd) build is also available on [unpkg](https://unpkg.com):
55+
56+
```html
57+
<script src="https://unpkg.com/unfetch/dist/unfetch.umd.js"></script>
58+
```
59+
60+
This exposes a `fetch` global if not already present.
61+
62+
* * *
63+
64+
## Usage
65+
66+
```js
67+
import fetch from 'unfetch'
68+
69+
fetch('/foo.json')
70+
.then( r => r.json() )
71+
.then( data => {
72+
console.log(data)
73+
})
74+
```
75+
76+
## Examples & Demos
77+
78+
_Coming soon!_
79+
80+
* * *
81+
82+
## API
83+
84+
## Contribute
85+
86+
First off, thanks for taking the time to contribute!
87+
Now, take a moment to be sure your contributions make sense to everyone else.
88+
89+
### Reporting Issues
90+
91+
Found a problem? Want a new feature? First of all see if your issue or idea has [already been reported](../../issues).
92+
If don't, just open a [new clear and descriptive issue](../../issues/new).
93+
94+
### Submitting pull requests
95+
96+
Pull requests are the greatest contributions, so be sure they are focused in scope, and do avoid unrelated commits.
97+
98+
- Fork it!
99+
- Clone your fork: `git clone https://github.com/<your-username>/unfetch`
100+
- Navigate to the newly cloned directory: `cd unfetch`
101+
- Create a new branch for the new feature: `git checkout -b my-new-feature`
102+
- Install the tools necessary for development: `npm install`
103+
- Make your changes.
104+
- Commit your changes: `git commit -am 'Add some feature'`
105+
- Push to the branch: `git push origin my-new-feature`
106+
- Submit a pull request with full remarks documenting your changes.
107+
108+
## License
109+
110+
[MIT License](LICENSE.md) © [Jason Miller](https://jasonformat.com/)

package.json

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
{
2+
"name": "unfetch",
3+
"version": "1.0.0",
4+
"description": "Bare minimum 500b fetch polyfill.",
5+
"jsnext:main": "src/index.js",
6+
"main": "dist/unfetch.js",
7+
"umd:main": "dist/unfetch.umd.js",
8+
"scripts": {
9+
"test": "eslint src test && mocha --compilers js:babel-register test/**/*.js",
10+
"build": "npm-run-all clean -p rollup:* -p minify:* -s docs size",
11+
"clean": "rimraf dist && mkdirp dist",
12+
"rollup:cjs": "rollup -c rollup.config.js -m -f cjs -n $npm_package_name $npm_package_jsnext_main -o $npm_package_main",
13+
"rollup:umd": "rollup -c rollup.config.js -m -f umd -n $npm_package_name $npm_package_jsnext_main -o $npm_package_umd_main",
14+
"minify:cjs": "uglifyjs $npm_package_main -cm toplevel -o $npm_package_main -p relative --in-source-map ${npm_package_main}.map --source-map ${npm_package_main}.map",
15+
"minify:umd": "uglifyjs $npm_package_umd_main -cm -o $npm_package_umd_main -p relative --in-source-map ${npm_package_umd_main}.map --source-map ${npm_package_umd_main}.map",
16+
"docs": "documentation readme src/index.js --section API -q",
17+
"size": "echo \"Gzipped Size: $(strip-json-comments --no-whitespace $npm_package_main | gzip-size)\"",
18+
"release": "npm run build -s && git commit -am $npm_package_version && git tag $npm_package_version && git push && git push --tags && npm publish"
19+
},
20+
"repository": "developit/unfetch",
21+
"keywords": [
22+
"fetch",
23+
"polyfill",
24+
"xhr",
25+
"ajax"
26+
],
27+
"homepage": "https://github.com/developit/unfetch",
28+
"authors": [
29+
"Jason Miller <jason@developit.ca>"
30+
],
31+
"license": "MIT",
32+
"files": [
33+
"src",
34+
"dist"
35+
],
36+
"eslintConfig": {
37+
"parser": "babel-eslint",
38+
"extends": "eslint:recommended",
39+
"env": {
40+
"browser": true,
41+
"mocha": true,
42+
"node": true,
43+
"es6": true
44+
},
45+
"globals": {
46+
"expect": true
47+
}
48+
},
49+
"devDependencies": {
50+
"babel-core": "^6.9.1",
51+
"babel-eslint": "^7.1.1",
52+
"babel-preset-es2015": "^6.9.0",
53+
"babel-preset-stage-0": "^6.5.0",
54+
"babel-register": "^6.9.0",
55+
"chai": "^3.5.0",
56+
"documentation": "^4.0.0-beta4",
57+
"eslint": "^3.13.1",
58+
"gzip-size-cli": "^1.0.0",
59+
"mkdirp": "^0.5.1",
60+
"mocha": "^3.2.0",
61+
"npm-run-all": "^2.1.1",
62+
"rimraf": "^2.5.2",
63+
"rollup": "^0.41.4",
64+
"rollup-plugin-buble": "^0.15.0",
65+
"sinon": "^1.17.4",
66+
"sinon-chai": "^2.8.0",
67+
"strip-json-comments-cli": "^1.0.1",
68+
"uglify-js": "^2.6.2"
69+
}
70+
}

rollup.config.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import buble from 'rollup-plugin-buble';
2+
3+
export default {
4+
useStrict: false,
5+
plugins: [
6+
buble()
7+
]
8+
};

src/index.js

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
export default function fetch(url, options) {
2+
options = options || {};
3+
return new Promise( (resolve, reject) => {
4+
let request = new XMLHttpRequest();
5+
6+
for (let i in options.headers) {
7+
request.setRequestHeader(i, options.headers[i]);
8+
}
9+
10+
request.open(options.method || 'get', url);
11+
12+
request.onload = () => {
13+
resolve(response(request));
14+
};
15+
16+
request.onerror = () => {
17+
reject(Error('Network Error'));
18+
};
19+
20+
request.send(options.body || null);
21+
22+
function response(xhr) {
23+
let headerText = xhr.getAllResponseHeaders(),
24+
keys = [],
25+
all = [],
26+
headers = {},
27+
reg = /^\s*(.*?)\s*\:\s*([\s\S]*?)\s*$/gm,
28+
match, key;
29+
while ((match=reg.exec(headerText))) {
30+
keys.push(key = match[1].toLowerCase());
31+
all.push([key, match[2]]);
32+
headers[key] = (headers[key]?(headers[key]+','):'') + match[2];
33+
}
34+
35+
return {
36+
type: 'cors',
37+
ok: xhr.status/200|0 == 1, // 200-399
38+
status: xhr.status,
39+
statusText: xhr.statusText,
40+
url: xhr.responseURL,
41+
clone: () => response(xhr),
42+
text: () => Promise.resolve(xhr.responseText),
43+
json: () => Promise.resolve(xhr.responseText).then(JSON.parse),
44+
xml: () => Promise.resolve(xhr.responseXML),
45+
blob: () => Promise.resolve(xhr.response),
46+
headers: {
47+
keys: () => keys,
48+
entries: () => all,
49+
get: n => headers[n.toLowerCase()],
50+
has: n => !!headers[n.toLowerCase()]
51+
}
52+
};
53+
}
54+
});
55+
}

test/index.js

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import fetch from '../src';
2+
import chai, { expect } from 'chai';
3+
import { spy, stub } from 'sinon';
4+
import sinonChai from 'sinon-chai';
5+
chai.use(sinonChai);
6+
7+
8+
describe('unfetch', () => {
9+
it('should be a function', () => {
10+
expect(fetch).to.be.a('function');
11+
});
12+
13+
describe('fetch()', () => {
14+
it('sanity test', () => {
15+
let xhr = {
16+
setRequestHeader: spy(),
17+
getAllResponseHeaders: stub().returns('X-Foo: bar\nX-Foo:baz'),
18+
open: spy(),
19+
send: spy(),
20+
status: 200,
21+
statusText: 'OK',
22+
responseText: '{"a":"b"}',
23+
responseURL: '/foo?redirect'
24+
};
25+
26+
global.XMLHttpRequest = stub().returns(xhr);
27+
28+
let p = fetch('/foo', { headers: { a: 'b' } })
29+
.then( r => {
30+
expect(r).to.have.property('text').that.is.a('function');
31+
expect(r).to.have.property('json').that.is.a('function');
32+
expect(r).to.have.property('xml').that.is.a('function');
33+
expect(r).to.have.property('blob').that.is.a('function');
34+
expect(r).to.have.property('clone').that.is.a('function');
35+
expect(r).to.have.property('headers');
36+
expect(r.clone()).not.to.equal(r);
37+
expect(r.clone()).to.have.property('url', '/foo?redirect');
38+
expect(r).to.have.property('headers').with.property('get').that.is.a('function');
39+
expect(r.headers.get('x-foo')).to.equal('bar,baz');
40+
return r.json();
41+
})
42+
.then( data => {
43+
expect(data).to.eql({ a:'b' });
44+
45+
expect(xhr.setRequestHeader).to.have.been.calledOnce.and.calledWith('a', 'b');
46+
expect(xhr.open).to.have.been.calledOnce.and.calledWith('get', '/foo');
47+
expect(xhr.send).to.have.been.calledOnce.and.calledWith(null);
48+
49+
delete global.XMLHttpRequest;
50+
});
51+
52+
expect(xhr.onload).to.be.a('function');
53+
expect(xhr.onerror).to.be.a('function');
54+
55+
xhr.onload();
56+
57+
return p;
58+
});
59+
});
60+
});

0 commit comments

Comments
 (0)