UNPKG

string-format

Version:

String formatting inspired by Python's str.format()

97 lines (85 loc) 3.08 kB
void function(global) { 'use strict'; // ValueError :: String -> Error function ValueError(message) { var err = new Error(message); err.name = 'ValueError'; return err; } // create :: Object -> String,*... -> String function create(transformers) { return function(template) { var args = Array.prototype.slice.call(arguments, 1); var idx = 0; var state = 'UNDEFINED'; return template.replace( /([{}])\1|[{](.*?)(?:!(.+?))?[}]/g, function(match, literal, _key, xf) { if (literal != null) { return literal; } var key = _key; if (key.length > 0) { if (state === 'IMPLICIT') { throw ValueError('cannot switch from ' + 'implicit to explicit numbering'); } state = 'EXPLICIT'; } else { if (state === 'EXPLICIT') { throw ValueError('cannot switch from ' + 'explicit to implicit numbering'); } state = 'IMPLICIT'; key = String(idx); idx += 1; } // 1. Split the key into a lookup path. // 2. If the first path component is not an index, prepend '0'. // 3. Reduce the lookup path to a single result. If the lookup // succeeds the result is a singleton array containing the // value at the lookup path; otherwise the result is []. // 4. Unwrap the result by reducing with '' as the default value. var path = key.split('.'); var value = (/^\d+$/.test(path[0]) ? path : ['0'].concat(path)) .reduce(function(maybe, key) { return maybe.reduce(function(_, x) { return x != null && key in Object(x) ? [typeof x[key] === 'function' ? x[key]() : x[key]] : []; }, []); }, [args]) .reduce(function(_, x) { return x; }, ''); if (xf == null) { return value; } else if (Object.prototype.hasOwnProperty.call(transformers, xf)) { return transformers[xf](value); } else { throw ValueError('no transformer named "' + xf + '"'); } } ); }; } // format :: String,*... -> String var format = create({}); // format.create :: Object -> String,*... -> String format.create = create; // format.extend :: Object,Object -> () format.extend = function(prototype, transformers) { var $format = create(transformers); prototype.format = function() { var args = Array.prototype.slice.call(arguments); args.unshift(this); return $format.apply(global, args); }; }; /* istanbul ignore else */ if (typeof module !== 'undefined') { module.exports = format; } else if (typeof define === 'function' && define.amd) { define(function() { return format; }); } else { global.format = format; } }.call(this, this);