second
[josuexyz/.git] / node_modules / range-parser / index.js
1 /*!
2  * range-parser
3  * Copyright(c) 2012-2014 TJ Holowaychuk
4  * Copyright(c) 2015-2016 Douglas Christopher Wilson
5  * MIT Licensed
6  */
7
8 'use strict'
9
10 /**
11  * Module exports.
12  * @public
13  */
14
15 module.exports = rangeParser
16
17 /**
18  * Parse "Range" header `str` relative to the given file `size`.
19  *
20  * @param {Number} size
21  * @param {String} str
22  * @param {Object} [options]
23  * @return {Array}
24  * @public
25  */
26
27 function rangeParser (size, str, options) {
28   if (typeof str !== 'string') {
29     throw new TypeError('argument str must be a string')
30   }
31
32   var index = str.indexOf('=')
33
34   if (index === -1) {
35     return -2
36   }
37
38   // split the range string
39   var arr = str.slice(index + 1).split(',')
40   var ranges = []
41
42   // add ranges type
43   ranges.type = str.slice(0, index)
44
45   // parse all ranges
46   for (var i = 0; i < arr.length; i++) {
47     var range = arr[i].split('-')
48     var start = parseInt(range[0], 10)
49     var end = parseInt(range[1], 10)
50
51     // -nnn
52     if (isNaN(start)) {
53       start = size - end
54       end = size - 1
55     // nnn-
56     } else if (isNaN(end)) {
57       end = size - 1
58     }
59
60     // limit last-byte-pos to current length
61     if (end > size - 1) {
62       end = size - 1
63     }
64
65     // invalid or unsatisifiable
66     if (isNaN(start) || isNaN(end) || start > end || start < 0) {
67       continue
68     }
69
70     // add range
71     ranges.push({
72       start: start,
73       end: end
74     })
75   }
76
77   if (ranges.length < 1) {
78     // unsatisifiable
79     return -1
80   }
81
82   return options && options.combine
83     ? combineRanges(ranges)
84     : ranges
85 }
86
87 /**
88  * Combine overlapping & adjacent ranges.
89  * @private
90  */
91
92 function combineRanges (ranges) {
93   var ordered = ranges.map(mapWithIndex).sort(sortByRangeStart)
94
95   for (var j = 0, i = 1; i < ordered.length; i++) {
96     var range = ordered[i]
97     var current = ordered[j]
98
99     if (range.start > current.end + 1) {
100       // next range
101       ordered[++j] = range
102     } else if (range.end > current.end) {
103       // extend range
104       current.end = range.end
105       current.index = Math.min(current.index, range.index)
106     }
107   }
108
109   // trim ordered array
110   ordered.length = j + 1
111
112   // generate combined range
113   var combined = ordered.sort(sortByRangeIndex).map(mapWithoutIndex)
114
115   // copy ranges type
116   combined.type = ranges.type
117
118   return combined
119 }
120
121 /**
122  * Map function to add index value to ranges.
123  * @private
124  */
125
126 function mapWithIndex (range, index) {
127   return {
128     start: range.start,
129     end: range.end,
130     index: index
131   }
132 }
133
134 /**
135  * Map function to remove index value from ranges.
136  * @private
137  */
138
139 function mapWithoutIndex (range) {
140   return {
141     start: range.start,
142     end: range.end
143   }
144 }
145
146 /**
147  * Sort function to sort ranges by index.
148  * @private
149  */
150
151 function sortByRangeIndex (a, b) {
152   return a.index - b.index
153 }
154
155 /**
156  * Sort function to sort ranges by start position.
157  * @private
158  */
159
160 function sortByRangeStart (a, b) {
161   return a.start - b.start
162 }