penguins-eggs
Version:
A remaster system tool, compatible with Almalinux, Alpine, Arch, Debian, Devuan, Fedora, Manjaro, Opensuse, Ubuntu and derivatives
159 lines (158 loc) • 6.19 kB
JavaScript
/**
* sprintf.ts
*
* Converted to a pure, strictly-typed TypeScript module.
*/
export default function sprintf(format, ...args) {
let i = 0;
const regex = /%%|%(\d+\$)?([-+'#0 ]*)(\*\d+\$|\*|\d+)?(\.(\*\d+\$|\*|\d+))?([scboxXuidfegEG])/g;
const pad = (str, len, chr, leftJustify) => {
const padding = str.length >= len ? '' : Array.from({ length: 1 + len - str.length }).join(chr || ' ');
return leftJustify ? str + padding : padding + str;
};
const justify = (value, prefix, leftJustify, minWidth, zeroPad, customPadChar) => {
const diff = minWidth - value.length;
if (diff > 0) {
if (leftJustify || !zeroPad) {
value = pad(value, minWidth, customPadChar || ' ', leftJustify);
}
else {
value = value.slice(0, prefix.length) + pad('', diff, '0', true) + value.slice(prefix.length);
}
}
return value;
};
const formatBaseX = (value, base, prefix, leftJustify, minWidth, precision, zeroPad) => {
const number = value >>> 0;
const p = (prefix && number && { 2: '0b', 8: '0', 16: '0x' }[base]) || '';
const val = p + pad(number.toString(base), precision || 0, '0', false);
return justify(val, p, leftJustify, minWidth, zeroPad);
};
const formatString = (value, leftJustify, minWidth, precision, zeroPad, customPadChar) => {
if (precision !== null && precision !== undefined) {
value = value.slice(0, precision);
}
return justify(value, '', leftJustify, minWidth, zeroPad, customPadChar);
};
const doFormat = (substring, valueIndex, flags, minWidthStr, _, // Explicitly type the unused parameter
precisionStr, type) => {
if (substring === '%%') {
return '%';
}
let leftJustify = false;
let positivePrefix = '';
let zeroPad = false;
let prefixBaseX = false;
let customPadChar = ' ';
for (let j = 0; flags && j < flags.length; j++) {
switch (flags.charAt(j)) {
case ' ': {
positivePrefix = ' ';
break;
}
case '0': {
zeroPad = true;
break;
}
case '#': {
prefixBaseX = true;
break;
}
case "'": {
customPadChar = flags.charAt(j + 1);
break;
}
case '+': {
positivePrefix = '+';
break;
}
case '-': {
leftJustify = true;
break;
}
}
}
let minWidth = minWidthStr ? +minWidthStr : 0;
if (minWidthStr === '*') {
minWidth = +args[i++];
}
else if (minWidthStr?.charAt(0) === '*') {
minWidth = +args[Number.parseInt(minWidthStr.slice(1, -1)) - 1];
}
if (minWidth < 0) {
minWidth = -minWidth;
leftJustify = true;
}
if (!isFinite(minWidth)) {
throw new TypeError('sprintf: (minimum-)width must be finite');
}
let precision = precisionStr ? +precisionStr : undefined;
if (precisionStr === '*') {
precision = +args[i++];
}
else if (precisionStr?.charAt(0) === '*') {
precision = +args[Number.parseInt(precisionStr.slice(1, -1)) - 1];
}
if (precision === undefined) {
precision = 'fFeE'.includes(type) ? 6 : type === 'd' ? 0 : undefined;
}
const value = valueIndex ? args[Number.parseInt(valueIndex.slice(0, -1)) - 1] : args[i++];
switch (type) {
case 'b': {
return formatBaseX(value, 2, prefixBaseX, leftJustify, minWidth, precision, zeroPad);
}
case 'c': {
return formatString(String.fromCharCode(+value), leftJustify, minWidth, precision, zeroPad);
}
case 'd':
case 'i': {
const number = +value | 0;
const prefix = number < 0 ? '-' : positivePrefix;
const val = prefix + pad(String(Math.abs(number)), precision || 0, '0', false);
return justify(val, prefix, leftJustify, minWidth, zeroPad);
}
case 'e':
case 'E':
case 'f':
case 'F':
case 'g':
case 'G': {
{
const number = +value;
const prefix = number < 0 ? '-' : positivePrefix;
const method = ['toExponential', 'toFixed', 'toPrecision']['efg'.indexOf(type.toLowerCase())];
const textTransform = ['toString', 'toUpperCase']['eEfFgG'.indexOf(type) % 2];
const val = prefix + Math.abs(number)[method](precision);
return justify(val, prefix, leftJustify, minWidth, zeroPad)[textTransform]();
}
}
case 'o': {
{
return formatBaseX(value, 8, prefixBaseX, leftJustify, minWidth, precision, zeroPad);
}
}
case 's': {
{
return formatString(String(value), leftJustify, minWidth, precision, zeroPad, customPadChar);
}
}
case 'u': {
{
return formatBaseX(value, 10, prefixBaseX, leftJustify, minWidth, precision, zeroPad);
}
}
case 'x': {
{
return formatBaseX(value, 16, prefixBaseX, leftJustify, minWidth, precision, zeroPad);
}
}
case 'X': {
return formatBaseX(value, 16, prefixBaseX, leftJustify, minWidth, precision, zeroPad).toUpperCase();
}
default: {
return substring;
}
}
};
return format.replaceAll(regex, doFormat);
}