in src/formattingService/formattingService.ts [698:801]
function formatNumberCustom(
value: number,
format: string,
culture: Culture,
nonScientificOverrideFormat?: string): string {
let result: string;
let numberFormatInfo = culture.numberFormat;
if (isFinite(value)) {
// Split format by positive[;negative;zero] pattern
let formatComponents = getComponents(format);
// Pick a format based on the sign of value
if (value > 0) {
format = formatComponents.positive;
} else if (value === 0) {
format = formatComponents.zero;
} else {
format = formatComponents.negative;
}
// Normalize value if we have an explicit negative format
if (formatComponents.hasNegative)
value = Math.abs(value);
// Get format metadata
let formatMeta = getCustomFormatMetadata(format, true /*calculatePrecision*/);
// Preserve literals and escaped chars
let literals: string[] = [];
if (formatMeta.hasLiterals) {
format = formattingEncoder.preserveLiterals(format, literals);
}
// Scientific format
if (formatMeta.hasE && !nonScientificOverrideFormat) {
let scientificMatch = RegExpExtensions.run(ScientificFormatRegex, format);
if (scientificMatch) {
// Case 2.1. Scientific custom format
let formatM = format.substr(0, scientificMatch.index);
let formatE = format.substr(scientificMatch.index + 2); // E(+|-)
let precision = getCustomFormatPrecision(formatM, formatMeta);
let scale = getCustomFormatScale(formatM, formatMeta);
if (scale !== 1) {
value = value * scale;
}
// Assert that value is a number and fall back on returning value if it is not
if (typeof (value) !== "number")
return String(value);
let s = value.toExponential(precision);
let indexOfE = s.indexOf("e");
let mantissa = s.substr(0, indexOfE);
let exp = s.substr(indexOfE + 1);
let resultM = fuseNumberWithCustomFormat(mantissa, formatM, numberFormatInfo);
let resultE = fuseNumberWithCustomFormat(exp, formatE, numberFormatInfo);
if (resultE.charAt(0) === "+" && scientificMatch[0].charAt(1) !== "+") {
resultE = resultE.substr(1);
}
let e = scientificMatch[0].charAt(0);
result = resultM + e + resultE;
}
}
// Non scientific format
if (result === undefined) {
let valueFormatted: string;
let isValueGlobalized: boolean = false;
let precision = getCustomFormatPrecision(format, formatMeta);
let scale = getCustomFormatScale(format, formatMeta);
if (scale !== 1)
value = value * scale;
// Rounding
value = parseFloat(toNonScientific(value, precision));
if (!isFinite(value)) {
// very large and small finite values can become infinite by parseFloat(toNonScientific())
return Globalize.format(value, undefined);
}
if (nonScientificOverrideFormat) {
// Get numeric format from format string
let numericFormat = numberFormat.getNumericFormat(value, format);
// Add separators and decimalFormat to nonScientificFormat
nonScientificOverrideFormat = getNonScientificFormatWithPrecision(nonScientificOverrideFormat, numericFormat);
// Format the value
valueFormatted = formattingService.format(nonScientificOverrideFormat, [value], culture.name);
isValueGlobalized = true;
}
else
valueFormatted = toNonScientific(value, precision);
result = fuseNumberWithCustomFormat(valueFormatted, format, <any>numberFormatInfo, nonScientificOverrideFormat, isValueGlobalized);
}
if (formatMeta.hasLiterals) {
result = formattingEncoder.restoreLiterals(result, literals, false);
}
_lastCustomFormatMeta = formatMeta;
} else {
return Globalize.format(value, undefined);
}
return result;
}