var Compiler = require('./compiler'); /** A set of utility functions that are called by the compiled Javascript * functions, these are included locally in the output of {@link * MessageFormat#compile compile()}. * * @class * @private * @param {MessageFormat} mf - A MessageFormat instance */ function Runtime(mf) { this.mf = mf; this.setStrictNumber(mf.strictNumberSign); } module.exports = Runtime; /** Utility function for `#` in plural rules * * Will throw an Error if `value` has a non-numeric value and `offset` is * non-zero or {@link MessageFormat#setStrictNumberSign} is set. * * @function Runtime#number * @param {number} value - The value to operate on * @param {string} name - The name of the argument, used for error reporting * @param {number} [offset=0] - An optional offset, set by the surrounding context * @returns {number|string} The result of applying the offset to the input value */ function defaultNumber(value, name, offset) { if (!offset) return value; if (isNaN(value)) throw new Error('Can\'t apply offset:' + offset + ' to argument `' + name + '` with non-numerical value ' + JSON.stringify(value) + '.'); return value - offset; } /** @private */ function strictNumber(value, name, offset) { if (isNaN(value)) throw new Error('Argument `' + name + '` has non-numerical value ' + JSON.stringify(value) + '.'); return value - (offset || 0); } /** Set how strictly the {@link number} method parses its input. * * According to the ICU MessageFormat spec, `#` can only be used to replace a * number input of a `plural` statement. By default, messageformat does not * throw a runtime error if you use non-numeric argument with a `plural` rule, * unless rule also includes a non-zero `offset`. * * This is called by {@link MessageFormat#setStrictNumberSign} to follow the * stricter ICU MessageFormat spec. * * @param {boolean} [enable=false] */ Runtime.prototype.setStrictNumber = function(enable) { this.number = enable ? strictNumber : defaultNumber; } /** Utility function for `{N, plural|selectordinal, ...}` * * @param {number} value - The key to use to find a pluralization rule * @param {number} offset - An offset to apply to `value` * @param {function} lcfunc - A locale function from `pluralFuncs` * @param {Object.<string,string>} data - The object from which results are looked up * @param {?boolean} isOrdinal - If true, use ordinal rather than cardinal rules * @returns {string} The result of the pluralization */ Runtime.prototype.plural = function(value, offset, lcfunc, data, isOrdinal) { if ({}.hasOwnProperty.call(data, value)) return data[value]; if (offset) value -= offset; var key = lcfunc(value, isOrdinal); if (key in data) return data[key]; return data.other; } /** Utility function for `{N, select, ...}` * * @param {number} value - The key to use to find a selection * @param {Object.<string,string>} data - The object from which results are looked up * @returns {string} The result of the select statement */ Runtime.prototype.select = function(value, data) { if ({}.hasOwnProperty.call(data, value)) return data[value]; return data.other; } /** @private */ Runtime.prototype.toString = function(pluralFuncs, compiler) { function _stringify(o, level) { if (typeof o != 'object') { var funcStr = o.toString().replace(/^(function )\w*/, '$1'); var indent = /([ \t]*)\S.*$/.exec(funcStr); return indent ? funcStr.replace(new RegExp('^' + indent[1], 'mg'), '') : funcStr; } var s = []; for (var i in o) { if (level == 0) s.push('var ' + i + ' = ' + _stringify(o[i], level + 1) + ';\n'); else s.push(Compiler.propname(i) + ': ' + _stringify(o[i], level + 1)); } if (level == 0) return s.join(''); if (s.length == 0) return '{}'; var indent = ' '; while (--level) indent += ' '; return '{\n' + s.join(',\n').replace(/^/gm, indent) + '\n}'; } var obj = {}; Object.keys(compiler.locales).forEach(function(lc) { obj[Compiler.funcname(lc)] = pluralFuncs[lc]; }); Object.keys(compiler.runtime).forEach(function(fn) { obj[fn] = this[fn]; }, this); var fmtKeys = Object.keys(compiler.formatters); var fmt = this.mf.fmt; if (fmtKeys.length) obj.fmt = fmtKeys.reduce(function(o, key) { o[key] = fmt[key]; return o; }, {}); return _stringify(obj, 0); }