Skip to content

Commit

Permalink
feat: support literal decorator
Browse files Browse the repository at this point in the history
  • Loading branch information
medikoo committed Jul 2, 2018
1 parent e49808a commit 305278c
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 40 deletions.
47 changes: 29 additions & 18 deletions README.md
Expand Up @@ -8,9 +8,9 @@

## sprintf parser and basic formatter

* Full [printf format parser](#parser)
* Basic (ECMAScript level) modifier [resolvers](#preconfigured-modifiers)
* Format function [generator](#format-function-generator).
- Full [printf format parser](#parser)
- Basic (ECMAScript level) modifier [resolvers](#preconfigured-modifiers)
- Format function [generator](#format-function-generator).

### Installation

Expand Down Expand Up @@ -42,17 +42,17 @@ const data = parse("Some %s with %d count");

`data` spec:

* `literals` - Surrounding string literals
* `placeholders` - Meta data of parsed placholders.
- `literals` - Surrounding string literals
- `placeholders` - Meta data of parsed placholders.
Placeholder properties map (refer to [spec](https://en.wikipedia.org/wiki/Printf_format_string) for explanation of each property)
* `parameter` - (optional) parameter setting (e.g. `1`)
* `flags` - (optional) array of flags (e.g. `["0", "-"]`)
* `width` - (optional) width (e.g. `4` or `"*"` if dynamic)
* `precision` - (optional) precision (e.g. `4` or `"*"` if dynamic)
* `length` - (optional) length (e.g. `"z"`)
* `type` - Modifier type (e.g. `"s"` or `"d"`)
* `content` - Full string representation of placeholder (e.g. `"%s"`)
* `isParameterIndexingValid` - Whether parameter indexing is valid across all placeholders.
- `parameter` - (optional) parameter setting (e.g. `1`)
- `flags` - (optional) array of flags (e.g. `["0", "-"]`)
- `width` - (optional) width (e.g. `4` or `"*"` if dynamic)
- `precision` - (optional) precision (e.g. `4` or `"*"` if dynamic)
- `length` - (optional) length (e.g. `"z"`)
- `type` - Modifier type (e.g. `"s"` or `"d"`)
- `content` - Full string representation of placeholder (e.g. `"%s"`)
- `isParameterIndexingValid` - Whether parameter indexing is valid across all placeholders.
e.g. if no placeholders come with parameters it'll be true. If some but not all of them will come with parameters, it'll be false (if used, then all placeholders should use them).

#### Format function generator
Expand All @@ -75,6 +75,17 @@ format = require("sprintf-kit")({
});

format("Some %s with %d count", "foo", 12, "rest", "args"); // Some foo with 12 count rest args

// Message string literals (all but placeholders text) can be additionally decorated
// Useful when we want to apply some specific color to message without affecting format of special arguments

const clc = require("cli-color");

format = require("sprintf-kit")({
d: require("sprintf-kit/modifiers/d"),
s: require("sprintf-kit/modifiers/s"),
literal: literal => clc.red(literal)
});
```

#### Preconfigured modifiers
Expand All @@ -85,11 +96,11 @@ Modifiers can be found at `sprintf-kit/modifiers` folder.

Preconfigured modifiers

* `d` - Number
* `f` - Floating point value
* `i` - Integer
* `j` - JSON
* `s` - String
- `d` - Number
- `f` - Floating point value
- `i` - Integer
- `j` - JSON
- `s` - String

Every modifier is exception safe, in case of approaching invalid value, adequate error message token is displayed in place of placeholder

Expand Down
53 changes: 31 additions & 22 deletions index.js
@@ -1,6 +1,7 @@
"use strict";

var aFrom = require("es5-ext/array/from")
, identity = require("es5-ext/function/identity")
, ensureObject = require("es5-ext/object/valid-object")
, objForEach = require("es5-ext/object/for-each")
, ensurePlainFunction = require("es5-ext/object/ensure-plain-function")
Expand All @@ -10,7 +11,7 @@ var aFrom = require("es5-ext/array/from")

var slice = Array.prototype.slice;

var customTypes = primitiveSet("rest");
var customTypes = primitiveSet("literal", "rest");

module.exports = function (modifiers) {
objForEach(ensureObject(modifiers), function (value, type) {
Expand All @@ -30,29 +31,37 @@ module.exports = function (modifiers) {

var args = slice.call(arguments, 1);
var skippedArgsLength = 0;
var resolvedString = data.literals.reduce(function (result, literal, index) {
var placeholder = placeholders[index - 1];
var resolvedPlaceholder;
if (placeholder.width === "*") ++skippedArgsLength;
if (placeholder.precision === "*") ++skippedArgsLength;
if (!isParameterIndexingValid) {
resolvedPlaceholder = "[invalid placeholder parameters]";
} else if (modifiers[placeholder.type]) {
if (placeholder.parameter) index = placeholder.parameter;
if (index > args.length) {
resolvedPlaceholder = placeholder.content;
var resolvedString;
if (data.literals.length > 1) {
resolvedString = data.literals.reduce(function (result, literal, index) {
if (index === 1 && modifiers.literal) result = modifiers.literal(result, args);
var placeholder = placeholders[index - 1];
var resolvedPlaceholder;
if (placeholder.width === "*") ++skippedArgsLength;
if (placeholder.precision === "*") ++skippedArgsLength;
if (!isParameterIndexingValid) {
resolvedPlaceholder = "[invalid placeholder parameters]";
} else if (modifiers[placeholder.type]) {
if (placeholder.parameter) index = placeholder.parameter;
if (index > args.length) {
resolvedPlaceholder = placeholder.content;
} else {
index += skippedArgsLength - 1;
var arg = args[index];
resolvedPlaceholder = modifiers[placeholder.type](
arg, placeholder, index, args
);
}
} else {
index += skippedArgsLength - 1;
var arg = args[index];
resolvedPlaceholder = modifiers[placeholder.type](
arg, placeholder, index, args
);
resolvedPlaceholder = placeholder.content;
}
} else {
resolvedPlaceholder = placeholder.content;
}
return result + resolvedPlaceholder + literal;
});
return (
result + resolvedPlaceholder + (modifiers.literal || identity)(literal, args)
);
});
} else {
resolvedString = (modifiers.literal || identity)(data.literals[0]);
}
if (!modifiers.rest || args.length <= placeholders.length + skippedArgsLength) {
return resolvedString;
}
Expand Down
5 changes: 5 additions & 0 deletions test/index.js
Expand Up @@ -9,6 +9,7 @@ test("Should", function (t) {
t.test("Resolve", function (t) {
// eslint-disable-next-line id-length
var resolve = getResolver({ d: modifierD, s: modifierS });
t.equal(resolve("foo raz", "marko"), "foo raz", "No placeholders");
t.equal(resolve("foo %s", "marko"), "foo marko", "Single placeholder");
t.equal(resolve("foo %s %d", "marko", 12), "foo marko 12", "Two placeholders");
t.equal(
Expand Down Expand Up @@ -47,6 +48,10 @@ test("Should", function (t) {
t.equal(resolve(12, 13), "12-13", "Non-string first argument with rest");
t.end();
});
var resolve = getResolver({ d: modifierD, literal: function (str) { return str + "foo"; } });
t.equal(resolve("mar %d ko", 12), "mar foo12 kofoo", "Support 'literal' modifier");
t.equal(resolve("marlo"), "marlofoo", "Support 'literal' modifier with no placeholder");

t.throws(
function () { getResolver({ foo: modifierD }); }, TypeError, "Reject invalid modifiers map"
);
Expand Down

0 comments on commit 305278c

Please sign in to comment.