-
Notifications
You must be signed in to change notification settings - Fork 121
/
Util.ts
86 lines (78 loc) · 2.74 KB
/
Util.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
import type { Readable, Writable } from 'stream';
import arrayifyStream from 'arrayify-stream';
import { UnsupportedHttpError } from './errors/UnsupportedHttpError';
/**
* Makes sure the input path has exactly 1 slash at the end.
* Multiple slashes will get merged into one.
* If there is no slash it will be added.
*
* @param path - Path to check.
*
* @returns The potentially changed path.
*/
export const ensureTrailingSlash = (path: string): string => path.replace(/\/*$/u, '/');
/**
* Joins all strings of a stream.
* @param stream - Stream of strings.
*
* @returns The joined string.
*/
export const readableToString = async(stream: Readable): Promise<string> => (await arrayifyStream(stream)).join('');
/**
* Makes sure the input path has no slashes at the end.
*
* @param path - Path to check.
*
* @returns The potentially changed path.
*/
export const trimTrailingSlashes = (path: string): string => path.replace(/\/+$/u, '');
/**
* Checks if the given two media types/ranges match each other.
* Takes wildcards into account.
* @param mediaA - Media type to match.
* @param mediaB - Media type to match.
*
* @returns True if the media type patterns can match each other.
*/
export const matchingMediaType = (mediaA: string, mediaB: string): boolean => {
const [ typeA, subTypeA ] = mediaA.split('/');
const [ typeB, subTypeB ] = mediaB.split('/');
if (typeA === '*' || typeB === '*') {
return true;
}
if (typeA !== typeB) {
return false;
}
if (subTypeA === '*' || subTypeB === '*') {
return true;
}
return subTypeA === subTypeB;
};
/**
* Pipes one stream into another.
* Makes sure an error of the first stream gets passed to the second.
* @param readable - Initial readable stream.
* @param destination - The destination for writing data.
*
* @returns The destination stream.
*/
export const pipeStreamsAndErrors = <T extends Writable>(readable: Readable, destination: T): T => {
readable.pipe(destination);
readable.on('error', (error): boolean => destination.emit('error', new UnsupportedHttpError(error.message)));
return destination;
};
/**
* Converts a URI path to the canonical version by splitting on slashes,
* decoding any percent-based encodings,
* and then encoding any special characters.
*/
export const toCanonicalUriPath = (path: string): string => path.split('/').map((part): string =>
encodeURIComponent(decodeURIComponent(part))).join('/');
/**
* Decodes all components of a URI path.
*/
export const decodeUriPathComponents = (path: string): string => path.split('/').map(decodeURIComponent).join('/');
/**
* Encodes all (non-slash) special characters in a URI path.
*/
export const encodeUriPathComponents = (path: string): string => path.split('/').map(encodeURIComponent).join('/');