Skip to content

Commit

Permalink
util: change %d to format a integer, add %i and %f
Browse files Browse the repository at this point in the history
This change brings formatting specifiers available in `util.format` and
consequently, `console.*` closer to what is supported in all major
browsers. There is a breaking change with the `%d` specifier which
previously served a double purpose of formatting both integer and
floats. With this change, it will format only as integer.

- `%d` is being changed to format only as integer.
- `%i` is introduced as an alias to `%d`.
- `%f` is introduced to format floating point values.

When updating code, all instances of `%d` format strings that
were supplied with floats should be changed to the `%f` format string.

Fixes: nodejs#10292
  • Loading branch information
silverwind committed Mar 25, 2017
1 parent ed12ea3 commit 04143cf
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 11 deletions.
3 changes: 2 additions & 1 deletion doc/api/util.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,8 @@ Each placeholder token is replaced with the converted value from the
corresponding argument. Supported placeholders are:

* `%s` - String.
* `%d` - Number (both integer and float).
* `%d` or `%i` - Integer.
* `%f` - Floating point value.
* `%j` - JSON. Replaced with the string `'[Circular]'` if the argument
contains circular references.
* `%%` - single percent sign (`'%'`). This does not consume an argument.
Expand Down
11 changes: 10 additions & 1 deletion lib/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,20 @@ exports.format = function(f) {
if (f.charCodeAt(i) === 37/*'%'*/ && i + 1 < f.length) {
switch (f.charCodeAt(i + 1)) {
case 100: // 'd'
case 105: // 'i'
if (a >= argLen)
break;
if (lastPos < i)
str += f.slice(lastPos, i);
str += Number(arguments[a++]);
str += parseInt(arguments[a++]);
lastPos = i = i + 2;
continue;
case 102: // 'f'
if (a >= argLen)
break;
if (lastPos < i)
str += f.slice(lastPos, i);
str += parseFloat(arguments[a++]);
lastPos = i = i + 2;
continue;
case 106: // 'j'
Expand Down
44 changes: 35 additions & 9 deletions test/parallel/test-util-format.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,21 +48,49 @@ assert.throws(function() {
util.format('%d', symbol);
}, TypeError);

// Integer format specifier
assert.strictEqual(util.format('%d'), '%d');
assert.strictEqual(util.format('%d', 42.0), '42');
assert.strictEqual(util.format('%d', 42), '42');
assert.strictEqual(util.format('%s', 42), '42');
assert.strictEqual(util.format('%j', 42), '42');

assert.strictEqual(util.format('%d', '42.0'), '42');
assert.strictEqual(util.format('%d', '42'), '42');
assert.strictEqual(util.format('%s', '42'), '42');
assert.strictEqual(util.format('%j', '42'), '"42"');
assert.strictEqual(util.format('%d', '42.0'), '42');
assert.strictEqual(util.format('%d', 1.5), '1');
assert.strictEqual(util.format('%d', -0.5), '0');
assert.strictEqual(util.format('%d', ''), 'NaN');
assert.strictEqual(util.format('%i'), '%i');
assert.strictEqual(util.format('%i', 42.0), '42');
assert.strictEqual(util.format('%i', 42), '42');
assert.strictEqual(util.format('%i', '42'), '42');
assert.strictEqual(util.format('%i', '42.0'), '42');
assert.strictEqual(util.format('%i', 1.5), '1');
assert.strictEqual(util.format('%i', -0.5), '0');
assert.strictEqual(util.format('%i', ''), 'NaN');

assert.strictEqual(util.format('%%s%s', 'foo'), '%sfoo');
// Float format specifier
assert.strictEqual(util.format('%f'), '%f');
assert.strictEqual(util.format('%f', 42.0), '42');
assert.strictEqual(util.format('%f', 42), '42');
assert.strictEqual(util.format('%f', '42'), '42');
assert.strictEqual(util.format('%f', '42.0'), '42');
assert.strictEqual(util.format('%f', 1.5), '1.5');
assert.strictEqual(util.format('%f', -0.5), '-0.5');
assert.strictEqual(util.format('%f', Math.PI), '3.141592653589793');
assert.strictEqual(util.format('%f', ''), 'NaN');

// String format specifier
assert.strictEqual(util.format('%s'), '%s');
assert.strictEqual(util.format('%s', undefined), 'undefined');
assert.strictEqual(util.format('%s', 'foo'), 'foo');
assert.strictEqual(util.format('%s', 42), '42');
assert.strictEqual(util.format('%s', '42'), '42');

// JSON format specifier
assert.strictEqual(util.format('%j'), '%j');
assert.strictEqual(util.format('%j', 42), '42');
assert.strictEqual(util.format('%j', '42'), '"42"');

// Various format specifiers
assert.strictEqual(util.format('%%s%s', 'foo'), '%sfoo');
assert.strictEqual(util.format('%s:%s'), '%s:%s');
assert.strictEqual(util.format('%s:%s', undefined), 'undefined:%s');
assert.strictEqual(util.format('%s:%s', 'foo'), 'foo:%s');
Expand All @@ -71,11 +99,9 @@ assert.strictEqual(util.format('%s:%s', 'foo', 'bar', 'baz'), 'foo:bar baz');
assert.strictEqual(util.format('%%%s%%', 'hi'), '%hi%');
assert.strictEqual(util.format('%%%s%%%%', 'hi'), '%hi%%');
assert.strictEqual(util.format('%sbc%%def', 'a'), 'abc%def');

assert.strictEqual(util.format('%d:%d', 12, 30), '12:30');
assert.strictEqual(util.format('%d:%d', 12), '12:%d');
assert.strictEqual(util.format('%d:%d'), '%d:%d');

assert.strictEqual(util.format('o: %j, a: %j', {}, []), 'o: {}, a: []');
assert.strictEqual(util.format('o: %j, a: %j', {}), 'o: {}, a: %j');
assert.strictEqual(util.format('o: %j, a: %j'), 'o: %j, a: %j');
Expand Down

0 comments on commit 04143cf

Please sign in to comment.