127 lines
2.7 KiB
JavaScript
127 lines
2.7 KiB
JavaScript
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
const json = require('./json');
|
|
|
|
const RE = /%(-?\d+)?(\.-?\d+)?(:\d+)?(%|(\([^\)]+\))?([sdOj\?]))/g;
|
|
|
|
const toString = Object.prototype.toString;
|
|
function type(x) {
|
|
return toString.call(x).slice(8, -1).toLowerCase();
|
|
}
|
|
|
|
function pad(str, value) {
|
|
var isRight = false;
|
|
|
|
if(value < 0) {
|
|
isRight = true;
|
|
value = -value;
|
|
}
|
|
|
|
if(str.length < value) {
|
|
var padding = new Array(value - str.length + 1).join(' ');
|
|
return isRight ? str + padding : padding + str;
|
|
} else{
|
|
return str;
|
|
}
|
|
}
|
|
|
|
function truncate(str, value) {
|
|
if(value > 0) {// truncate from begining
|
|
return str.slice(-value);
|
|
} else {// truncate from end
|
|
return str.slice(0, -value);
|
|
}
|
|
}
|
|
|
|
function defaultFmt(x) {
|
|
switch (type(x)) {
|
|
case 'arguments':
|
|
case 'object':
|
|
return json(x);
|
|
default:
|
|
return String(x);
|
|
}
|
|
}
|
|
|
|
function printfNextValue(format, nextValFn) {
|
|
var str = String(format).replace(RE,
|
|
function(match, padding, trunc, indent, kind, name, type) {
|
|
|
|
if (kind === '%') {
|
|
return '%';
|
|
}
|
|
|
|
var val = nextValFn(name);
|
|
|
|
|
|
var fmt = '';
|
|
|
|
switch (type) {
|
|
case 's':
|
|
fmt = String(val);
|
|
break;
|
|
case 'd':
|
|
fmt = String(Number(val));
|
|
break;
|
|
case 'O':
|
|
case 'j':
|
|
fmt = json(val, indent && parseInt(indent.slice(1), 10));
|
|
break;
|
|
case '?':
|
|
fmt = defaultFmt(val);
|
|
break;
|
|
}
|
|
|
|
if (trunc !== undefined) {
|
|
fmt = truncate(fmt, trunc.slice(1));
|
|
}
|
|
|
|
if (padding !== undefined) {
|
|
fmt = pad(fmt, padding);
|
|
}
|
|
|
|
return fmt;
|
|
});
|
|
return str;
|
|
}
|
|
|
|
function printfObj(format, obj) {
|
|
return printfNextValue(format, function(name) {
|
|
name = name && name.slice(1, -1);
|
|
return obj[name];
|
|
});
|
|
}
|
|
|
|
function printfArgs(format, args) {
|
|
var i = 0;
|
|
var len = args.length;
|
|
var str = printfNextValue(format, function() {
|
|
return args[i++];
|
|
});
|
|
if (len > 0) {
|
|
for (var x = args[i]; i < len; x = args[++i]) {
|
|
str += ' ' + defaultFmt(x);
|
|
}
|
|
}
|
|
|
|
return str;
|
|
}
|
|
|
|
// Usage:
|
|
// printf('I am %d %s old', 4, 'years');
|
|
// printf('%(name)s: %:2(message)j', { name: 'foo', message: { foo: 'bar' }});
|
|
const OBJECT_FMT = /%([:\-]?\d+)?\([^\)]+\)[sdjO\?]/;
|
|
module.exports = function printf(format, obj/*, ..args*/) {
|
|
if (!OBJECT_FMT.test(format)) {
|
|
var args = new Array(arguments.length - 1);
|
|
for (var i = 0; i < args.length; i++) {
|
|
args[i] = arguments[i + 1];
|
|
}
|
|
return printfArgs(format, args);
|
|
} else {
|
|
return printfObj(format, obj);
|
|
}
|
|
};
|