UNPKG

5.14 kBJavaScriptView Raw
1import exponent from "./exponent";
2import formatGroup from "./formatGroup";
3import formatSpecifier from "./formatSpecifier";
4import formatTypes from "./formatTypes";
5import {prefixExponent} from "./formatPrefixAuto";
6
7var prefixes = ["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"];
8
9function identity(x) {
10 return x;
11}
12
13export default function(locale) {
14 var group = locale.grouping && locale.thousands ? formatGroup(locale.grouping, locale.thousands) : identity,
15 currency = locale.currency,
16 decimal = locale.decimal;
17
18 function format(specifier) {
19 specifier = formatSpecifier(specifier);
20
21 var fill = specifier.fill,
22 align = specifier.align,
23 sign = specifier.sign,
24 symbol = specifier.symbol,
25 zero = specifier.zero,
26 width = specifier.width,
27 comma = specifier.comma,
28 precision = specifier.precision,
29 type = specifier.type;
30
31 // Compute the prefix and suffix.
32 // For SI-prefix, the suffix is lazily computed.
33 var prefix = symbol === "$" ? currency[0] : symbol === "#" && /[boxX]/.test(type) ? "0" + type.toLowerCase() : "",
34 suffix = symbol === "$" ? currency[1] : /[%p]/.test(type) ? "%" : "";
35
36 // What format function should we use?
37 // Is this an integer type?
38 // Can this type generate exponential notation?
39 var formatType = formatTypes[type],
40 maybeSuffix = !type || /[defgprs%]/.test(type);
41
42 // Set the default precision if not specified,
43 // or clamp the specified precision to the supported range.
44 // For significant precision, it must be in [1, 21].
45 // For fixed precision, it must be in [0, 20].
46 precision = precision == null ? (type ? 6 : 12)
47 : /[gprs]/.test(type) ? Math.max(1, Math.min(21, precision))
48 : Math.max(0, Math.min(20, precision));
49
50 return function(value) {
51 var valuePrefix = prefix,
52 valueSuffix = suffix;
53
54 if (type === "c") {
55 valueSuffix = formatType(value) + valueSuffix;
56 value = "";
57 } else {
58 value = +value;
59
60 // Convert negative to positive, and compute the prefix.
61 // Note that -0 is not less than 0, but 1 / -0 is!
62 var valueNegative = (value < 0 || 1 / value < 0) && (value *= -1, true);
63
64 // Perform the initial formatting.
65 value = formatType(value, precision);
66
67 // If the original value was negative, it may be rounded to zero during
68 // formatting; treat this as (positive) zero.
69 if (valueNegative) {
70 var i = -1, n = value.length, c;
71 valueNegative = false;
72 while (++i < n) {
73 if (c = value.charCodeAt(i), (48 < c && c < 58)
74 || (type === "x" && 96 < c && c < 103)
75 || (type === "X" && 64 < c && c < 71)) {
76 valueNegative = true;
77 break;
78 }
79 }
80 }
81
82 // Compute the prefix and suffix.
83 valuePrefix = (valueNegative ? (sign === "(" ? sign : "-") : sign === "-" || sign === "(" ? "" : sign) + valuePrefix;
84 valueSuffix = valueSuffix + (type === "s" ? prefixes[8 + prefixExponent / 3] : "") + (valueNegative && sign === "(" ? ")" : "");
85
86 // Break the formatted value into the integer “value” part that can be
87 // grouped, and fractional or exponential “suffix” part that is not.
88 if (maybeSuffix) {
89 var i = -1, n = value.length, c;
90 while (++i < n) {
91 if (c = value.charCodeAt(i), 48 > c || c > 57) {
92 valueSuffix = (c === 46 ? decimal + value.slice(i + 1) : value.slice(i)) + valueSuffix;
93 value = value.slice(0, i);
94 break;
95 }
96 }
97 }
98 }
99
100 // If the fill character is not "0", grouping is applied before padding.
101 if (comma && !zero) value = group(value, Infinity);
102
103 // Compute the padding.
104 var length = valuePrefix.length + value.length + valueSuffix.length,
105 padding = length < width ? new Array(width - length + 1).join(fill) : "";
106
107 // If the fill character is "0", grouping is applied after padding.
108 if (comma && zero) value = group(padding + value, padding.length ? width - valueSuffix.length : Infinity), padding = "";
109
110 // Reconstruct the final output based on the desired alignment.
111 switch (align) {
112 case "<": return valuePrefix + value + valueSuffix + padding;
113 case "=": return valuePrefix + padding + value + valueSuffix;
114 case "^": return padding.slice(0, length = padding.length >> 1) + valuePrefix + value + valueSuffix + padding.slice(length);
115 }
116 return padding + valuePrefix + value + valueSuffix;
117 };
118 }
119
120 function formatPrefix(specifier, value) {
121 var f = format((specifier = formatSpecifier(specifier), specifier.type = "f", specifier)),
122 e = Math.max(-8, Math.min(8, Math.floor(exponent(value) / 3))) * 3,
123 k = Math.pow(10, -e),
124 prefix = prefixes[8 + e / 3];
125 return function(value) {
126 return f(k * value) + prefix;
127 };
128 }
129
130 return {
131 format: format,
132 formatPrefix: formatPrefix
133 };
134};