-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathsource-converters.ts
126 lines (114 loc) · 3.68 KB
/
source-converters.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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
import { basename, extname } from 'path'
import { createReadStream, ReadStream } from 'fs'
import { Readable } from 'stream'
import { FileURI, PlainSource, Source, TupleSource, TupleStreamsSource } from '../_types'
import {
isBuffer,
isFileName,
isFileUri,
isIterable,
isObject,
isStream,
isString,
isTuple,
isURL,
} from './source-checkers'
export const DEFAULT_FILENAME = 'index.html'
/**
* Convert any possible source to tuples array
*/
export const toTuples = (source: Source, recursive = false): TupleSource[] => {
// if single URL is given -> remove it (should be removed by `url`, but nonetheless)
if (isURL(source)) return []
// if single file uri
if (isFileUri(source)) {
return !recursive && extname(source) === '.html'
? [[DEFAULT_FILENAME, source]] // single file uri and not inside recursion -> assume this is 'index.html'
: [[basename(source), source]] // if inside recursion or file is not .html -> just get name from file uri
}
// single string or buffer
if (isString(source) || isBuffer(source)) {
// just assume it is 'index.html', as most useful and common case
return [[DEFAULT_FILENAME, source]]
}
// if single stream
if (isStream(source)) {
if (source instanceof ReadStream) {
// file stream
// https://nodejs.org/api/fs.html#fs_readstream_path
const name = basename(String(source.path))
return !recursive && extname(name) === '.html'
? [[DEFAULT_FILENAME, source]] // single file stream and not inside recursion -> assume this is 'index.html'
: [[name, source]] // if inside recursion or file is not .html -> just get name from file uri
} else {
// some strange, not file stream -> just assume it is 'index.html'
return [[DEFAULT_FILENAME, source]]
}
}
// single tuple like we want to be -> just return it
if (isTuple(source)) {
if (isFileName(source[0])) {
return [source]
}
throw new Error(`Source name "${source[0]}" doesn't look like file name`)
}
// if object source
if (isObject(source)) {
const ret: TupleSource[] = []
for (const key in source) {
if (source.hasOwnProperty(key)) {
if (isFileName(key)) {
ret.push([key, source[key]])
} else {
throw new Error(`Source name "${key}" doesn't look like file name`)
}
}
}
return ret
}
// if iterable source
if (isIterable(source)) {
const ret: TupleSource[] = []
for (const src of source) {
// recursively convert to tuples
ret.push(...toTuples(src, true))
}
return ret
}
// if we get there, something is definitely wrong
throw new Error(`Bad source, don't know what to do with "${source}"`)
}
/**
* Read file to stream
* `path` should starts with 'file:' or 'file://'
* see https://en.wikipedia.org/wiki/File_URI_scheme
*/
export const fromFile = (path: FileURI): NodeJS.ReadableStream =>
createReadStream(path.replace(/^file:(\/\/)?/, ''))
/**
* Convert any plain source to stream
*/
export const toStream = (source: PlainSource): NodeJS.ReadableStream =>
isStream(source)
? source
: isFileUri(source)
? fromFile(source)
: // https://nodejs.org/docs/latest-v10.x/api/stream.html#stream_new_stream_readable_options
new Readable({
read() {
this.push(source)
this.push(null)
},
})
/**
* Convert any possible source to tuples array with streams only
*/
export const toStreams = (source?: Source): TupleStreamsSource[] => {
if (!source) return []
const tuples = toTuples(source)
const ret: TupleStreamsSource[] = []
for (let i = 0; i < tuples.length; i++) {
ret.push([tuples[i][0], toStream(tuples[i][1])])
}
return ret
}