Skip to content

Commit dfc13a7

Browse files
committed
Add Accept-Encoding support
1 parent 0735a75 commit dfc13a7

10 files changed

+460
-21
lines changed

packages/headers/CHANGELOG.md

+19-1
Original file line numberDiff line numberDiff line change
@@ -109,9 +109,27 @@ header.getQuality('text/plain'); // 0.9
109109
header.getPreferred(['text/html', 'text/plain']); // 'text/html'
110110
```
111111

112-
- Added property support (getters and setters) for
112+
- Added `Accept-Encoding` support
113113

114+
```ts
115+
import { AcceptEncoding } from '@mjackson/headers';
116+
117+
let header = new AcceptEncoding({ gzip: 1, deflate: 0.9 });
118+
119+
header.accepts('gzip'); // true
120+
header.accepts('deflate'); // true
121+
header.accepts('identity'); // true
122+
header.accepts('br'); // false
123+
124+
header.getQuality('gzip'); // 1
125+
header.getQuality('deflate'); // 0.9
126+
127+
header.getPreferred(['gzip', 'deflate']); // 'gzip'
128+
```
129+
130+
- Added `SuperHeaders.prototype` (getters and setters) for:
114131
- `headers.accept`
132+
- `headers.acceptEncoding`
115133
- `headers.connection`
116134
- `headers.host`
117135
- `headers.referer`

packages/headers/README.md

+38-4
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ import Headers from '@mjackson/headers';
2525
let headers = new Headers();
2626

2727
// Accept
28-
headers.accept = 'text/html,text/*;q=0.9';
28+
headers.accept = { 'text/html': 1, 'text/*': 0.9 };
29+
// or headers.accept = 'text/html,text/*;q=0.9';
2930

3031
console.log(headers.accept.mediaTypes); // [ 'text/html', 'text/*' ]
3132
console.log(Object.fromEntries(headers.accept.entries())); // { 'text/html': 1, 'text/*': 0.9 }
@@ -41,8 +42,18 @@ headers.accept.set('text/*', 0.8);
4142

4243
console.log(headers.get('Accept')); // "text/html,text/plain;q=0.9,text/*;q=0.8"
4344

45+
// Accept-Encoding
46+
headers.acceptEncoding = { gzip: 1, deflate: 0.8 };
47+
// or headers.acceptEncoding = 'gzip, deflate;q=0.8';
48+
49+
headers.acceptEncoding.accepts('gzip'); // true
50+
headers.acceptEncoding.accepts('br'); // false
51+
52+
headers.acceptEncoding.getPreferred(['gzip', 'deflate']); // 'gzip'
53+
4454
// Accept-Language
45-
headers.acceptLanguage = 'en-US,en;q=0.9';
55+
headers.acceptLanguage = { 'en-US': 1, en: 0.9 };
56+
// or headers.acceptLanguage = 'en-US,en;q=0.9';
4657

4758
console.log(headers.acceptLanguage.languages); // [ 'en-us', 'en' ]
4859
console.log(Object.fromEntries(headers.acceptLanguage.entries())); // { 'en-us': 1, en: 0.9 }
@@ -190,6 +201,7 @@ The following headers are currently supported:
190201
- [Overview](#overview)
191202
- [Low-level API](#low-level-api)
192203
- [Accept](#accept)
204+
- [Accept-Encoding](#accept-encoding)
193205
- [Accept-Language](#accept-language)
194206
- [Cache-Control](#cache-control)
195207
- [Content-Disposition](#content-disposition)
@@ -215,7 +227,6 @@ header.accepts('image/jpeg'); // false
215227

216228
header.getPreferred(['text/html', 'text/plain']); // 'text/html'
217229

218-
// Iterate over media type/quality pairs
219230
for (let [mediaType, quality] of header) {
220231
// ...
221232
}
@@ -225,6 +236,30 @@ let header = new Accept({ 'text/html': 1, 'text/*': 0.9 });
225236
let header = new Accept(['text/html', ['text/*', 0.9]]);
226237
```
227238

239+
### Accept-Encoding
240+
241+
```ts
242+
let header = new AcceptEncoding('gzip,deflate;q=0.9');
243+
244+
header.has('gzip'); // true
245+
header.has('br'); // false
246+
247+
header.accepts('gzip'); // true
248+
header.accepts('deflate'); // true
249+
header.accepts('identity'); // true
250+
header.accepts('br'); // true
251+
252+
header.getPreferred(['gzip', 'deflate']); // 'gzip'
253+
254+
for (let [encoding, weight] of header) {
255+
// ...
256+
}
257+
258+
// Alternative init styles
259+
let header = new AcceptEncoding({ gzip: 1, deflate: 0.9 });
260+
let header = new AcceptEncoding(['gzip', ['deflate', 0.9]]);
261+
```
262+
228263
### Accept-Language
229264

230265
```ts
@@ -241,7 +276,6 @@ header.accepts('fr'); // true
241276
header.getPreferred(['en-US', 'en-GB']); // 'en-US'
242277
header.getPreferred(['en', 'fr']); // 'en'
243278

244-
// Iterate over language/quality pairs
245279
for (let [language, quality] of header) {
246280
// ...
247281
}

packages/headers/src/headers.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export { type AcceptInit, Accept } from './lib/accept.ts';
2+
export { type AcceptEncodingInit, AcceptEncoding } from './lib/accept-encoding.ts';
23
export { type AcceptLanguageInit, AcceptLanguage } from './lib/accept-language.ts';
34
export { type CacheControlInit, CacheControl } from './lib/cache-control.ts';
45
export { type ContentDispositionInit, ContentDisposition } from './lib/content-disposition.ts';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
import * as assert from 'node:assert/strict';
2+
import { describe, it } from 'node:test';
3+
4+
import { AcceptEncoding } from './accept-encoding.ts';
5+
6+
describe('Accept-Encoding', () => {
7+
it('initializes with an empty string', () => {
8+
let header = new AcceptEncoding('');
9+
assert.equal(header.size, 0);
10+
});
11+
12+
it('initializes with a string', () => {
13+
let header = new AcceptEncoding('gzip, deflate;q=0.9');
14+
assert.equal(header.size, 2);
15+
});
16+
17+
it('initializes with an array', () => {
18+
let header = new AcceptEncoding(['gzip', ['deflate', 0.9]]);
19+
assert.equal(header.size, 2);
20+
});
21+
22+
it('initializes with an object', () => {
23+
let header = new AcceptEncoding({ gzip: 1, deflate: 0.9 });
24+
assert.equal(header.size, 2);
25+
});
26+
27+
it('initializes with another AcceptEncoding', () => {
28+
let header = new AcceptEncoding(new AcceptEncoding('gzip, deflate;q=0.9'));
29+
assert.equal(header.size, 2);
30+
});
31+
32+
it('handles whitespace in initial value', () => {
33+
let header = new AcceptEncoding(' gzip , deflate;q= 0.9 ');
34+
assert.equal(header.size, 2);
35+
});
36+
37+
it('gets all encodings', () => {
38+
let header = new AcceptEncoding('gzip, deflate;q=0.9');
39+
assert.deepEqual(header.encodings, ['gzip', 'deflate']);
40+
});
41+
42+
it('gets all weights', () => {
43+
let header = new AcceptEncoding('gzip, deflate;q=0.9');
44+
assert.deepEqual(header.weights, [1, 0.9]);
45+
});
46+
47+
it('checks if an encoding is acceptable', () => {
48+
let header = new AcceptEncoding('gzip, deflate;q=0.9,br;q=0.8');
49+
assert.equal(header.accepts('gzip'), true);
50+
assert.equal(header.accepts('deflate'), true);
51+
assert.equal(header.accepts('br'), true);
52+
assert.equal(header.accepts('compress'), false);
53+
assert.equal(header.accepts('identity'), true); // special case
54+
});
55+
56+
it('gets the correct weights', () => {
57+
let header = new AcceptEncoding('gzip, deflate;q=0.9,*;q=0.8');
58+
assert.equal(header.getWeight('gzip'), 1);
59+
assert.equal(header.getWeight('deflate'), 0.9);
60+
assert.equal(header.getWeight('br'), 0.8);
61+
});
62+
63+
it('gets the preferred encoding', () => {
64+
let header = new AcceptEncoding('gzip, deflate;q=0.9,*;q=0.8');
65+
assert.equal(header.getPreferred(['gzip', 'deflate']), 'gzip');
66+
assert.equal(header.getPreferred(['deflate', 'br']), 'deflate');
67+
});
68+
69+
it('sets and gets encodings', () => {
70+
let header = new AcceptEncoding();
71+
header.set('gzip', 1);
72+
assert.equal(header.get('gzip'), 1);
73+
});
74+
75+
it('deletes encodings', () => {
76+
let header = new AcceptEncoding('gzip, deflate;q=0.9');
77+
assert.equal(header.has('gzip'), true);
78+
header.delete('gzip');
79+
assert.equal(header.has('gzip'), false);
80+
});
81+
82+
it('clears all encodings', () => {
83+
let header = new AcceptEncoding('gzip, deflate;q=0.9');
84+
assert.equal(header.size, 2);
85+
header.clear();
86+
assert.equal(header.size, 0);
87+
});
88+
89+
it('iterates over entries', () => {
90+
let header = new AcceptEncoding('gzip, deflate;q=0.9');
91+
assert.deepEqual(Array.from(header.entries()), [
92+
['gzip', 1],
93+
['deflate', 0.9],
94+
]);
95+
});
96+
97+
it('is directly iterable', () => {
98+
let header = new AcceptEncoding('gzip, deflate;q=0.9');
99+
assert.deepEqual(Array.from(header), [
100+
['gzip', 1],
101+
['deflate', 0.9],
102+
]);
103+
});
104+
105+
it('uses forEach correctly', () => {
106+
let header = new AcceptEncoding('gzip, deflate;q=0.9');
107+
let result: [string, number][] = [];
108+
header.forEach((encoding, weight) => {
109+
result.push([encoding, weight]);
110+
});
111+
assert.deepEqual(result, [
112+
['gzip', 1],
113+
['deflate', 0.9],
114+
]);
115+
});
116+
117+
it('returns correct size', () => {
118+
let header = new AcceptEncoding('gzip, deflate;q=0.9');
119+
assert.equal(header.size, 2);
120+
});
121+
122+
it('converts to a string', () => {
123+
let header = new AcceptEncoding('gzip, deflate;q=0.9');
124+
assert.equal(header.toString(), 'gzip,deflate;q=0.9');
125+
});
126+
127+
it('handles setting empty weights', () => {
128+
let header = new AcceptEncoding();
129+
header.set('deflate');
130+
assert.equal(header.get('deflate'), 1);
131+
});
132+
133+
it('handles setting wildcard value', () => {
134+
let header = new AcceptEncoding();
135+
header.set('*', 0.8);
136+
assert.equal(header.get('*'), 0.8);
137+
});
138+
139+
it('sorts initial value', () => {
140+
let header = new AcceptEncoding('deflate;q=0.9,gzip');
141+
assert.equal(header.toString(), 'gzip,deflate;q=0.9');
142+
});
143+
144+
it('sorts updated value', () => {
145+
let header = new AcceptEncoding('gzip;q=0.8,deflate');
146+
header.set('br');
147+
assert.equal(header.toString(), 'deflate,br,gzip;q=0.8');
148+
header.set('deflate', 0.9);
149+
assert.equal(header.toString(), 'br,deflate;q=0.9,gzip;q=0.8');
150+
});
151+
});

0 commit comments

Comments
 (0)