Apply module bundling
[platform/framework/web/wrtjs.git] / node_modules / to-regex-range / index.js
1 /*!
2  * to-regex-range <https://github.com/micromatch/to-regex-range>
3  *
4  * Copyright (c) 2015-present, Jon Schlinkert.
5  * Released under the MIT License.
6  */
7
8 'use strict';
9
10 const isNumber = require('is-number');
11
12 const toRegexRange = (min, max, options) => {
13   if (isNumber(min) === false) {
14     throw new TypeError('toRegexRange: expected the first argument to be a number');
15   }
16
17   if (max === void 0 || min === max) {
18     return String(min);
19   }
20
21   if (isNumber(max) === false) {
22     throw new TypeError('toRegexRange: expected the second argument to be a number.');
23   }
24
25   let opts = { relaxZeros: true, ...options };
26   if (typeof opts.strictZeros === 'boolean') {
27     opts.relaxZeros = opts.strictZeros === false;
28   }
29
30   let relax = String(opts.relaxZeros);
31   let shorthand = String(opts.shorthand);
32   let capture = String(opts.capture);
33   let wrap = String(opts.wrap);
34   let cacheKey = min + ':' + max + '=' + relax + shorthand + capture + wrap;
35
36   if (toRegexRange.cache.hasOwnProperty(cacheKey)) {
37     return toRegexRange.cache[cacheKey].result;
38   }
39
40   let a = Math.min(min, max);
41   let b = Math.max(min, max);
42
43   if (Math.abs(a - b) === 1) {
44     let result = min + '|' + max;
45     if (opts.capture) {
46       return `(${result})`;
47     }
48     if (opts.wrap === false) {
49       return result;
50     }
51     return `(?:${result})`;
52   }
53
54   let isPadded = hasPadding(min) || hasPadding(max);
55   let state = { min, max, a, b };
56   let positives = [];
57   let negatives = [];
58
59   if (isPadded) {
60     state.isPadded = isPadded;
61     state.maxLen = String(state.max).length;
62   }
63
64   if (a < 0) {
65     let newMin = b < 0 ? Math.abs(b) : 1;
66     negatives = splitToPatterns(newMin, Math.abs(a), state, opts);
67     a = state.a = 0;
68   }
69
70   if (b >= 0) {
71     positives = splitToPatterns(a, b, state, opts);
72   }
73
74   state.negatives = negatives;
75   state.positives = positives;
76   state.result = collatePatterns(negatives, positives, opts);
77
78   if (opts.capture === true) {
79     state.result = `(${state.result})`;
80   } else if (opts.wrap !== false && (positives.length + negatives.length) > 1) {
81     state.result = `(?:${state.result})`;
82   }
83
84   toRegexRange.cache[cacheKey] = state;
85   return state.result;
86 };
87
88 function collatePatterns(neg, pos, options) {
89   let onlyNegative = filterPatterns(neg, pos, '-', false, options) || [];
90   let onlyPositive = filterPatterns(pos, neg, '', false, options) || [];
91   let intersected = filterPatterns(neg, pos, '-?', true, options) || [];
92   let subpatterns = onlyNegative.concat(intersected).concat(onlyPositive);
93   return subpatterns.join('|');
94 }
95
96 function splitToRanges(min, max) {
97   let nines = 1;
98   let zeros = 1;
99
100   let stop = countNines(min, nines);
101   let stops = new Set([max]);
102
103   while (min <= stop && stop <= max) {
104     stops.add(stop);
105     nines += 1;
106     stop = countNines(min, nines);
107   }
108
109   stop = countZeros(max + 1, zeros) - 1;
110
111   while (min < stop && stop <= max) {
112     stops.add(stop);
113     zeros += 1;
114     stop = countZeros(max + 1, zeros) - 1;
115   }
116
117   stops = [...stops];
118   stops.sort(compare);
119   return stops;
120 }
121
122 /**
123  * Convert a range to a regex pattern
124  * @param {Number} `start`
125  * @param {Number} `stop`
126  * @return {String}
127  */
128
129 function rangeToPattern(start, stop, options) {
130   if (start === stop) {
131     return { pattern: start, count: [], digits: 0 };
132   }
133
134   let zipped = zip(start, stop);
135   let digits = zipped.length;
136   let pattern = '';
137   let count = 0;
138
139   for (let i = 0; i < digits; i++) {
140     let [startDigit, stopDigit] = zipped[i];
141
142     if (startDigit === stopDigit) {
143       pattern += startDigit;
144
145     } else if (startDigit !== '0' || stopDigit !== '9') {
146       pattern += toCharacterClass(startDigit, stopDigit, options);
147
148     } else {
149       count++;
150     }
151   }
152
153   if (count) {
154     pattern += options.shorthand === true ? '\\d' : '[0-9]';
155   }
156
157   return { pattern, count: [count], digits };
158 }
159
160 function splitToPatterns(min, max, tok, options) {
161   let ranges = splitToRanges(min, max);
162   let tokens = [];
163   let start = min;
164   let prev;
165
166   for (let i = 0; i < ranges.length; i++) {
167     let max = ranges[i];
168     let obj = rangeToPattern(String(start), String(max), options);
169     let zeros = '';
170
171     if (!tok.isPadded && prev && prev.pattern === obj.pattern) {
172       if (prev.count.length > 1) {
173         prev.count.pop();
174       }
175
176       prev.count.push(obj.count[0]);
177       prev.string = prev.pattern + toQuantifier(prev.count);
178       start = max + 1;
179       continue;
180     }
181
182     if (tok.isPadded) {
183       zeros = padZeros(max, tok, options);
184     }
185
186     obj.string = zeros + obj.pattern + toQuantifier(obj.count);
187     tokens.push(obj);
188     start = max + 1;
189     prev = obj;
190   }
191
192   return tokens;
193 }
194
195 function filterPatterns(arr, comparison, prefix, intersection, options) {
196   let result = [];
197
198   for (let ele of arr) {
199     let { string } = ele;
200
201     // only push if _both_ are negative...
202     if (!intersection && !contains(comparison, 'string', string)) {
203       result.push(prefix + string);
204     }
205
206     // or _both_ are positive
207     if (intersection && contains(comparison, 'string', string)) {
208       result.push(prefix + string);
209     }
210   }
211   return result;
212 }
213
214 /**
215  * Zip strings
216  */
217
218 function zip(a, b) {
219   let arr = [];
220   for (let i = 0; i < a.length; i++) arr.push([a[i], b[i]]);
221   return arr;
222 }
223
224 function compare(a, b) {
225   return a > b ? 1 : b > a ? -1 : 0;
226 }
227
228 function contains(arr, key, val) {
229   return arr.some(ele => ele[key] === val);
230 }
231
232 function countNines(min, len) {
233   return Number(String(min).slice(0, -len) + '9'.repeat(len));
234 }
235
236 function countZeros(integer, zeros) {
237   return integer - (integer % Math.pow(10, zeros));
238 }
239
240 function toQuantifier(digits) {
241   let [start = 0, stop = ''] = digits;
242   if (stop || start > 1) {
243     return `{${start + (stop ? ',' + stop : '')}}`;
244   }
245   return '';
246 }
247
248 function toCharacterClass(a, b, options) {
249   return `[${a}${(b - a === 1) ? '' : '-'}${b}]`;
250 }
251
252 function hasPadding(str) {
253   return /^-?(0+)\d/.test(str);
254 }
255
256 function padZeros(value, tok, options) {
257   if (!tok.isPadded) {
258     return value;
259   }
260
261   let diff = Math.abs(tok.maxLen - String(value).length);
262   let relax = options.relaxZeros !== false;
263
264   switch (diff) {
265     case 0:
266       return '';
267     case 1:
268       return relax ? '0?' : '0';
269     case 2:
270       return relax ? '0{0,2}' : '00';
271     default: {
272       return relax ? `0{0,${diff}}` : `0{${diff}}`;
273     }
274   }
275 }
276
277 /**
278  * Cache
279  */
280
281 toRegexRange.cache = {};
282 toRegexRange.clearCache = () => (toRegexRange.cache = {});
283
284 /**
285  * Expose `toRegexRange`
286  */
287
288 module.exports = toRegexRange;