UNPKG

14.4 kBJavaScriptView Raw
1!function(global, exports) {
2 "use strict";
3
4 var zhCn = {
5 decimal: ".",
6 thousands: ",",
7 grouping: [3],
8 currency: ["¥", ""]
9 };
10
11 var svSe = {
12 decimal: ",",
13 thousands: "\xa0",
14 grouping: [3],
15 currency: ["", "SEK"]
16 };
17
18 var ruRu = {
19 decimal: ",",
20 thousands: "\xa0",
21 grouping: [3],
22 currency: ["", "\xa0руб."]
23 };
24
25 var ptBr = {
26 decimal: ",",
27 thousands: ".",
28 grouping: [3],
29 currency: ["R$", ""]
30 };
31
32 var plPl = {
33 decimal: ",",
34 thousands: ".",
35 grouping: [3],
36 currency: ["", "zł"]
37 };
38
39 var nlNl = {
40 decimal: ",",
41 thousands: ".",
42 grouping: [3],
43 currency: ["€\xa0", ""]
44 };
45
46 var mkMk = {
47 decimal: ",",
48 thousands: ".",
49 grouping: [3],
50 currency: ["", "\xa0ден."]
51 };
52
53 var koKr = {
54 decimal: ".",
55 thousands: ",",
56 grouping: [3],
57 currency: ["₩", ""]
58 };
59
60 var jaJp = {
61 decimal: ".",
62 thousands: ",",
63 grouping: [3],
64 currency: ["", "円"]
65 };
66
67 var itIt = {
68 decimal: ",",
69 thousands: ".",
70 grouping: [3],
71 currency: ["€", ""]
72 };
73
74 var huHu = {
75 decimal: ",",
76 thousands: "\xa0",
77 grouping: [3],
78 currency: ["", "\xa0Ft"]
79 };
80
81 var heIl = {
82 decimal: ".",
83 thousands: ",",
84 grouping: [3],
85 currency: ["₪", ""]
86 };
87
88 var frFr = {
89 decimal: ",",
90 thousands: ".",
91 grouping: [3],
92 currency: ["", "\xa0€"]
93 };
94
95 var frCa = {
96 decimal: ",",
97 thousands: "\xa0",
98 grouping: [3],
99 currency: ["", "$"]
100 };
101
102 var fiFi = {
103 decimal: ",",
104 thousands: "\xa0",
105 grouping: [3],
106 currency: ["", "\xa0€"]
107 };
108
109 var esEs = {
110 decimal: ",",
111 thousands: ".",
112 grouping: [3],
113 currency: ["", "\xa0€"]
114 };
115
116 var enUs = {
117 decimal: ".",
118 thousands: ",",
119 grouping: [3],
120 currency: ["$", ""]
121 };
122
123 var enGb = {
124 decimal: ".",
125 thousands: ",",
126 grouping: [3],
127 currency: ["£", ""]
128 };
129
130 var enCa = {
131 decimal: ".",
132 thousands: ",",
133 grouping: [3],
134 currency: ["$", ""]
135 };
136
137 var deDe = {
138 decimal: ",",
139 thousands: ".",
140 grouping: [3],
141 currency: ["", "\xa0€"]
142 };
143
144 var deCh = {
145 decimal: ",",
146 thousands: "'",
147 grouping: [3],
148 currency: ["", "\xa0CHF"]
149 };
150
151 var caEs = {
152 decimal: ",",
153 thousands: ".",
154 grouping: [3],
155 currency: ["", "\xa0€"]
156 };
157
158 // Computes the decimal coefficient and exponent of the specified number x with
159 // significant digits p, where x is positive and p is in [1, 21] or undefined.
160 // For example, formatDecimal(1.23) returns ["123", 0].
161 function formatDecimal(x, p) {
162 if ((i = (x = p ? x.toExponential(p - 1) : x.toExponential()).indexOf("e")) < 0) return null; // NaN, ±Infinity
163 var i, coefficient = x.slice(0, i);
164
165 // The string returned by toExponential either has the form \d\.\d+e[-+]\d+
166 // (e.g., 1.2e+3) or the form \de[-+]\d+ (e.g., 1e+3).
167 return [
168 coefficient.length > 1 ? coefficient[0] + coefficient.slice(2) : coefficient,
169 +x.slice(i + 1)
170 ];
171 };
172
173 function exponent(x) {
174 return x = formatDecimal(Math.abs(x)), x ? x[1] : NaN;
175 };
176
177 function formatGroup(grouping, thousands) {
178 return function(value, width) {
179 var i = value.length,
180 t = [],
181 j = 0,
182 g = grouping[0],
183 length = 0;
184
185 while (i > 0 && g > 0) {
186 if (length + g + 1 > width) g = Math.max(1, width - length);
187 t.push(value.substring(i -= g, i + g));
188 if ((length += g + 1) > width) break;
189 g = grouping[j = (j + 1) % grouping.length];
190 }
191
192 return t.reverse().join(thousands);
193 };
194 };
195
196 var prefixExponent;
197
198 function formatPrefixAuto(x, p) {
199 var d = formatDecimal(x, p);
200 if (!d) return x + "";
201 var coefficient = d[0],
202 exponent = d[1],
203 i = exponent - (prefixExponent = Math.max(-8, Math.min(8, Math.floor(exponent / 3))) * 3) + 1,
204 n = coefficient.length;
205 return i === n ? coefficient
206 : i > n ? coefficient + new Array(i - n + 1).join("0")
207 : i > 0 ? coefficient.slice(0, i) + "." + coefficient.slice(i)
208 : "0." + new Array(1 - i).join("0") + formatDecimal(x, Math.max(0, p + i - 1))[0]; // less than 1y!
209 };
210
211 function formatRounded(x, p) {
212 var d = formatDecimal(x, p);
213 if (!d) return x + "";
214 var coefficient = d[0],
215 exponent = d[1];
216 return exponent < 0 ? "0." + new Array(-exponent).join("0") + coefficient
217 : coefficient.length > exponent + 1 ? coefficient.slice(0, exponent + 1) + "." + coefficient.slice(exponent + 1)
218 : coefficient + new Array(exponent - coefficient.length + 2).join("0");
219 };
220
221 function formatDefault(x, p) {
222 x = x.toPrecision(p);
223
224 out: for (var n = x.length, i = 1, i0 = -1, i1; i < n; ++i) {
225 switch (x[i]) {
226 case ".": i0 = i1 = i; break;
227 case "0": if (i0 === 0) i0 = i; i1 = i; break;
228 case "e": break out;
229 default: if (i0 > 0) i0 = 0; break;
230 }
231 }
232
233 return i0 > 0 ? x.slice(0, i0) + x.slice(i1 + 1) : x;
234 };
235
236 var formatTypes = {
237 "": formatDefault,
238 "%": function(x, p) { return (x * 100).toFixed(p); },
239 "b": function(x) { return Math.round(x).toString(2); },
240 "c": function(x) { return x + ""; },
241 "d": function(x) { return Math.round(x).toString(10); },
242 "e": function(x, p) { return x.toExponential(p); },
243 "f": function(x, p) { return x.toFixed(p); },
244 "g": function(x, p) { return x.toPrecision(p); },
245 "o": function(x) { return Math.round(x).toString(8); },
246 "p": function(x, p) { return formatRounded(x * 100, p); },
247 "r": formatRounded,
248 "s": formatPrefixAuto,
249 "X": function(x) { return Math.round(x).toString(16).toUpperCase(); },
250 "x": function(x) { return Math.round(x).toString(16); }
251 };
252
253 // [[fill]align][sign][symbol][0][width][,][.precision][type]
254 var re = /^(?:(.)?([<>=^]))?([+\-\( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?([a-z%])?$/i;
255
256 function formatSpecifier(specifier) {
257 return new FormatSpecifier(specifier);
258 };
259
260 function FormatSpecifier(specifier) {
261 if (!(match = re.exec(specifier))) throw new Error("invalid format: " + specifier);
262
263 var match,
264 fill = match[1] || " ",
265 align = match[2] || ">",
266 sign = match[3] || "-",
267 symbol = match[4] || "",
268 zero = !!match[5],
269 width = match[6] && +match[6],
270 comma = !!match[7],
271 precision = match[8] && +match[8].slice(1),
272 type = match[9] || "";
273
274 // The "n" type is an alias for ",g".
275 if (type === "n") comma = true, type = "g";
276
277 // Map invalid types to the default format.
278 else if (!formatTypes[type]) type = "";
279
280 // If zero fill is specified, padding goes after sign and before digits.
281 if (zero || (fill === "0" && align === "=")) zero = true, fill = "0", align = "=";
282
283 this.fill = fill;
284 this.align = align;
285 this.sign = sign;
286 this.symbol = symbol;
287 this.zero = zero;
288 this.width = width;
289 this.comma = comma;
290 this.precision = precision;
291 this.type = type;
292 }
293
294 FormatSpecifier.prototype.toString = function() {
295 return this.fill
296 + this.align
297 + this.sign
298 + this.symbol
299 + (this.zero ? "0" : "")
300 + (this.width == null ? "" : Math.max(1, this.width | 0))
301 + (this.comma ? "," : "")
302 + (this.precision == null ? "" : "." + Math.max(0, this.precision | 0))
303 + this.type;
304 };
305
306 var prefixes = ["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"];
307
308 function identity(x) {
309 return x;
310 }
311
312 function locale(locale) {
313 var group = locale.grouping && locale.thousands ? formatGroup(locale.grouping, locale.thousands) : identity,
314 currency = locale.currency,
315 decimal = locale.decimal;
316
317 function format(specifier) {
318 specifier = formatSpecifier(specifier);
319
320 var fill = specifier.fill,
321 align = specifier.align,
322 sign = specifier.sign,
323 symbol = specifier.symbol,
324 zero = specifier.zero,
325 width = specifier.width,
326 comma = specifier.comma,
327 precision = specifier.precision,
328 type = specifier.type;
329
330 // Compute the prefix and suffix.
331 // For SI-prefix, the suffix is lazily computed.
332 var prefix = symbol === "$" ? currency[0] : symbol === "#" && /[boxX]/.test(type) ? "0" + type.toLowerCase() : "",
333 suffix = symbol === "$" ? currency[1] : /[%p]/.test(type) ? "%" : "";
334
335 // What format function should we use?
336 // Is this an integer type?
337 // Can this type generate exponential notation?
338 var formatType = formatTypes[type],
339 maybeSuffix = !type || /[defgprs%]/.test(type);
340
341 // Set the default precision if not specified,
342 // or clamp the specified precision to the supported range.
343 // For significant precision, it must be in [1, 21].
344 // For fixed precision, it must be in [0, 20].
345 precision = precision == null ? (type ? 6 : 12)
346 : /[gprs]/.test(type) ? Math.max(1, Math.min(21, precision))
347 : Math.max(0, Math.min(20, precision));
348
349 return function(value) {
350 var valuePrefix = prefix,
351 valueSuffix = suffix;
352
353 if (type === "c") {
354 valueSuffix = formatType(value) + valueSuffix;
355 value = "";
356 } else {
357 value = +value;
358
359 // Convert negative to positive, and compute the prefix.
360 // Note that -0 is not less than 0, but 1 / -0 is!
361 var valueNegative = (value < 0 || 1 / value < 0) && (value *= -1, true);
362
363 // Perform the initial formatting.
364 value = formatType(value, precision);
365
366 // If the original value was negative, it may be rounded to zero during
367 // formatting; treat this as (positive) zero.
368 if (valueNegative) {
369 var i = -1, n = value.length, c;
370 valueNegative = false;
371 while (++i < n) {
372 if (c = value.charCodeAt(i), (48 < c && c < 58)
373 || (type === "x" && 96 < c && c < 103)
374 || (type === "X" && 64 < c && c < 71)) {
375 valueNegative = true;
376 break;
377 }
378 }
379 }
380
381 // Compute the prefix and suffix.
382 valuePrefix = (valueNegative ? (sign === "(" ? sign : "-") : sign === "-" || sign === "(" ? "" : sign) + valuePrefix;
383 valueSuffix = valueSuffix + (type === "s" ? prefixes[8 + prefixExponent / 3] : "") + (valueNegative && sign === "(" ? ")" : "");
384
385 // Break the formatted value into the integer “value” part that can be
386 // grouped, and fractional or exponential “suffix” part that is not.
387 if (maybeSuffix) {
388 var i = -1, n = value.length, c;
389 while (++i < n) {
390 if (c = value.charCodeAt(i), 48 > c || c > 57) {
391 valueSuffix = (c === 46 ? decimal + value.slice(i + 1) : value.slice(i)) + valueSuffix;
392 value = value.slice(0, i);
393 break;
394 }
395 }
396 }
397 }
398
399 // If the fill character is not "0", grouping is applied before padding.
400 if (comma && !zero) value = group(value, Infinity);
401
402 // Compute the padding.
403 var length = valuePrefix.length + value.length + valueSuffix.length,
404 padding = length < width ? new Array(width - length + 1).join(fill) : "";
405
406 // If the fill character is "0", grouping is applied after padding.
407 if (comma && zero) value = group(padding + value, padding.length ? width - valueSuffix.length : Infinity), padding = "";
408
409 // Reconstruct the final output based on the desired alignment.
410 switch (align) {
411 case "<": return valuePrefix + value + valueSuffix + padding;
412 case "=": return valuePrefix + padding + value + valueSuffix;
413 case "^": return padding.slice(0, length = padding.length >> 1) + valuePrefix + value + valueSuffix + padding.slice(length);
414 }
415 return padding + valuePrefix + value + valueSuffix;
416 };
417 }
418
419 function formatPrefix(specifier, value) {
420 var f = format((specifier = formatSpecifier(specifier), specifier.type = "f", specifier)),
421 e = Math.max(-8, Math.min(8, Math.floor(exponent(value) / 3))) * 3,
422 k = Math.pow(10, -e),
423 prefix = prefixes[8 + e / 3];
424 return function(value) {
425 return f(k * value) + prefix;
426 };
427 }
428
429 return {
430 format: format,
431 formatPrefix: formatPrefix
432 };
433 };
434
435 function precisionFixed(step) {
436 return Math.max(0, -exponent(Math.abs(step)));
437 };
438
439 function precisionPrefix(step, value) {
440 return Math.max(0, Math.max(-8, Math.min(8, Math.floor(exponent(value) / 3))) * 3 - exponent(Math.abs(step)));
441 };
442
443 function precisionRound(step, max) {
444 return Math.max(0, exponent(Math.abs(max)) - exponent(Math.abs(step))) + 1;
445 };
446
447 var localeDefinitions = {
448 "ca-ES": caEs,
449 "de-CH": deCh,
450 "de-DE": deDe,
451 "en-CA": enCa,
452 "en-GB": enGb,
453 "en-US": enUs,
454 "es-ES": esEs,
455 "fi-FI": fiFi,
456 "fr-CA": frCa,
457 "fr-FR": frFr,
458 "he-IL": heIl,
459 "hu-HU": huHu,
460 "it-IT": itIt,
461 "ja-JP": jaJp,
462 "ko-KR": koKr,
463 "mk-MK": mkMk,
464 "nl-NL": nlNl,
465 "pl-PL": plPl,
466 "pt-BR": ptBr,
467 "ru-RU": ruRu,
468 "sv-SE": svSe,
469 "zh-CN": zhCn
470 };
471
472 var defaultLocale = locale(enUs);
473 var format = defaultLocale.format;
474 var formatPrefix = defaultLocale.formatPrefix;
475
476 function localeFormat(definition) {
477 if (typeof definition === "string") {
478 if (!localeDefinitions.hasOwnProperty(definition)) return null;
479 definition = localeDefinitions[definition];
480 }
481 return locale(definition);
482 };
483
484 exports.format = format;
485 exports.formatPrefix = formatPrefix;
486 exports.localeFormat = localeFormat;
487 exports.formatSpecifier = formatSpecifier;
488 exports.precisionFixed = precisionFixed;
489 exports.precisionPrefix = precisionPrefix;
490 exports.precisionRound = precisionRound;
491 exports.version = "0.3.5";
492
493 if (typeof define === "function" && define.amd) global.format = exports, define("format", [], function() { return exports; });
494 else if (typeof module === "object" && module.exports) module.exports = exports;
495 else global.format = exports;
496}(this, {});