@ultraq/icu-message-formatter 0.12.0-beta.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,3 @@
1
- import _slicedToArray from '@babel/runtime/helpers/slicedToArray';
2
- import _classCallCheck from '@babel/runtime/helpers/classCallCheck';
3
- import _createClass from '@babel/runtime/helpers/createClass';
4
1
  import _defineProperty from '@babel/runtime/helpers/defineProperty';
5
2
  import { flatten } from '@ultraq/array-utils';
6
3
  import { memoize } from '@ultraq/function-utils';
@@ -22,389 +19,380 @@ import { memoize } from '@ultraq/function-utils';
22
19
  */
23
20
 
24
21
  /**
25
- * Most branch-based type handlers are based around "cases".
26
- * For example, `select` and `plural` compare compare a value
27
- * to "case keys" to choose a subtranslation.
22
+ * @typedef ParseCasesResult
23
+ * @property {string[]} args
24
+ * A list of prepended arguments.
25
+ * @property {Record<string,string>} cases
26
+ * A map of all cases.
27
+ */
28
+
29
+ /**
30
+ * Most branch-based type handlers are based around "cases". For example,
31
+ * `select` and `plural` compare compare a value to "case keys" to choose a
32
+ * subtranslation.
28
33
  *
29
- * This util splits "matches" portions provided to the aforementioned
30
- * handlers into case strings, and extracts any prepended arguments
31
- * (for example, `plural` supports an `offset:n` argument used for
32
- * populating the magic `#` variable).
34
+ * This util splits "matches" portions provided to the aforementioned handlers
35
+ * into case strings, and extracts any prepended arguments (for example,
36
+ * `plural` supports an `offset:n` argument used for populating the magic `#`
37
+ * variable).
33
38
  *
34
- * @param {String} string
35
- * @return {Object} The `cases` key points to a map of all cases.
36
- * The `arguments` key points to a list of prepended arguments.
39
+ * @param {string} string
40
+ * @return {ParseCasesResult}
37
41
  */
38
42
  function parseCases(string) {
39
- var isWhitespace = function isWhitespace(ch) {
40
- return /\s/.test(ch);
41
- };
42
-
43
- var args = [];
44
- var cases = {};
45
- var currTermStart = 0;
46
- var latestTerm = null;
47
- var inTerm = false;
48
- var i = 0;
49
-
43
+ const isWhitespace = ch => /\s/.test(ch);
44
+ const args = [];
45
+ const cases = {};
46
+ let currTermStart = 0;
47
+ let latestTerm = null;
48
+ let inTerm = false;
49
+ let i = 0;
50
50
  while (i < string.length) {
51
51
  // Term ended
52
52
  if (inTerm && (isWhitespace(string[i]) || string[i] === '{')) {
53
53
  inTerm = false;
54
- latestTerm = string.slice(currTermStart, i); // We want to process the opening char again so the case will be properly registered.
54
+ latestTerm = string.slice(currTermStart, i);
55
55
 
56
+ // We want to process the opening char again so the case will be properly registered.
56
57
  if (string[i] === '{') {
57
58
  i--;
58
59
  }
59
- } // New term
60
+ }
61
+
62
+ // New term
60
63
  else if (!inTerm && !isWhitespace(string[i])) {
61
- var caseBody = string[i] === '{'; // If there's a previous term, we can either handle a whole
62
- // case, or add that as an argument.
64
+ const caseBody = string[i] === '{';
63
65
 
66
+ // If there's a previous term, we can either handle a whole
67
+ // case, or add that as an argument.
64
68
  if (latestTerm && caseBody) {
65
- var branchEndIndex = findClosingBracket(string, i);
66
-
69
+ const branchEndIndex = findClosingBracket(string, i);
67
70
  if (branchEndIndex === -1) {
68
- throw new Error("Unbalanced curly braces in string: \"".concat(string, "\""));
71
+ throw new Error(`Unbalanced curly braces in string: "${string}"`);
69
72
  }
70
-
71
73
  cases[latestTerm] = string.slice(i + 1, branchEndIndex); // Don't include the braces
72
74
 
73
75
  i = branchEndIndex; // Will be moved up where needed at end of loop.
74
-
75
76
  latestTerm = null;
76
77
  } else {
77
78
  if (latestTerm) {
78
79
  args.push(latestTerm);
79
80
  latestTerm = null;
80
81
  }
81
-
82
82
  inTerm = true;
83
83
  currTermStart = i;
84
84
  }
85
85
  }
86
-
87
86
  i++;
88
87
  }
89
-
90
88
  if (inTerm) {
91
89
  latestTerm = string.slice(currTermStart);
92
90
  }
93
-
94
91
  if (latestTerm) {
95
92
  args.push(latestTerm);
96
93
  }
97
-
98
94
  return {
99
- args: args,
100
- cases: cases
95
+ args,
96
+ cases
101
97
  };
102
98
  }
99
+
103
100
  /**
104
101
  * Finds the index of the matching closing curly bracket, including through
105
102
  * strings that could have nested brackets.
106
103
  *
107
- * @param {String} string
108
- * @param {Number} fromIndex
109
- * @return {Number} The index of the matching closing bracket, or -1 if no
110
- * closing bracket could be found.
104
+ * @param {string} string
105
+ * @param {number} fromIndex
106
+ * @return {number}
107
+ * The index of the matching closing bracket, or -1 if no closing bracket
108
+ * could be found.
111
109
  */
112
-
113
110
  function findClosingBracket(string, fromIndex) {
114
- var depth = 0;
115
-
116
- for (var i = fromIndex + 1; i < string.length; i++) {
117
- var char = string.charAt(i);
118
-
111
+ let depth = 0;
112
+ for (let i = fromIndex + 1; i < string.length; i++) {
113
+ let char = string.charAt(i);
119
114
  if (char === '}') {
120
115
  if (depth === 0) {
121
116
  return i;
122
117
  }
123
-
124
118
  depth--;
125
119
  } else if (char === '{') {
126
120
  depth++;
127
121
  }
128
122
  }
129
-
130
123
  return -1;
131
124
  }
125
+
132
126
  /**
133
127
  * Split a `{key, type, format}` block into those 3 parts, taking into account
134
128
  * nested message syntax that can exist in the `format` part.
135
129
  *
136
- * @param {String} block
137
- * @return {Array}
130
+ * @param {string} block
131
+ * @return {string[]}
138
132
  * An array with `key`, `type`, and `format` items in that order, if present
139
133
  * in the formatted argument block.
140
134
  */
141
-
142
135
  function splitFormattedArgument(block) {
143
136
  return split(block.slice(1, -1), ',', 3);
144
137
  }
138
+
145
139
  /**
146
140
  * Like `String.prototype.split()` but where the limit parameter causes the
147
141
  * remainder of the string to be grouped together in a final entry.
148
142
  *
149
143
  * @private
150
- * @param {String} string
151
- * @param {String} separator
152
- * @param {Number} limit
153
- * @param {Array} [accumulator=[]]
154
- * @return {Array}
144
+ * @param {string} string
145
+ * @param {string} separator
146
+ * @param {number} limit
147
+ * @param {string[]} accumulator
148
+ * @return {string[]}
155
149
  */
156
-
157
150
  function split(string, separator, limit) {
158
- var accumulator = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : [];
159
-
151
+ let accumulator = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : [];
160
152
  if (!string) {
161
153
  return accumulator;
162
154
  }
163
-
164
155
  if (limit === 1) {
165
156
  accumulator.push(string);
166
157
  return accumulator;
167
158
  }
168
-
169
- var indexOfDelimiter = string.indexOf(separator);
170
-
159
+ let indexOfDelimiter = string.indexOf(separator);
171
160
  if (indexOfDelimiter === -1) {
172
161
  accumulator.push(string);
173
162
  return accumulator;
174
163
  }
175
-
176
- var head = string.substring(0, indexOfDelimiter).trim();
177
- var tail = string.substring(indexOfDelimiter + separator.length + 1).trim();
164
+ let head = string.substring(0, indexOfDelimiter).trim();
165
+ let tail = string.substring(indexOfDelimiter + separator.length + 1).trim();
178
166
  accumulator.push(head);
179
167
  return split(tail, separator, limit - 1, accumulator);
180
168
  }
181
169
 
170
+ /**
171
+ * @typedef {Record<string,any>} FormatValues
172
+ */
173
+
174
+ /**
175
+ * @callback ProcessFunction
176
+ * @param {string} message
177
+ * @param {FormatValues} [values={}]
178
+ * @return {any[]}
179
+ */
180
+
181
+ /**
182
+ * @callback TypeHandler
183
+ * @param {any} value
184
+ * The object which matched the key of the block being processed.
185
+ * @param {string} matches
186
+ * Any format options associated with the block being processed.
187
+ * @param {string} locale
188
+ * The locale to use for formatting.
189
+ * @param {FormatValues} values
190
+ * The object of placeholder data given to the original `format`/`process`
191
+ * call.
192
+ * @param {ProcessFunction} process
193
+ * The `process` function itself so that sub-messages can be processed by type
194
+ * handlers.
195
+ * @return {any | any[]}
196
+ */
197
+
182
198
  /**
183
199
  * The main class for formatting messages.
184
200
  *
185
201
  * @author Emanuel Rabina
186
202
  */
187
-
188
- var MessageFormatter = /*#__PURE__*/function () {
203
+ class MessageFormatter {
189
204
  /**
190
205
  * Creates a new formatter that can work using any of the custom type handlers
191
206
  * you register.
192
207
  *
193
- * @param {String} locale
194
- * @param {Object} [typeHandlers={}]
208
+ * @param {string} locale
209
+ * @param {Record<string,TypeHandler>} [typeHandlers]
195
210
  * Optional object where the keys are the names of the types to register,
196
211
  * their values being the functions that will return a nicely formatted
197
212
  * string for the data and locale they are given.
198
213
  */
199
- function MessageFormatter(locale) {
214
+ constructor(locale) {
200
215
  var _this = this;
201
-
202
- var typeHandlers = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
203
-
204
- _classCallCheck(this, MessageFormatter);
205
-
216
+ let typeHandlers = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
217
+ /**
218
+ * Formats an ICU message syntax string using `values` for placeholder data
219
+ * and any currently-registered type handlers.
220
+ *
221
+ * @type {(message: string, values?: FormatValues) => string}
222
+ */
206
223
  _defineProperty(this, "format", memoize(function (message) {
207
- var values = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
224
+ let values = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
208
225
  return flatten(_this.process(message, values)).join('');
209
226
  }));
210
-
211
227
  this.locale = locale;
212
228
  this.typeHandlers = typeHandlers;
213
229
  }
214
230
  /**
215
- * Formats an ICU message syntax string using `values` for placeholder data
216
- * and any currently-registered type handlers.
231
+ * Process an ICU message syntax string using `values` for placeholder data
232
+ * and any currently-registered type handlers. The result of this method is
233
+ * an array of the component parts after they have been processed in turn by
234
+ * their own type handlers. This raw output is useful for other renderers,
235
+ * eg: React where components can be used instead of being forced to return
236
+ * raw strings.
237
+ *
238
+ * This method is used by {@link MessageFormatter#format} where it acts as a
239
+ * string renderer.
217
240
  *
218
- * @param {String} message
219
- * @param {Object} [values={}]
220
- * @return {String}
241
+ * @param {string} message
242
+ * @param {FormatValues} [values]
243
+ * @return {any[]}
221
244
  */
222
-
223
-
224
- _createClass(MessageFormatter, [{
225
- key: "process",
226
- value:
227
- /**
228
- * Process an ICU message syntax string using `values` for placeholder data
229
- * and any currently-registered type handlers. The result of this method is
230
- * an array of the component parts after they have been processed in turn by
231
- * their own type handlers. This raw output is useful for other renderers,
232
- * eg: React where components can be used instead of being forced to return
233
- * raw strings.
234
- *
235
- * This method is used by {@link MessageFormatter#format} where it acts as a
236
- * string renderer.
237
- *
238
- * @param {String} message
239
- * @param {Object} [values={}]
240
- * @return {Array}
241
- */
242
- function process(message) {
243
- var values = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
244
-
245
- if (!message) {
246
- return [];
247
- }
248
-
249
- var blockStartIndex = message.indexOf('{');
250
-
251
- if (blockStartIndex !== -1) {
252
- var blockEndIndex = findClosingBracket(message, blockStartIndex);
253
-
254
- if (blockEndIndex !== -1) {
255
- var block = message.substring(blockStartIndex, blockEndIndex + 1);
256
-
257
- if (block) {
258
- var result = [];
259
- var head = message.substring(0, blockStartIndex);
260
-
261
- if (head) {
262
- result.push(head);
263
- }
264
-
265
- var _splitFormattedArgume = splitFormattedArgument(block),
266
- _splitFormattedArgume2 = _slicedToArray(_splitFormattedArgume, 3),
267
- key = _splitFormattedArgume2[0],
268
- type = _splitFormattedArgume2[1],
269
- format = _splitFormattedArgume2[2];
270
-
271
- var body = values[key];
272
-
273
- if (body === null || body === undefined) {
274
- body = '';
275
- }
276
-
277
- var typeHandler = type && this.typeHandlers[type];
278
- result.push(typeHandler ? typeHandler(body, format, this.locale, values, this.process.bind(this)) : body);
279
- var tail = message.substring(blockEndIndex + 1);
280
-
281
- if (tail) {
282
- result.push(this.process(tail, values));
283
- }
284
-
285
- return result;
245
+ process(message) {
246
+ let values = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
247
+ if (!message) {
248
+ return [];
249
+ }
250
+ let blockStartIndex = message.indexOf('{');
251
+ if (blockStartIndex !== -1) {
252
+ let blockEndIndex = findClosingBracket(message, blockStartIndex);
253
+ if (blockEndIndex !== -1) {
254
+ let block = message.substring(blockStartIndex, blockEndIndex + 1);
255
+ if (block) {
256
+ let result = [];
257
+ let head = message.substring(0, blockStartIndex);
258
+ if (head) {
259
+ result.push(head);
286
260
  }
287
- } else {
288
- throw new Error("Unbalanced curly braces in string: \"".concat(message, "\""));
261
+ let [key, type, format] = splitFormattedArgument(block);
262
+ let body = values[key];
263
+ if (body === null || body === undefined) {
264
+ body = '';
265
+ }
266
+ let typeHandler = type && this.typeHandlers[type];
267
+ result.push(typeHandler ? typeHandler(body, format, this.locale, values, this.process.bind(this)) : body);
268
+ let tail = message.substring(blockEndIndex + 1);
269
+ if (tail) {
270
+ result.push(this.process(tail, values));
271
+ }
272
+ return result;
289
273
  }
274
+ } else {
275
+ throw new Error(`Unbalanced curly braces in string: "${message}"`);
290
276
  }
291
-
292
- return [message];
293
277
  }
294
- }]);
278
+ return [message];
279
+ }
280
+ }
295
281
 
296
- return MessageFormatter;
297
- }();
282
+ /*
283
+ * Copyright 2019, Emanuel Rabina (http://www.ultraq.net.nz/)
284
+ *
285
+ * Licensed under the Apache License, Version 2.0 (the "License");
286
+ * you may not use this file except in compliance with the License.
287
+ * You may obtain a copy of the License at
288
+ *
289
+ * http://www.apache.org/licenses/LICENSE-2.0
290
+ *
291
+ * Unless required by applicable law or agreed to in writing, software
292
+ * distributed under the License is distributed on an "AS IS" BASIS,
293
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
294
+ * See the License for the specific language governing permissions and
295
+ * limitations under the License.
296
+ */
298
297
 
299
- function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
298
+ let pluralFormatter;
299
+ let keyCounter = 0;
300
300
 
301
- function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
302
- var pluralFormatter;
303
- var keyCounter = 0; // All the special keywords that can be used in `plural` blocks for the various branches
301
+ // All the special keywords that can be used in `plural` blocks for the various branches
302
+ const ONE = 'one';
303
+ const OTHER$1 = 'other';
304
304
 
305
- var ONE = 'one';
306
- var OTHER$1 = 'other';
307
305
  /**
308
306
  * @private
309
- * @param {String} caseBody
310
- * @param {Number} value
311
- * @return {Object} {caseBody: string, numberValues: object}
307
+ * @param {string} caseBody
308
+ * @param {number} value
309
+ * @return {{caseBody: string, numberValues: object}}
312
310
  */
313
-
314
311
  function replaceNumberSign(caseBody, value) {
315
- var i = 0;
316
- var output = '';
317
- var numBraces = 0;
318
- var numberValues = {};
319
-
312
+ let i = 0;
313
+ let output = '';
314
+ let numBraces = 0;
315
+ const numberValues = {};
320
316
  while (i < caseBody.length) {
321
317
  if (caseBody[i] === '#' && !numBraces) {
322
- var keyParam = "__hashToken".concat(keyCounter++);
323
- output += "{".concat(keyParam, ", number}");
318
+ let keyParam = `__hashToken${keyCounter++}`;
319
+ output += `{${keyParam}, number}`;
324
320
  numberValues[keyParam] = value;
325
321
  } else {
326
322
  output += caseBody[i];
327
323
  }
328
-
329
324
  if (caseBody[i] === '{') {
330
325
  numBraces++;
331
326
  } else if (caseBody[i] === '}') {
332
327
  numBraces--;
333
328
  }
334
-
335
329
  i++;
336
330
  }
337
-
338
331
  return {
339
332
  caseBody: output,
340
- numberValues: numberValues
333
+ numberValues
341
334
  };
342
335
  }
336
+
343
337
  /**
344
338
  * Handler for `plural` statements within ICU message syntax strings. Returns
345
339
  * a formatted string for the branch that closely matches the current value.
346
340
  *
347
341
  * See https://formatjs.io/docs/core-concepts/icu-syntax#plural-format for more
348
342
  * details on how the `plural` statement works.
349
- *
350
- * @param {String} value
351
- * @param {String} matches
352
- * @param {String} locale
353
- * @param {String} values
354
- * @param {Function} format
355
- * @return {String}
343
+ *
344
+ * @param {string} value
345
+ * @param {string} matches
346
+ * @param {string} locale
347
+ * @param {Record<string,any>} values
348
+ * @param {(message: string, values?: Record<string,any>) => any[]} process
349
+ * @return {any | any[]}
356
350
  */
357
-
358
-
359
351
  function pluralTypeHandler(value) {
360
- var matches = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
361
- var locale = arguments.length > 2 ? arguments[2] : undefined;
362
- var values = arguments.length > 3 ? arguments[3] : undefined;
363
- var format = arguments.length > 4 ? arguments[4] : undefined;
364
-
365
- var _parseCases = parseCases(matches),
366
- args = _parseCases.args,
367
- cases = _parseCases.cases;
368
-
369
- var intValue = parseInt(value);
370
- args.forEach(function (arg) {
352
+ let matches = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
353
+ let locale = arguments.length > 2 ? arguments[2] : undefined;
354
+ let values = arguments.length > 3 ? arguments[3] : undefined;
355
+ let process = arguments.length > 4 ? arguments[4] : undefined;
356
+ const {
357
+ args,
358
+ cases
359
+ } = parseCases(matches);
360
+ let intValue = parseInt(value);
361
+ args.forEach(arg => {
371
362
  if (arg.startsWith('offset:')) {
372
363
  intValue -= parseInt(arg.slice('offset:'.length));
373
364
  }
374
365
  });
375
- var keywordPossibilities = [];
376
-
366
+ const keywordPossibilities = [];
377
367
  if ('PluralRules' in Intl) {
378
368
  // Effectively memoize because instantiation of `Int.*` objects is expensive.
379
369
  if (pluralFormatter === undefined || pluralFormatter.resolvedOptions().locale !== locale) {
380
370
  pluralFormatter = new Intl.PluralRules(locale);
381
371
  }
372
+ const pluralKeyword = pluralFormatter.select(intValue);
382
373
 
383
- var pluralKeyword = pluralFormatter.select(intValue); // Other is always added last with least priority, so we don't want to add it here.
384
-
374
+ // Other is always added last with least priority, so we don't want to add it here.
385
375
  if (pluralKeyword !== OTHER$1) {
386
376
  keywordPossibilities.push(pluralKeyword);
387
377
  }
388
378
  }
389
-
390
379
  if (intValue === 1) {
391
380
  keywordPossibilities.push(ONE);
392
381
  }
393
-
394
- keywordPossibilities.push("=".concat(intValue), OTHER$1);
395
-
396
- for (var i = 0; i < keywordPossibilities.length; i++) {
397
- var keyword = keywordPossibilities[i];
398
-
382
+ keywordPossibilities.push(`=${intValue}`, OTHER$1);
383
+ for (let i = 0; i < keywordPossibilities.length; i++) {
384
+ const keyword = keywordPossibilities[i];
399
385
  if (keyword in cases) {
400
- var _replaceNumberSign = replaceNumberSign(cases[keyword], intValue),
401
- caseBody = _replaceNumberSign.caseBody,
402
- numberValues = _replaceNumberSign.numberValues;
403
-
404
- return format(caseBody, _objectSpread(_objectSpread({}, values), numberValues));
386
+ const {
387
+ caseBody,
388
+ numberValues
389
+ } = replaceNumberSign(cases[keyword], intValue);
390
+ return process(caseBody, {
391
+ ...values,
392
+ ...numberValues
393
+ });
405
394
  }
406
395
  }
407
-
408
396
  return value;
409
397
  }
410
398
 
@@ -423,7 +411,9 @@ function pluralTypeHandler(value) {
423
411
  * See the License for the specific language governing permissions and
424
412
  * limitations under the License.
425
413
  */
426
- var OTHER = 'other';
414
+
415
+ const OTHER = 'other';
416
+
427
417
  /**
428
418
  * Handler for `select` statements within ICU message syntax strings. Returns
429
419
  * a formatted string for the branch that closely matches the current value.
@@ -431,28 +421,25 @@ var OTHER = 'other';
431
421
  * See https://formatjs.io/docs/core-concepts/icu-syntax#select-format for more
432
422
  * details on how the `select` statement works.
433
423
  *
434
- * @param {String} value
435
- * @param {String} matches
436
- * @param {String} locale
437
- * @param {String} values
438
- * @param {Function} format
439
- * @return {String}
424
+ * @param {string} value
425
+ * @param {string} matches
426
+ * @param {string} locale
427
+ * @param {Record<string,any>} values
428
+ * @param {(message: string, values?: Record<string,any>) => any[]} process
429
+ * @return {any | any[]}
440
430
  */
441
-
442
431
  function selectTypeHandler(value) {
443
- var matches = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
444
- var values = arguments.length > 3 ? arguments[3] : undefined;
445
- var format = arguments.length > 4 ? arguments[4] : undefined;
446
-
447
- var _parseCases = parseCases(matches),
448
- cases = _parseCases.cases;
449
-
432
+ let matches = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
433
+ let values = arguments.length > 3 ? arguments[3] : undefined;
434
+ let process = arguments.length > 4 ? arguments[4] : undefined;
435
+ const {
436
+ cases
437
+ } = parseCases(matches);
450
438
  if (value in cases) {
451
- return format(cases[value], values);
439
+ return process(cases[value], values);
452
440
  } else if (OTHER in cases) {
453
- return format(cases[OTHER], values);
441
+ return process(cases[OTHER], values);
454
442
  }
455
-
456
443
  return value;
457
444
  }
458
445