globalize-rpk 1.7.0 → 1.7.1

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.
Files changed (74) hide show
  1. package/globalize/currency.js +590 -0
  2. package/globalize/date.js +3139 -0
  3. package/globalize/globalize-runtime.js +326 -0
  4. package/globalize/globalize.js +507 -0
  5. package/globalize/message.js +2076 -0
  6. package/globalize/number.js +1727 -0
  7. package/globalize/plural.js +376 -0
  8. package/globalize/relative-time.js +203 -0
  9. package/globalize/unit.js +301 -0
  10. package/node-main.js +27 -0
  11. package/package.json +3 -26
  12. package/CONTRIBUTING.md +0 -5
  13. package/README.md +0 -818
  14. package/doc/api/core/constructor.md +0 -28
  15. package/doc/api/core/load.md +0 -96
  16. package/doc/api/core/locale.md +0 -43
  17. package/doc/api/currency/currency-formatter.md +0 -196
  18. package/doc/api/currency/currency-to-parts-formatter.md +0 -117
  19. package/doc/api/date/date-formatter.md +0 -203
  20. package/doc/api/date/date-parser.md +0 -60
  21. package/doc/api/date/date-to-parts-formatter.md +0 -176
  22. package/doc/api/date/load-iana-time-zone.md +0 -29
  23. package/doc/api/message/load-messages.md +0 -105
  24. package/doc/api/message/message-formatter.md +0 -208
  25. package/doc/api/number/number-formatter.md +0 -202
  26. package/doc/api/number/number-parser.md +0 -130
  27. package/doc/api/number/number-to-parts-formatter.md +0 -140
  28. package/doc/api/plural/plural-generator.md +0 -84
  29. package/doc/api/relative-time/relative-time-formatter.md +0 -60
  30. package/doc/api/unit/unit-formatter.md +0 -72
  31. package/doc/blog-post/2017-07-xx-1.3.0-announcement.md +0 -177
  32. package/doc/cldr.md +0 -114
  33. package/doc/error/e-default-locale-not-defined.md +0 -9
  34. package/doc/error/e-invalid-cldr.md +0 -14
  35. package/doc/error/e-invalid-par-type.md +0 -12
  36. package/doc/error/e-invalid-par-value.md +0 -11
  37. package/doc/error/e-missing-cldr.md +0 -11
  38. package/doc/error/e-missing-parameter.md +0 -10
  39. package/doc/error/e-missing-plural-module.md +0 -9
  40. package/doc/error/e-par-missing-key.md +0 -11
  41. package/doc/error/e-par-out-of-range.md +0 -13
  42. package/doc/error/e-unsupported.md +0 -10
  43. package/doc/migrating-from-0.x.md +0 -64
  44. package/examples/amd-bower/.bowerrc +0 -7
  45. package/examples/amd-bower/README.md +0 -65
  46. package/examples/amd-bower/bower.json +0 -13
  47. package/examples/amd-bower/index.html +0 -46
  48. package/examples/amd-bower/main.js +0 -141
  49. package/examples/amd-bower/messages/en.json +0 -12
  50. package/examples/amd-bower/package.json +0 -14
  51. package/examples/app-npm-webpack/README.md +0 -74
  52. package/examples/app-npm-webpack/app/index.js +0 -89
  53. package/examples/app-npm-webpack/index-template.html +0 -71
  54. package/examples/app-npm-webpack/messages/ar.json +0 -25
  55. package/examples/app-npm-webpack/messages/de.json +0 -21
  56. package/examples/app-npm-webpack/messages/en.json +0 -21
  57. package/examples/app-npm-webpack/messages/es.json +0 -21
  58. package/examples/app-npm-webpack/messages/pt.json +0 -21
  59. package/examples/app-npm-webpack/messages/ru.json +0 -23
  60. package/examples/app-npm-webpack/messages/zh.json +0 -20
  61. package/examples/app-npm-webpack/package.json +0 -17
  62. package/examples/app-npm-webpack/webpack-config.js +0 -63
  63. package/examples/globalize-compiler/README.md +0 -45
  64. package/examples/globalize-compiler/app.js +0 -58
  65. package/examples/globalize-compiler/development.html +0 -121
  66. package/examples/globalize-compiler/messages.json +0 -12
  67. package/examples/globalize-compiler/package.json +0 -15
  68. package/examples/globalize-compiler/production.html +0 -75
  69. package/examples/node-npm/README.md +0 -57
  70. package/examples/node-npm/main.js +0 -65
  71. package/examples/node-npm/messages/en.json +0 -12
  72. package/examples/node-npm/package.json +0 -10
  73. package/examples/plain-javascript/README.md +0 -81
  74. package/examples/plain-javascript/index.html +0 -445
@@ -0,0 +1,1727 @@
1
+ /**
2
+ * Globalize v1.7.0
3
+ *
4
+ * https://github.com/globalizejs/globalize
5
+ *
6
+ * Copyright OpenJS Foundation and other contributors
7
+ * Released under the MIT license
8
+ * https://jquery.org/license
9
+ *
10
+ * Date: 2021-08-02T11:53Z
11
+ */
12
+ /*!
13
+ * Globalize v1.7.0 2021-08-02T11:53Z Released under the MIT license
14
+ * http://git.io/TrdQbw
15
+ */
16
+ (function( root, factory ) {
17
+
18
+ // UMD returnExports
19
+ if ( typeof define === "function" && define.amd ) {
20
+
21
+ // AMD
22
+ define([
23
+ "cldr",
24
+ "../globalize",
25
+ "cldr/event",
26
+ "cldr/supplemental"
27
+ ], factory );
28
+ } else if ( typeof exports === "object" ) {
29
+
30
+ // Node, CommonJS
31
+ module.exports = factory( require( "cldrjs" ), require( "../globalize" ) );
32
+ } else {
33
+
34
+ // Global
35
+ factory( root.Cldr, root.Globalize );
36
+ }
37
+ }(this, function( Cldr, Globalize ) {
38
+
39
+ var createError = Globalize._createError,
40
+ partsJoin = Globalize._partsJoin,
41
+ partsPush = Globalize._partsPush,
42
+ regexpEscape = Globalize._regexpEscape,
43
+ runtimeBind = Globalize._runtimeBind,
44
+ stringPad = Globalize._stringPad,
45
+ validateCldr = Globalize._validateCldr,
46
+ validateDefaultLocale = Globalize._validateDefaultLocale,
47
+ validateParameterPresence = Globalize._validateParameterPresence,
48
+ validateParameterRange = Globalize._validateParameterRange,
49
+ validateParameterType = Globalize._validateParameterType,
50
+ validateParameterTypePlainObject = Globalize._validateParameterTypePlainObject;
51
+
52
+
53
+ var createErrorUnsupportedFeature = function( feature ) {
54
+ return createError( "E_UNSUPPORTED", "Unsupported {feature}.", {
55
+ feature: feature
56
+ });
57
+ };
58
+
59
+
60
+
61
+
62
+ var validateParameterTypeNumber = function( value, name ) {
63
+ validateParameterType(
64
+ value,
65
+ name,
66
+ value === undefined || typeof value === "number",
67
+ "Number"
68
+ );
69
+ };
70
+
71
+
72
+
73
+
74
+ var validateParameterTypeString = function( value, name ) {
75
+ validateParameterType(
76
+ value,
77
+ name,
78
+ value === undefined || typeof value === "string",
79
+ "a string"
80
+ );
81
+ };
82
+
83
+
84
+
85
+
86
+ var numberFormatterFn = function( numberToPartsFormatter ) {
87
+ return function numberFormatter( value ) {
88
+ return partsJoin( numberToPartsFormatter( value ));
89
+ };
90
+ };
91
+
92
+
93
+
94
+
95
+ /**
96
+ * NumberingSystem( cldr )
97
+ *
98
+ * - http://www.unicode.org/reports/tr35/tr35-numbers.html#otherNumberingSystems
99
+ * - http://cldr.unicode.org/index/bcp47-extension
100
+ * - http://www.unicode.org/reports/tr35/#u_Extension
101
+ */
102
+ var numberNumberingSystem = function( cldr ) {
103
+ var nu = cldr.attributes[ "u-nu" ];
104
+
105
+ if ( nu ) {
106
+ if ( nu === "traditio" ) {
107
+ nu = "traditional";
108
+ }
109
+ if ( [ "native", "traditional", "finance" ].indexOf( nu ) !== -1 ) {
110
+
111
+ // Unicode locale extension `u-nu` is set using either (native, traditional or
112
+ // finance). So, lookup the respective locale's numberingSystem and return it.
113
+ return cldr.main([ "numbers/otherNumberingSystems", nu ]);
114
+ }
115
+
116
+ // Unicode locale extension `u-nu` is set with an explicit numberingSystem. Return it.
117
+ return nu;
118
+ }
119
+
120
+ // Return the default numberingSystem.
121
+ return cldr.main( "numbers/defaultNumberingSystem" );
122
+ };
123
+
124
+
125
+
126
+
127
+ /**
128
+ * Compact( name, cldr )
129
+ *
130
+ * @compactType [String] Compact mode, `short` or `long`.
131
+ *
132
+ * @cldr [Cldr instance].
133
+ *
134
+ * Return the localized compact map for the given compact mode.
135
+ */
136
+ var numberCompact = function( compactType, cldr ) {
137
+ var maxExponent = 0;
138
+
139
+ var object = cldr.main([
140
+ "numbers/decimalFormats-numberSystem-" + numberNumberingSystem( cldr ),
141
+ compactType,
142
+ "decimalFormat"
143
+ ]);
144
+
145
+ object = Object.keys( object ).reduce(function( newObject, compactKey ) {
146
+ var numberExponent = compactKey.split( "0" ).length - 1;
147
+ var pluralForm = compactKey.split( "-" )[ 2 ];
148
+ newObject[ numberExponent ] = newObject[ numberExponent ] || {};
149
+ newObject[ numberExponent ][ pluralForm ] = object[ compactKey ];
150
+ maxExponent = Math.max( numberExponent, maxExponent );
151
+ return newObject;
152
+ }, {});
153
+
154
+ object.maxExponent = maxExponent;
155
+
156
+ return object;
157
+ };
158
+
159
+
160
+
161
+
162
+ /**
163
+ * nuMap( cldr )
164
+ *
165
+ * @cldr [Cldr instance].
166
+ *
167
+ * Return digits map if numbering system is different than `latn`.
168
+ */
169
+ var numberNumberingSystemDigitsMap = function( cldr ) {
170
+ var aux,
171
+ nu = numberNumberingSystem( cldr );
172
+
173
+ if ( nu === "latn" ) {
174
+ return;
175
+ }
176
+
177
+ aux = cldr.supplemental([ "numberingSystems", nu ]);
178
+
179
+ if ( aux._type !== "numeric" ) {
180
+ throw createErrorUnsupportedFeature( "`" + aux._type + "` numbering system" );
181
+ }
182
+
183
+ return aux._digits;
184
+ };
185
+
186
+
187
+
188
+
189
+ /**
190
+ * EBNF representation:
191
+ *
192
+ * number_pattern_re = prefix?
193
+ * padding?
194
+ * (integer_fraction_pattern | significant_pattern)
195
+ * scientific_notation?
196
+ * suffix?
197
+ *
198
+ * prefix = non_number_stuff
199
+ *
200
+ * padding = "*" regexp(.)
201
+ *
202
+ * integer_fraction_pattern = integer_pattern
203
+ * fraction_pattern?
204
+ *
205
+ * integer_pattern = regexp([#,]*[0,]*0+)
206
+ *
207
+ * fraction_pattern = "." regexp(0*[0-9]*#*)
208
+ *
209
+ * significant_pattern = regexp([#,]*@+#*)
210
+ *
211
+ * scientific_notation = regexp(E\+?0+)
212
+ *
213
+ * suffix = non_number_stuff
214
+ *
215
+ * non_number_stuff = regexp(('[^']+'|''|[^*#@0,.E])*)
216
+ *
217
+ *
218
+ * Regexp groups:
219
+ *
220
+ * 0: number_pattern_re
221
+ * 1: prefix
222
+ * 2: -
223
+ * 3: -
224
+ * 4: padding
225
+ * 5: (integer_fraction_pattern | significant_pattern)
226
+ * 6: integer_fraction_pattern
227
+ * 7: integer_pattern
228
+ * 8: fraction_pattern
229
+ * 9: significant_pattern
230
+ * 10: scientific_notation
231
+ * 11: suffix
232
+ * 12: -
233
+ */
234
+ var numberPatternRe = ( /^(('([^']|'')*'|[^*#@0,.E])*)(\*.)?((([#,]*[0,]*0+)(\.0*[0-9]*#*)?)|([#,]*@+#*))(E\+?0+)?(('[^']+'|''|[^*#@0,.E])*)$/ );
235
+
236
+
237
+
238
+
239
+ /**
240
+ * format( number, pattern )
241
+ *
242
+ * @number [Number].
243
+ *
244
+ * @pattern [String] raw pattern for numbers.
245
+ *
246
+ * Return the formatted number.
247
+ * ref: http://www.unicode.org/reports/tr35/tr35-numbers.html
248
+ */
249
+ var numberPatternProperties = function( pattern ) {
250
+ var aux1, aux2, fractionPattern, integerFractionOrSignificantPattern, integerPattern,
251
+ maximumFractionDigits, maximumSignificantDigits, minimumFractionDigits,
252
+ minimumIntegerDigits, minimumSignificantDigits, padding, prefix, primaryGroupingSize,
253
+ roundIncrement, scientificNotation, secondaryGroupingSize, significantPattern, suffix;
254
+
255
+ pattern = pattern.match( numberPatternRe );
256
+ if ( !pattern ) {
257
+ throw new Error( "Invalid pattern: " + pattern );
258
+ }
259
+
260
+ prefix = pattern[ 1 ];
261
+ padding = pattern[ 4 ];
262
+ integerFractionOrSignificantPattern = pattern[ 5 ];
263
+ significantPattern = pattern[ 9 ];
264
+ scientificNotation = pattern[ 10 ];
265
+ suffix = pattern[ 11 ];
266
+
267
+ // Significant digit format
268
+ if ( significantPattern ) {
269
+ significantPattern.replace( /(@+)(#*)/, function( _match, minimumSignificantDigitsMatch, maximumSignificantDigitsMatch ) {
270
+ minimumSignificantDigits = minimumSignificantDigitsMatch.length;
271
+ maximumSignificantDigits = minimumSignificantDigits +
272
+ maximumSignificantDigitsMatch.length;
273
+ });
274
+
275
+ // Integer and fractional format
276
+ } else {
277
+ fractionPattern = pattern[ 8 ];
278
+ integerPattern = pattern[ 7 ];
279
+
280
+ if ( fractionPattern ) {
281
+
282
+ // Minimum fraction digits, and rounding.
283
+ fractionPattern.replace( /[0-9]+/, function( match ) {
284
+ minimumFractionDigits = match;
285
+ });
286
+ if ( minimumFractionDigits ) {
287
+ roundIncrement = +( "0." + minimumFractionDigits );
288
+ minimumFractionDigits = minimumFractionDigits.length;
289
+ } else {
290
+ minimumFractionDigits = 0;
291
+ }
292
+
293
+ // Maximum fraction digits
294
+ // 1: ignore decimal character
295
+ maximumFractionDigits = fractionPattern.length - 1; /* 1 */
296
+ } else {
297
+ minimumFractionDigits = 0;
298
+ maximumFractionDigits = 0;
299
+ }
300
+
301
+ // Minimum integer digits
302
+ integerPattern.replace( /0+$/, function( match ) {
303
+ minimumIntegerDigits = match.length;
304
+ });
305
+ }
306
+
307
+ // Scientific notation
308
+ if ( scientificNotation ) {
309
+ throw createErrorUnsupportedFeature({
310
+ feature: "scientific notation (not implemented)"
311
+ });
312
+ }
313
+
314
+ // Padding
315
+ if ( padding ) {
316
+ throw createErrorUnsupportedFeature({
317
+ feature: "padding (not implemented)"
318
+ });
319
+ }
320
+
321
+ // Grouping
322
+ if ( ( aux1 = integerFractionOrSignificantPattern.lastIndexOf( "," ) ) !== -1 ) {
323
+
324
+ // Primary grouping size is the interval between the last group separator and the end of
325
+ // the integer (or the end of the significant pattern).
326
+ aux2 = integerFractionOrSignificantPattern.split( "." )[ 0 ];
327
+ primaryGroupingSize = aux2.length - aux1 - 1;
328
+
329
+ // Secondary grouping size is the interval between the last two group separators.
330
+ if ( ( aux2 = integerFractionOrSignificantPattern.lastIndexOf( ",", aux1 - 1 ) ) !== -1 ) {
331
+ secondaryGroupingSize = aux1 - 1 - aux2;
332
+ }
333
+ }
334
+
335
+ // Return:
336
+ // 0: @prefix String
337
+ // 1: @padding Array [ <character>, <count> ] TODO
338
+ // 2: @minimumIntegerDigits non-negative integer Number value indicating the minimum integer
339
+ // digits to be used. Numbers will be padded with leading zeroes if necessary.
340
+ // 3: @minimumFractionDigits and
341
+ // 4: @maximumFractionDigits are non-negative integer Number values indicating the minimum and
342
+ // maximum fraction digits to be used. Numbers will be rounded or padded with trailing
343
+ // zeroes if necessary.
344
+ // 5: @minimumSignificantDigits and
345
+ // 6: @maximumSignificantDigits are positive integer Number values indicating the minimum and
346
+ // maximum fraction digits to be shown. Either none or both of these properties are
347
+ // present; if they are, they override minimum and maximum integer and fraction digits
348
+ // – the formatter uses however many integer and fraction digits are required to display
349
+ // the specified number of significant digits.
350
+ // 7: @roundIncrement Decimal round increment or null
351
+ // 8: @primaryGroupingSize
352
+ // 9: @secondaryGroupingSize
353
+ // 10: @suffix String
354
+ return [
355
+ prefix,
356
+ padding,
357
+ minimumIntegerDigits,
358
+ minimumFractionDigits,
359
+ maximumFractionDigits,
360
+ minimumSignificantDigits,
361
+ maximumSignificantDigits,
362
+ roundIncrement,
363
+ primaryGroupingSize,
364
+ secondaryGroupingSize,
365
+ suffix
366
+ ];
367
+ };
368
+
369
+
370
+
371
+
372
+ /**
373
+ * Symbol( name, cldr )
374
+ *
375
+ * @name [String] Symbol name.
376
+ *
377
+ * @cldr [Cldr instance].
378
+ *
379
+ * Return the localized symbol given its name.
380
+ */
381
+ var numberSymbol = function( name, cldr ) {
382
+ return cldr.main([
383
+ "numbers/symbols-numberSystem-" + numberNumberingSystem( cldr ),
384
+ name
385
+ ]);
386
+ };
387
+
388
+
389
+
390
+
391
+ var numberSymbolName = {
392
+ ".": "decimal",
393
+ ",": "group",
394
+ "%": "percentSign",
395
+ "+": "plusSign",
396
+ "-": "minusSign",
397
+ "E": "exponential",
398
+ "\u2030": "perMille"
399
+ };
400
+
401
+
402
+
403
+
404
+ /**
405
+ * symbolMap( cldr )
406
+ *
407
+ * @cldr [Cldr instance].
408
+ *
409
+ * Return the (localized symbol, pattern symbol) key value pair, eg. {
410
+ * ".": "٫",
411
+ * ",": "٬",
412
+ * "%": "٪",
413
+ * ...
414
+ * };
415
+ */
416
+ var numberSymbolMap = function( cldr ) {
417
+ var symbol,
418
+ symbolMap = {};
419
+
420
+ for ( symbol in numberSymbolName ) {
421
+ symbolMap[ symbol ] = numberSymbol( numberSymbolName[ symbol ], cldr );
422
+ }
423
+
424
+ return symbolMap;
425
+ };
426
+
427
+
428
+
429
+
430
+ var numberTruncate = function( value ) {
431
+ if ( isNaN( value ) ) {
432
+ return NaN;
433
+ }
434
+ return Math[ value < 0 ? "ceil" : "floor" ]( value );
435
+ };
436
+
437
+
438
+
439
+
440
+ /**
441
+ * round( method )
442
+ *
443
+ * @method [String] with either "round", "ceil", "floor", or "truncate".
444
+ *
445
+ * Return function( value, incrementOrExp ):
446
+ *
447
+ * @value [Number] eg. 123.45.
448
+ *
449
+ * @incrementOrExp [Number] optional, eg. 0.1; or
450
+ * [Object] Either { increment: <value> } or { exponent: <value> }
451
+ *
452
+ * Return the rounded number, eg:
453
+ * - round( "round" )( 123.45 ): 123;
454
+ * - round( "ceil" )( 123.45 ): 124;
455
+ * - round( "floor" )( 123.45 ): 123;
456
+ * - round( "truncate" )( 123.45 ): 123;
457
+ * - round( "round" )( 123.45, 0.1 ): 123.5;
458
+ * - round( "round" )( 123.45, 10 ): 120;
459
+ *
460
+ * Based on https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round
461
+ * Ref: #376
462
+ */
463
+ var numberRound = function( method ) {
464
+ method = method || "round";
465
+ method = method === "truncate" ? numberTruncate : Math[ method ];
466
+
467
+ return function( value, incrementOrExp ) {
468
+ var exp, increment;
469
+
470
+ value = +value;
471
+
472
+ // If the value is not a number, return NaN.
473
+ if ( isNaN( value ) ) {
474
+ return NaN;
475
+ }
476
+
477
+ // Exponent given.
478
+ if ( typeof incrementOrExp === "object" && incrementOrExp.exponent ) {
479
+ exp = +incrementOrExp.exponent;
480
+ increment = 1;
481
+
482
+ if ( exp === 0 ) {
483
+ return method( value );
484
+ }
485
+
486
+ // If the exp is not an integer, return NaN.
487
+ if ( !( typeof exp === "number" && exp % 1 === 0 ) ) {
488
+ return NaN;
489
+ }
490
+
491
+ // Increment given.
492
+ } else {
493
+ increment = +incrementOrExp || 1;
494
+
495
+ if ( increment === 1 ) {
496
+ return method( value );
497
+ }
498
+
499
+ // If the increment is not a number, return NaN.
500
+ if ( isNaN( increment ) ) {
501
+ return NaN;
502
+ }
503
+
504
+ increment = increment.toExponential().split( "e" );
505
+ exp = +increment[ 1 ];
506
+ increment = +increment[ 0 ];
507
+ }
508
+
509
+ // Shift & Round
510
+ value = value.toString().split( "e" );
511
+ value[ 0 ] = +value[ 0 ] / increment;
512
+ value[ 1 ] = value[ 1 ] ? ( +value[ 1 ] - exp ) : -exp;
513
+ value = method( +( value[ 0 ] + "e" + value[ 1 ] ) );
514
+
515
+ // Shift back
516
+ value = value.toString().split( "e" );
517
+ value[ 0 ] = +value[ 0 ] * increment;
518
+ value[ 1 ] = value[ 1 ] ? ( +value[ 1 ] + exp ) : exp;
519
+ return +( value[ 0 ] + "e" + value[ 1 ] );
520
+ };
521
+ };
522
+
523
+
524
+
525
+
526
+ /**
527
+ * formatProperties( pattern, cldr [, options] )
528
+ *
529
+ * @pattern [String] raw pattern for numbers.
530
+ *
531
+ * @cldr [Cldr instance].
532
+ *
533
+ * @options [Object]:
534
+ * - minimumIntegerDigits [Number]
535
+ * - minimumFractionDigits, maximumFractionDigits [Number]
536
+ * - minimumSignificantDigits, maximumSignificantDigits [Number]
537
+ * - round [String] "ceil", "floor", "round" (default), or "truncate".
538
+ * - useGrouping [Boolean] default true.
539
+ *
540
+ * Return the processed properties that will be used in number/format.
541
+ * ref: http://www.unicode.org/reports/tr35/tr35-numbers.html
542
+ */
543
+ var numberFormatProperties = function( pattern, cldr, options ) {
544
+ var negativePattern, negativePrefix, negativeProperties, negativeSuffix, positivePattern,
545
+ roundFn, properties;
546
+
547
+ function getOptions( attribute, propertyIndex ) {
548
+ if ( attribute in options ) {
549
+ properties[ propertyIndex ] = options[ attribute ];
550
+ }
551
+ }
552
+
553
+ options = options || {};
554
+ pattern = pattern.split( ";" );
555
+
556
+ positivePattern = pattern[ 0 ];
557
+
558
+ negativePattern = pattern[ 1 ] || "-" + positivePattern;
559
+ negativeProperties = numberPatternProperties( negativePattern );
560
+ negativePrefix = negativeProperties[ 0 ];
561
+ negativeSuffix = negativeProperties[ 10 ];
562
+
563
+ // Have runtime code to refer to numberRound() instead of including it explicitly.
564
+ roundFn = numberRound( options.round );
565
+ roundFn.generatorString = function() {
566
+ return "numberRound(" + ( options.round ? "\"" + options.round + "\"" : "" ) + ")";
567
+ };
568
+
569
+ properties = numberPatternProperties( positivePattern ).concat([
570
+ positivePattern,
571
+ negativePrefix + positivePattern + negativeSuffix,
572
+ negativePrefix,
573
+ negativeSuffix,
574
+ roundFn,
575
+ numberSymbol( "infinity", cldr ),
576
+ numberSymbol( "nan", cldr ),
577
+ numberSymbolMap( cldr ),
578
+ numberNumberingSystemDigitsMap( cldr )
579
+ ]);
580
+
581
+ if ( options.compact ) {
582
+
583
+ // The compact digits number pattern is always `0+`, so override the following properties.
584
+ // Note: minimumIntegerDigits would actually range from `0` to `000` based on the scale of
585
+ // the value to be formatted, though we're always using 1 as a simplification, because the
586
+ // number won't be zero-padded since we chose the right format based on the scale, i.e.,
587
+ // we'd never see something like `003M` anyway.
588
+ properties[ 2 ] = 1; // minimumIntegerDigits
589
+ properties[ 3 ] = 0; // minimumFractionDigits
590
+ properties[ 4 ] = 0; // maximumFractionDigits
591
+ properties[ 5 ] = // minimumSignificantDigits &
592
+ properties[ 6 ] = undefined; // maximumSignificantDigits
593
+
594
+ properties[ 20 ] = numberCompact( options.compact, cldr );
595
+ }
596
+
597
+ getOptions( "minimumIntegerDigits", 2 );
598
+ getOptions( "minimumFractionDigits", 3 );
599
+ getOptions( "maximumFractionDigits", 4 );
600
+ getOptions( "minimumSignificantDigits", 5 );
601
+ getOptions( "maximumSignificantDigits", 6 );
602
+
603
+ // Grouping separators
604
+ if ( options.useGrouping === false ) {
605
+ properties[ 8 ] = null;
606
+ }
607
+
608
+ // Normalize number of digits if only one of either minimumFractionDigits or
609
+ // maximumFractionDigits is passed in as an option
610
+ if ( "minimumFractionDigits" in options && !( "maximumFractionDigits" in options ) ) {
611
+
612
+ // maximumFractionDigits = Math.max( minimumFractionDigits, maximumFractionDigits );
613
+ properties[ 4 ] = Math.max( properties[ 3 ], properties[ 4 ] );
614
+ } else if ( !( "minimumFractionDigits" in options ) &&
615
+ "maximumFractionDigits" in options ) {
616
+
617
+ // minimumFractionDigits = Math.min( minimumFractionDigits, maximumFractionDigits );
618
+ properties[ 3 ] = Math.min( properties[ 3 ], properties[ 4 ] );
619
+ }
620
+
621
+ // Return:
622
+ // 0-10: see number/pattern-properties.
623
+ // 11: @positivePattern [String] Positive pattern.
624
+ // 12: @negativePattern [String] Negative pattern.
625
+ // 13: @negativePrefix [String] Negative prefix.
626
+ // 14: @negativeSuffix [String] Negative suffix.
627
+ // 15: @round [Function] Round function.
628
+ // 16: @infinitySymbol [String] Infinity symbol.
629
+ // 17: @nanSymbol [String] NaN symbol.
630
+ // 18: @symbolMap [Object] A bunch of other symbols.
631
+ // 19: @nuDigitsMap [Array] Digits map if numbering system is different than `latn`.
632
+ // 20: @compactMap [Object] Map of per-digit-count format patterns for specified compact mode.
633
+ return properties;
634
+ };
635
+
636
+
637
+
638
+
639
+ /**
640
+ * Generated by:
641
+ *
642
+ * var regenerate = require( "regenerate" );
643
+ * var formatSymbols = require( "@unicode/unicode-13.0.0/General_Category/Format/symbols" );
644
+ * regenerate().add( formatSymbols ).toString();
645
+ *
646
+ * https://github.com/mathiasbynens/regenerate
647
+ * https://github.com/node-unicode/unicode-13.0.0
648
+ */
649
+ var regexpCfG = /[\xAD\u0600-\u0605\u061C\u06DD\u070F\u08E2\u180E\u200B-\u200F\u202A-\u202E\u2060-\u2064\u2066-\u206F\uFEFF\uFFF9-\uFFFB]|\uD804[\uDCBD\uDCCD]|\uD80D[\uDC30-\uDC38]|\uD82F[\uDCA0-\uDCA3]|\uD834[\uDD73-\uDD7A]|\uDB40[\uDC01\uDC20-\uDC7F]/g;
650
+
651
+
652
+
653
+
654
+ /**
655
+ * Generated by:
656
+ *
657
+ * var regenerate = require( "regenerate" );
658
+ * var dashSymbols = require( "https://github.com/node-unicode/unicode-13.0.0/General_Category/Dash_Punctuation/symbols" );
659
+ * regenerate().add( dashSymbols ).toString();
660
+ *
661
+ * https://github.com/mathiasbynens/regenerate
662
+ * https://github.com/node-unicode/unicode-13.0.0
663
+ *
664
+ * NOTE: In addition to [:dash:], the below includes MINUS SIGN U+2212.
665
+ */
666
+ var regexpDashG = /[\x2D\u058A\u05BE\u1400\u1806\u2010-\u2015\u2E17\u2E1A\u2E3A\u2E3B\u2E40\u301C\u3030\u30A0\uFE31\uFE32\uFE58\uFE63\uFF0D\u2212]|\uD803\uDEAD/g;
667
+
668
+
669
+
670
+
671
+ /**
672
+ * Generated by:
673
+ *
674
+ * var regenerate = require( "regenerate" );
675
+ * var spaceSeparatorSymbols = require( "@unicode/unicode-13.0.0/General_Category/Space_Separator/symbols" );
676
+ * regenerate().add( spaceSeparatorSymbols ).toString();
677
+ *
678
+ * https://github.com/mathiasbynens/regenerate
679
+ * https://github.com/node-unicode/unicode-13.0.0
680
+ */
681
+ var regexpZsG = /[ \xA0\u1680\u2000-\u200A\u202F\u205F\u3000]/g;
682
+
683
+
684
+
685
+
686
+ /**
687
+ * Loose Matching:
688
+ * - Ignore all format characters, which includes RLM, LRM or ALM used to control BIDI
689
+ * formatting.
690
+ * - Map all characters in [:Zs:] to U+0020 SPACE;
691
+ * - Map all characters in [:Dash:] to U+002D HYPHEN-MINUS;
692
+ */
693
+ var looseMatching = function( value ) {
694
+ return value
695
+ .replace( regexpCfG, "" )
696
+ .replace( regexpDashG, "-" )
697
+ .replace( regexpZsG, " " );
698
+ };
699
+
700
+
701
+
702
+
703
+ /**
704
+ * parse( value, properties )
705
+ *
706
+ * @value [String].
707
+ *
708
+ * @properties [Object] Parser properties is a reduced pre-processed cldr
709
+ * data set returned by numberParserProperties().
710
+ *
711
+ * Return the parsed Number (including Infinity) or NaN when value is invalid.
712
+ * ref: http://www.unicode.org/reports/tr35/tr35-numbers.html
713
+ */
714
+ var numberParse = function( value, properties ) {
715
+ var grammar, invertedNuDigitsMap, invertedSymbolMap, negative, number, prefix, prefixNSuffix,
716
+ suffix, tokenizer, valid;
717
+
718
+ // Grammar:
719
+ // - Value <= NaN | PositiveNumber | NegativeNumber
720
+ // - PositiveNumber <= PositivePrefix NumberOrInf PositiveSufix
721
+ // - NegativeNumber <= NegativePrefix NumberOrInf
722
+ // - NumberOrInf <= Number | Inf
723
+ grammar = [
724
+ [ "nan" ],
725
+ [ "prefix", "infinity", "suffix" ],
726
+ [ "prefix", "number", "suffix" ],
727
+ [ "negativePrefix", "infinity", "negativeSuffix" ],
728
+ [ "negativePrefix", "number", "negativeSuffix" ]
729
+ ];
730
+
731
+ invertedSymbolMap = properties[ 0 ];
732
+ invertedNuDigitsMap = properties[ 1 ] || {};
733
+ tokenizer = properties[ 2 ];
734
+
735
+ value = looseMatching( value );
736
+
737
+ function parse( type ) {
738
+ return function( lexeme ) {
739
+
740
+ // Reverse localized symbols and numbering system.
741
+ lexeme = lexeme.split( "" ).map(function( character ) {
742
+ return invertedSymbolMap[ character ] ||
743
+ invertedNuDigitsMap[ character ] ||
744
+ character;
745
+ }).join( "" );
746
+
747
+ switch ( type ) {
748
+ case "infinity":
749
+ number = Infinity;
750
+ break;
751
+
752
+ case "nan":
753
+ number = NaN;
754
+ break;
755
+
756
+ case "number":
757
+
758
+ // Remove grouping separators.
759
+ lexeme = lexeme.replace( /,/g, "" );
760
+
761
+ number = +lexeme;
762
+ break;
763
+
764
+ case "prefix":
765
+ case "negativePrefix":
766
+ prefix = lexeme;
767
+ break;
768
+
769
+ case "suffix":
770
+ suffix = lexeme;
771
+ break;
772
+
773
+ case "negativeSuffix":
774
+ suffix = lexeme;
775
+ negative = true;
776
+ break;
777
+
778
+ // This should never be reached.
779
+ default:
780
+ throw new Error( "Internal error" );
781
+ }
782
+ return "";
783
+ };
784
+ }
785
+
786
+ function tokenizeNParse( _value, grammar ) {
787
+ return grammar.some(function( statement ) {
788
+ var value = _value;
789
+
790
+ // The whole grammar statement should be used (i.e., .every() return true) and value be
791
+ // entirely consumed (i.e., !value.length).
792
+ return statement.every(function( type ) {
793
+ if ( value.match( tokenizer[ type ] ) === null ) {
794
+ return false;
795
+ }
796
+
797
+ // Consume and parse it.
798
+ value = value.replace( tokenizer[ type ], parse( type ) );
799
+ return true;
800
+ }) && !value.length;
801
+ });
802
+ }
803
+
804
+ valid = tokenizeNParse( value, grammar );
805
+
806
+ // NaN
807
+ if ( !valid || isNaN( number ) ) {
808
+ return NaN;
809
+ }
810
+
811
+ prefixNSuffix = "" + prefix + suffix;
812
+
813
+ // Percent
814
+ if ( prefixNSuffix.indexOf( "%" ) !== -1 ) {
815
+ number /= 100;
816
+
817
+ // Per mille
818
+ } else if ( prefixNSuffix.indexOf( "\u2030" ) !== -1 ) {
819
+ number /= 1000;
820
+ }
821
+
822
+ // Negative number
823
+ if ( negative ) {
824
+ number *= -1;
825
+ }
826
+
827
+ return number;
828
+ };
829
+
830
+
831
+
832
+
833
+ var numberParserFn = function( properties ) {
834
+ return function numberParser( value ) {
835
+ validateParameterPresence( value, "value" );
836
+ validateParameterTypeString( value, "value" );
837
+
838
+ return numberParse( value, properties );
839
+ };
840
+
841
+ };
842
+
843
+
844
+
845
+
846
+ /**
847
+ * symbolMap( cldr )
848
+ *
849
+ * @cldr [Cldr instance].
850
+ *
851
+ * Return the (localized symbol, pattern symbol) key value pair, eg. {
852
+ * "٫": ".",
853
+ * "٬": ",",
854
+ * "٪": "%",
855
+ * ...
856
+ * };
857
+ */
858
+ var numberSymbolInvertedMap = function( cldr ) {
859
+ var symbol,
860
+ symbolMap = {};
861
+
862
+ for ( symbol in numberSymbolName ) {
863
+ symbolMap[ numberSymbol( numberSymbolName[ symbol ], cldr ) ] = symbol;
864
+ }
865
+
866
+ return symbolMap;
867
+ };
868
+
869
+
870
+
871
+
872
+ /**
873
+ * objectMap( object, fn)
874
+ *
875
+ * - object
876
+ *
877
+ * - fn( pair ) => pair
878
+ */
879
+ var objectMap = function( object, fn ) {
880
+ return Object.keys( object ).map(function( key ) {
881
+ return fn([ key, object[ key ] ]);
882
+ }).reduce(function( object, pair ) {
883
+ object[ pair[ 0 ] ] = pair[ 1 ];
884
+ return object;
885
+ }, {});
886
+ };
887
+
888
+
889
+
890
+
891
+ /**
892
+ * removeLiteralQuotes( string )
893
+ *
894
+ * Return:
895
+ * - `'` if input string is `''`.
896
+ * - `o'clock` if input string is `'o''clock'`.
897
+ * - `foo` if input string is `foo`, i.e., return the same value in case it isn't a single-quoted
898
+ * string.
899
+ */
900
+ var removeLiteralQuotes = function( string ) {
901
+ if ( string[ 0 ] + string[ string.length - 1 ] !== "''" ) {
902
+ return string;
903
+ }
904
+ if ( string === "''" ) {
905
+ return "'";
906
+ }
907
+ return string.replace( /''/g, "'" ).slice( 1, -1 );
908
+ };
909
+
910
+
911
+
912
+
913
+ /**
914
+ * parseProperties( pattern, cldr )
915
+ *
916
+ * @pattern [String] raw pattern for numbers.
917
+ *
918
+ * @cldr [Cldr instance].
919
+ *
920
+ * Return parser properties, used to feed parser function.
921
+ *
922
+ * TODO:
923
+ * - Scientific_notation;
924
+ * - Padding;
925
+ */
926
+ var numberParseProperties = function( pattern, cldr, options ) {
927
+ var aux, decimalSymbolRe, digitsRe, groupingSeparatorRe, infinitySymbol, invertedNuDigitsMap,
928
+ invertedSymbolMap, maximumFractionDigits, maximumSignificantDigits,
929
+ minimumSignificantDigits, nanSymbol, negativePrefix, negativeSuffix, nuDigitsMap,
930
+ numberTokenizer, prefix, primaryGroupingSize, secondaryGroupingSize, suffix, symbolMap,
931
+ formatProperties = numberFormatProperties( pattern, cldr, options );
932
+
933
+ prefix = looseMatching( formatProperties[ 0 ] );
934
+ maximumFractionDigits = formatProperties[ 4 ];
935
+ minimumSignificantDigits = formatProperties[ 5 ];
936
+ maximumSignificantDigits = formatProperties[ 6 ];
937
+ primaryGroupingSize = formatProperties[ 8 ];
938
+ secondaryGroupingSize = formatProperties[ 9 ];
939
+ suffix = looseMatching( formatProperties[ 10 ] );
940
+ negativePrefix = looseMatching( formatProperties[ 13 ] );
941
+ negativeSuffix = looseMatching( formatProperties[ 14 ] );
942
+ infinitySymbol = looseMatching( formatProperties[ 16 ] );
943
+ nanSymbol = looseMatching( formatProperties[ 17 ] );
944
+ symbolMap = objectMap( formatProperties[ 18 ], function( pair ) {
945
+ return [ pair[ 0 ], looseMatching( pair[ 1 ] ) ];
946
+ });
947
+ nuDigitsMap = formatProperties[ 19 ];
948
+
949
+ invertedSymbolMap = objectMap( numberSymbolInvertedMap( cldr ), function( pair ) {
950
+ return [ looseMatching( pair[ 0 ] ), pair[ 1 ] ];
951
+ });
952
+
953
+ digitsRe = nuDigitsMap ? "[" + nuDigitsMap + "]" : "\\d";
954
+ groupingSeparatorRe = regexpEscape( symbolMap[ "," ] );
955
+ decimalSymbolRe = regexpEscape( symbolMap[ "." ] );
956
+
957
+ if ( nuDigitsMap ) {
958
+ invertedNuDigitsMap = nuDigitsMap.split( "" ).reduce(function( object, localizedDigit, i ) {
959
+ object[ localizedDigit ] = String( i );
960
+ return object;
961
+ }, {} );
962
+ }
963
+
964
+ aux = [ prefix, suffix, negativePrefix, negativeSuffix ].map(function( value ) {
965
+ return value.replace( /('([^']|'')+'|'')|./g, function( character, literal ) {
966
+
967
+ // Literals
968
+ if ( literal ) {
969
+ return removeLiteralQuotes( literal );
970
+ }
971
+
972
+ // Symbols
973
+ character = character.replace( /[\-+E%\u2030]/, function( symbol ) {
974
+ return symbolMap[ symbol ];
975
+ });
976
+
977
+ return character;
978
+ });
979
+ });
980
+
981
+ prefix = aux[ 0 ];
982
+ suffix = aux[ 1 ];
983
+ negativePrefix = aux[ 2 ];
984
+ negativeSuffix = aux[ 3 ];
985
+
986
+ // Number
987
+ //
988
+ // number_re = integer fraction?
989
+ //
990
+ // integer = digits | digits_using_grouping_separators
991
+ //
992
+ // fraction = regexp((.\d+)?)
993
+ //
994
+ // digits = regexp(\d+)
995
+ //
996
+ // digits_w_grouping_separators = digits_w_1_grouping_separators |
997
+ // digits_w_2_grouping_separators
998
+ //
999
+ // digits_w_1_grouping_separators = regexp(\d{1,3}(,\d{3})+)
1000
+ //
1001
+ // digits_w_2_grouping_separators = regexp(\d{1,2}((,\d{2})*(,\d{3})))
1002
+
1003
+ // Integer part
1004
+ numberTokenizer = digitsRe + "+";
1005
+
1006
+ // Grouping separators
1007
+ if ( primaryGroupingSize ) {
1008
+ if ( secondaryGroupingSize ) {
1009
+ aux = digitsRe + "{1," + secondaryGroupingSize + "}((" + groupingSeparatorRe +
1010
+ digitsRe + "{" + secondaryGroupingSize + "})*(" + groupingSeparatorRe +
1011
+ digitsRe + "{" + primaryGroupingSize + "}))";
1012
+ } else {
1013
+ aux = digitsRe + "{1," + primaryGroupingSize + "}(" + groupingSeparatorRe +
1014
+ digitsRe + "{" + primaryGroupingSize + "})+";
1015
+ }
1016
+ numberTokenizer = "(" + aux + "|" + numberTokenizer + ")";
1017
+ }
1018
+
1019
+ // Fraction part? Only included if 1 or 2.
1020
+ // 1: Using significant digit format.
1021
+ // 2: Using integer and fractional format && it has a maximumFractionDigits.
1022
+ if ( !isNaN( minimumSignificantDigits * maximumSignificantDigits ) || /* 1 */
1023
+ maximumFractionDigits /* 2 */ ) {
1024
+
1025
+ // 1: Handle trailing decimal separator, e.g., `"1." => `1``.
1026
+ aux = decimalSymbolRe + digitsRe + "+";
1027
+ numberTokenizer = numberTokenizer + "(" + aux + "|" + decimalSymbolRe /* 1 */ + ")?" +
1028
+
1029
+ // Handle non-padded decimals, e.g., `".12"` => `0.12` by making the integer part
1030
+ // optional.
1031
+ "|(" + numberTokenizer + ")?" + aux;
1032
+
1033
+ numberTokenizer = "(" + numberTokenizer + ")";
1034
+ }
1035
+
1036
+ // 0: @invertedSymbolMap [Object] Inverted symbol map.
1037
+ // 1: @invertedNuDigitsMap [Object] Inverted digits map if numbering system is different than
1038
+ // `latn`.
1039
+ // 2: @tokenizer [Object] Tokenizer map, used by parser to consume input.
1040
+ return [
1041
+ invertedSymbolMap,
1042
+ invertedNuDigitsMap,
1043
+ {
1044
+ infinity: new RegExp( "^" + regexpEscape( infinitySymbol ) ),
1045
+ nan: new RegExp( "^" + regexpEscape( nanSymbol ) ),
1046
+ negativePrefix: new RegExp( "^" + regexpEscape( negativePrefix ) ),
1047
+ negativeSuffix: new RegExp( "^" + regexpEscape( negativeSuffix ) ),
1048
+ number: new RegExp( "^" + numberTokenizer ),
1049
+ prefix: new RegExp( "^" + regexpEscape( prefix ) ),
1050
+ suffix: new RegExp( "^" + regexpEscape( suffix ) )
1051
+ }
1052
+ ];
1053
+
1054
+ };
1055
+
1056
+
1057
+
1058
+
1059
+ /**
1060
+ * Pattern( style )
1061
+ *
1062
+ * @style [String] "decimal" (default) or "percent".
1063
+ *
1064
+ * @cldr [Cldr instance].
1065
+ */
1066
+ var numberPattern = function( style, cldr ) {
1067
+ if ( style !== "decimal" && style !== "percent" ) {
1068
+ throw new Error( "Invalid style" );
1069
+ }
1070
+
1071
+ return cldr.main([
1072
+ "numbers",
1073
+ style + "Formats-numberSystem-" + numberNumberingSystem( cldr ),
1074
+ "standard"
1075
+ ]);
1076
+ };
1077
+
1078
+
1079
+
1080
+
1081
+ /**
1082
+ * EBNF representation:
1083
+ *
1084
+ * compact_pattern_re = prefix?
1085
+ * number_pattern_re
1086
+ * suffix?
1087
+ *
1088
+ * number_pattern_re = 0+
1089
+ *
1090
+ * Regexp groups:
1091
+ *
1092
+ * 0: compact_pattern_re
1093
+ * 1: prefix
1094
+ * 2: number_pattern_re (the number pattern to use in compact mode)
1095
+ * 3: suffix
1096
+ */
1097
+ var numberCompactPatternRe = ( /^([^0]*)(0+)([^0]*)$/ );
1098
+
1099
+
1100
+
1101
+
1102
+ /**
1103
+ * goupingSeparator( number, primaryGroupingSize, secondaryGroupingSize )
1104
+ *
1105
+ * @number [Number].
1106
+ *
1107
+ * @primaryGroupingSize [Number]
1108
+ *
1109
+ * @secondaryGroupingSize [Number]
1110
+ *
1111
+ * Return the formatted number with group separator.
1112
+ */
1113
+ var numberFormatGroupingSeparator = function( number, primaryGroupingSize, secondaryGroupingSize ) {
1114
+ var index,
1115
+ currentGroupingSize = primaryGroupingSize,
1116
+ ret = "",
1117
+ sep = ",",
1118
+ switchToSecondary = secondaryGroupingSize ? true : false;
1119
+
1120
+ number = String( number ).split( "." );
1121
+ index = number[ 0 ].length;
1122
+
1123
+ while ( index > currentGroupingSize ) {
1124
+ ret = number[ 0 ].slice( index - currentGroupingSize, index ) +
1125
+ ( ret.length ? sep : "" ) + ret;
1126
+ index -= currentGroupingSize;
1127
+ if ( switchToSecondary ) {
1128
+ currentGroupingSize = secondaryGroupingSize;
1129
+ switchToSecondary = false;
1130
+ }
1131
+ }
1132
+
1133
+ number[ 0 ] = number[ 0 ].slice( 0, index ) + ( ret.length ? sep : "" ) + ret;
1134
+ return number.join( "." );
1135
+ };
1136
+
1137
+
1138
+
1139
+
1140
+ /**
1141
+ * integerFractionDigits( number, minimumIntegerDigits, minimumFractionDigits,
1142
+ * maximumFractionDigits, round, roundIncrement )
1143
+ *
1144
+ * @number [Number]
1145
+ *
1146
+ * @minimumIntegerDigits [Number]
1147
+ *
1148
+ * @minimumFractionDigits [Number]
1149
+ *
1150
+ * @maximumFractionDigits [Number]
1151
+ *
1152
+ * @round [Function]
1153
+ *
1154
+ * @roundIncrement [Function]
1155
+ *
1156
+ * Return the formatted integer and fraction digits.
1157
+ */
1158
+ var numberFormatIntegerFractionDigits = function( number, minimumIntegerDigits, minimumFractionDigits, maximumFractionDigits, round,
1159
+ roundIncrement ) {
1160
+
1161
+ // Fraction
1162
+ if ( maximumFractionDigits ) {
1163
+
1164
+ // Rounding
1165
+ if ( roundIncrement ) {
1166
+ number = round( number, roundIncrement );
1167
+
1168
+ // Maximum fraction digits
1169
+ } else {
1170
+ number = round( number, { exponent: -maximumFractionDigits } );
1171
+ }
1172
+
1173
+ } else {
1174
+ number = round( number );
1175
+ }
1176
+
1177
+ number = String( number );
1178
+
1179
+ // Maximum integer digits (post string phase)
1180
+ if ( maximumFractionDigits && /e-/.test( number ) ) {
1181
+
1182
+ // Use toFixed( maximumFractionDigits ) to make sure small numbers like 1e-7 are
1183
+ // displayed using plain digits instead of scientific notation.
1184
+ // 1: Remove leading decimal zeros.
1185
+ // 2: Remove leading decimal separator.
1186
+ // Note: String() is still preferred so it doesn't mess up with a number precision
1187
+ // unnecessarily, e.g., (123456789.123).toFixed(10) === "123456789.1229999959",
1188
+ // String(123456789.123) === "123456789.123".
1189
+ number = ( +number ).toFixed( maximumFractionDigits )
1190
+ .replace( /0+$/, "" ) /* 1 */
1191
+ .replace( /\.$/, "" ); /* 2 */
1192
+ }
1193
+
1194
+ // Minimum fraction digits (post string phase)
1195
+ if ( minimumFractionDigits ) {
1196
+ number = number.split( "." );
1197
+ number[ 1 ] = stringPad( number[ 1 ] || "", minimumFractionDigits, true );
1198
+ number = number.join( "." );
1199
+ }
1200
+
1201
+ // Minimum integer digits
1202
+ if ( minimumIntegerDigits ) {
1203
+ number = number.split( "." );
1204
+ number[ 0 ] = stringPad( number[ 0 ], minimumIntegerDigits );
1205
+ number = number.join( "." );
1206
+ }
1207
+
1208
+ return number;
1209
+ };
1210
+
1211
+
1212
+
1213
+
1214
+ /**
1215
+ * toPrecision( number, precision, round )
1216
+ *
1217
+ * @number (Number)
1218
+ *
1219
+ * @precision (Number) significant figures precision (not decimal precision).
1220
+ *
1221
+ * @round (Function)
1222
+ *
1223
+ * Return number.toPrecision( precision ) using the given round function.
1224
+ */
1225
+ var numberToPrecision = function( number, precision, round ) {
1226
+ var roundOrder;
1227
+
1228
+ if ( number === 0 ) { // Fix #706
1229
+ return number;
1230
+ }
1231
+
1232
+ roundOrder = Math.ceil( Math.log( Math.abs( number ) ) / Math.log( 10 ) );
1233
+ roundOrder -= precision;
1234
+
1235
+ return round( number, { exponent: roundOrder } );
1236
+ };
1237
+
1238
+
1239
+
1240
+
1241
+ /**
1242
+ * toPrecision( number, minimumSignificantDigits, maximumSignificantDigits, round )
1243
+ *
1244
+ * @number [Number]
1245
+ *
1246
+ * @minimumSignificantDigits [Number]
1247
+ *
1248
+ * @maximumSignificantDigits [Number]
1249
+ *
1250
+ * @round [Function]
1251
+ *
1252
+ * Return the formatted significant digits number.
1253
+ */
1254
+ var numberFormatSignificantDigits = function( number, minimumSignificantDigits, maximumSignificantDigits, round ) {
1255
+ var atMinimum, atMaximum;
1256
+
1257
+ // Sanity check.
1258
+ if ( minimumSignificantDigits > maximumSignificantDigits ) {
1259
+ maximumSignificantDigits = minimumSignificantDigits;
1260
+ }
1261
+
1262
+ atMinimum = numberToPrecision( number, minimumSignificantDigits, round );
1263
+ atMaximum = numberToPrecision( number, maximumSignificantDigits, round );
1264
+
1265
+ // Use atMaximum only if it has more significant digits than atMinimum.
1266
+ number = +atMinimum === +atMaximum ? atMinimum : atMaximum;
1267
+
1268
+ // Expand integer numbers, eg. 123e5 to 12300.
1269
+ number = ( +number ).toString( 10 );
1270
+
1271
+ if ( ( /e/ ).test( number ) ) {
1272
+ throw createErrorUnsupportedFeature({
1273
+ feature: "integers out of (1e21, 1e-7)"
1274
+ });
1275
+ }
1276
+
1277
+ // Add trailing zeros if necessary.
1278
+ if ( minimumSignificantDigits - number.replace( /^0+|\./g, "" ).length > 0 ) {
1279
+ number = number.split( "." );
1280
+ number[ 1 ] = stringPad( number[ 1 ] || "", minimumSignificantDigits - number[ 0 ].replace( /^0+/, "" ).length, true );
1281
+ number = number.join( "." );
1282
+ }
1283
+
1284
+ return number;
1285
+ };
1286
+
1287
+
1288
+
1289
+
1290
+ /**
1291
+ * format( number, properties )
1292
+ *
1293
+ * @number [Number].
1294
+ *
1295
+ * @properties [Object] Output of number/format-properties.
1296
+ *
1297
+ * Return the formatted number.
1298
+ * ref: http://www.unicode.org/reports/tr35/tr35-numbers.html
1299
+ */
1300
+ var numberFormat = function( number, properties, pluralGenerator ) {
1301
+ var aux, compactMap, infinitySymbol, maximumFractionDigits, maximumSignificantDigits,
1302
+ minimumFractionDigits, minimumIntegerDigits, minimumSignificantDigits, nanSymbol,
1303
+ nuDigitsMap, prefix, primaryGroupingSize, pattern, round, roundIncrement,
1304
+ secondaryGroupingSize, stringToParts, suffix, symbolMap;
1305
+
1306
+ minimumIntegerDigits = properties[ 2 ];
1307
+ minimumFractionDigits = properties[ 3 ];
1308
+ maximumFractionDigits = properties[ 4 ];
1309
+ minimumSignificantDigits = properties[ 5 ];
1310
+ maximumSignificantDigits = properties[ 6 ];
1311
+ roundIncrement = properties[ 7 ];
1312
+ primaryGroupingSize = properties[ 8 ];
1313
+ secondaryGroupingSize = properties[ 9 ];
1314
+ round = properties[ 15 ];
1315
+ infinitySymbol = properties[ 16 ];
1316
+ nanSymbol = properties[ 17 ];
1317
+ symbolMap = properties[ 18 ];
1318
+ nuDigitsMap = properties[ 19 ];
1319
+ compactMap = properties[ 20 ];
1320
+
1321
+ // NaN
1322
+ if ( isNaN( number ) ) {
1323
+ return [ { type: "nan", value: nanSymbol } ];
1324
+ }
1325
+
1326
+ if ( number < 0 ) {
1327
+ pattern = properties[ 12 ];
1328
+ prefix = properties[ 13 ];
1329
+ suffix = properties[ 14 ];
1330
+ } else {
1331
+ pattern = properties[ 11 ];
1332
+ prefix = properties[ 0 ];
1333
+ suffix = properties[ 10 ];
1334
+ }
1335
+
1336
+ // For prefix, suffix, and number parts.
1337
+ stringToParts = function( string ) {
1338
+ var numberType = "integer",
1339
+ parts = [];
1340
+
1341
+ // TODO Move the tokenization of all parts that don't depend on number into
1342
+ // format-properties.
1343
+ string.replace( /('([^']|'')+'|'')|./g, function( character, literal ) {
1344
+
1345
+ // Literals
1346
+ if ( literal ) {
1347
+ partsPush( parts, "literal", removeLiteralQuotes( literal ) );
1348
+ return;
1349
+ }
1350
+
1351
+ // Currency symbol
1352
+ if ( character === "\u00A4" ) {
1353
+ partsPush( parts, "currency", character );
1354
+ return;
1355
+ }
1356
+
1357
+ // Symbols
1358
+ character = character.replace( /[.,\-+E%\u2030]/, function( symbol ) {
1359
+ if ( symbol === "." ) {
1360
+ numberType = "fraction";
1361
+ }
1362
+ partsPush( parts, numberSymbolName[ symbol ], symbolMap[ symbol ] );
1363
+
1364
+ // "Erase" handled character.
1365
+ return "";
1366
+ });
1367
+
1368
+ // Number
1369
+ character = character.replace( /[0-9]/, function( digit ) {
1370
+
1371
+ // Numbering system
1372
+ if ( nuDigitsMap ) {
1373
+ digit = nuDigitsMap[ +digit ];
1374
+ }
1375
+ partsPush( parts, numberType, digit );
1376
+
1377
+ // "Erase" handled character.
1378
+ return "";
1379
+ });
1380
+
1381
+ // Etc
1382
+ character.replace( /./, function( etc ) {
1383
+ partsPush( parts, "literal", etc );
1384
+ });
1385
+ });
1386
+ return parts;
1387
+ };
1388
+
1389
+ prefix = stringToParts( prefix );
1390
+ suffix = stringToParts( suffix );
1391
+
1392
+ // Infinity
1393
+ if ( !isFinite( number ) ) {
1394
+ return prefix.concat(
1395
+ { type: "infinity", value: infinitySymbol },
1396
+ suffix
1397
+ );
1398
+ }
1399
+
1400
+ // Percent
1401
+ if ( pattern.indexOf( "%" ) !== -1 ) {
1402
+ number *= 100;
1403
+
1404
+ // Per mille
1405
+ } else if ( pattern.indexOf( "\u2030" ) !== -1 ) {
1406
+ number *= 1000;
1407
+ }
1408
+
1409
+ var compactPattern, compactDigits, compactProperties, divisor, numberExponent, pluralForm;
1410
+
1411
+ // Compact mode: initial number digit processing
1412
+ if ( compactMap ) {
1413
+ numberExponent = Math.abs( Math.floor( number ) ).toString().length - 1;
1414
+ numberExponent = Math.min( numberExponent, compactMap.maxExponent );
1415
+
1416
+ // Use default plural form to perform initial decimal shift
1417
+ if ( numberExponent >= 3 ) {
1418
+ compactPattern = compactMap[ numberExponent ] && compactMap[ numberExponent ].other;
1419
+ }
1420
+
1421
+ if ( compactPattern === "0" ) {
1422
+ compactPattern = null;
1423
+ } else if ( compactPattern ) {
1424
+ compactDigits = compactPattern.split( "0" ).length - 1;
1425
+ divisor = numberExponent - ( compactDigits - 1 );
1426
+ number = number / Math.pow( 10, divisor );
1427
+ }
1428
+ }
1429
+
1430
+ // Significant digit format
1431
+ if ( !isNaN( minimumSignificantDigits * maximumSignificantDigits ) ) {
1432
+ number = numberFormatSignificantDigits( number, minimumSignificantDigits,
1433
+ maximumSignificantDigits, round );
1434
+
1435
+ // Integer and fractional format
1436
+ } else {
1437
+ number = numberFormatIntegerFractionDigits( number, minimumIntegerDigits,
1438
+ minimumFractionDigits, maximumFractionDigits, round, roundIncrement );
1439
+ }
1440
+
1441
+ // Compact mode: apply formatting
1442
+ if ( compactMap && compactPattern ) {
1443
+
1444
+ // Get plural form after possible roundings
1445
+ pluralForm = pluralGenerator ? pluralGenerator( +number ) : "other";
1446
+
1447
+ compactPattern = compactMap[ numberExponent ][ pluralForm ] || compactPattern;
1448
+ compactProperties = compactPattern.match( numberCompactPatternRe );
1449
+
1450
+ // TODO Move the tokenization of all parts that don't depend on number into
1451
+ // format-properties.
1452
+ aux = function( string ) {
1453
+ var parts = [];
1454
+ string.replace( /(\s+)|([^\s0]+)/g, function( _garbage, space, compact ) {
1455
+
1456
+ // Literals
1457
+ if ( space ) {
1458
+ partsPush( parts, "literal", space );
1459
+ return;
1460
+ }
1461
+
1462
+ // Compact value
1463
+ if ( compact ) {
1464
+ partsPush( parts, "compact", compact );
1465
+ return;
1466
+ }
1467
+ });
1468
+ return parts;
1469
+ };
1470
+
1471
+ // update prefix/suffix with compact prefix/suffix
1472
+ prefix = prefix.concat( aux( compactProperties[ 1 ] ) );
1473
+ suffix = aux( compactProperties[ 3 ] ).concat( suffix );
1474
+ }
1475
+
1476
+ // Remove the possible number minus sign
1477
+ number = number.replace( /^-/, "" );
1478
+
1479
+ // Grouping separators
1480
+ if ( primaryGroupingSize ) {
1481
+ number = numberFormatGroupingSeparator( number, primaryGroupingSize,
1482
+ secondaryGroupingSize );
1483
+ }
1484
+
1485
+ // Scientific notation
1486
+ // TODO implement here
1487
+
1488
+ // Padding/'([^']|'')+'|''|[.,\-+E%\u2030]/g
1489
+ // TODO implement here
1490
+
1491
+ return prefix.concat(
1492
+ stringToParts( number ),
1493
+ suffix
1494
+ );
1495
+ };
1496
+
1497
+
1498
+
1499
+
1500
+ var numberToPartsFormatterFn = function( properties, pluralGenerator ) {
1501
+ return function numberToPartsFormatter( value ) {
1502
+ validateParameterPresence( value, "value" );
1503
+ validateParameterTypeNumber( value, "value" );
1504
+
1505
+ return numberFormat( value, properties, pluralGenerator );
1506
+ };
1507
+ };
1508
+
1509
+
1510
+
1511
+
1512
+ function validateDigits( properties ) {
1513
+ var minimumIntegerDigits = properties[ 2 ],
1514
+ minimumFractionDigits = properties[ 3 ],
1515
+ maximumFractionDigits = properties[ 4 ],
1516
+ minimumSignificantDigits = properties[ 5 ],
1517
+ maximumSignificantDigits = properties[ 6 ];
1518
+
1519
+ // Validate significant digit format properties
1520
+ if ( !isNaN( minimumSignificantDigits * maximumSignificantDigits ) ) {
1521
+ validateParameterRange( minimumSignificantDigits, "minimumSignificantDigits", 1, 21 );
1522
+ validateParameterRange( maximumSignificantDigits, "maximumSignificantDigits",
1523
+ minimumSignificantDigits, 21 );
1524
+
1525
+ } else if ( !isNaN( minimumSignificantDigits ) || !isNaN( maximumSignificantDigits ) ) {
1526
+ throw new Error( "Neither or both the minimum and maximum significant digits must be " +
1527
+ "present" );
1528
+
1529
+ // Validate integer and fractional format
1530
+ } else {
1531
+ validateParameterRange( minimumIntegerDigits, "minimumIntegerDigits", 1, 21 );
1532
+ validateParameterRange( minimumFractionDigits, "minimumFractionDigits", 0, 20 );
1533
+ validateParameterRange( maximumFractionDigits, "maximumFractionDigits",
1534
+ minimumFractionDigits, 20 );
1535
+ }
1536
+ }
1537
+
1538
+ /**
1539
+ * .numberFormatter( [options] )
1540
+ *
1541
+ * @options [Object]:
1542
+ * - style: [String] "decimal" (default) or "percent".
1543
+ * - see also number/format options.
1544
+ *
1545
+ * Return a function that formats a number according to the given options and default/instance
1546
+ * locale.
1547
+ */
1548
+ Globalize.numberFormatter =
1549
+ Globalize.prototype.numberFormatter = function( options ) {
1550
+ var args, numberToPartsFormatter, returnFn;
1551
+
1552
+ validateParameterTypePlainObject( options, "options" );
1553
+
1554
+ options = options || {};
1555
+ args = [ options ];
1556
+
1557
+ numberToPartsFormatter = this.numberToPartsFormatter( options );
1558
+ returnFn = numberFormatterFn( numberToPartsFormatter );
1559
+ runtimeBind( args, this.cldr, returnFn, [ numberToPartsFormatter ] );
1560
+
1561
+ return returnFn;
1562
+ };
1563
+
1564
+ /**
1565
+ * .numberToPartsFormatter( [options] )
1566
+ *
1567
+ * @options [Object]:
1568
+ * - style: [String] "symbol" (default), "accounting", "code" or "name".
1569
+ * - see also number/format options.
1570
+ *
1571
+ * Return a function that formats a number to parts according to the given options and
1572
+ * default/instance locale.
1573
+ */
1574
+ Globalize.numberToPartsFormatter =
1575
+ Globalize.prototype.numberToPartsFormatter = function( options ) {
1576
+ var args, cldr, fnArgs, pattern, properties, returnFn;
1577
+
1578
+ validateParameterTypePlainObject( options, "options" );
1579
+
1580
+ options = options || {};
1581
+ cldr = this.cldr;
1582
+
1583
+ args = [ options ];
1584
+
1585
+ validateDefaultLocale( cldr );
1586
+
1587
+ cldr.on( "get", validateCldr );
1588
+ try {
1589
+ if ( options.raw ) {
1590
+ pattern = options.raw;
1591
+ } else {
1592
+ pattern = numberPattern( options.style || "decimal", cldr );
1593
+ }
1594
+
1595
+ properties = numberFormatProperties( pattern, cldr, options );
1596
+ fnArgs = [ properties ];
1597
+ } finally {
1598
+ cldr.off( "get", validateCldr );
1599
+ }
1600
+
1601
+ validateDigits( properties );
1602
+
1603
+ if ( options.compact ) {
1604
+ fnArgs.push( this.pluralGenerator() );
1605
+ }
1606
+ returnFn = numberToPartsFormatterFn.apply( null, fnArgs );
1607
+ runtimeBind( args, cldr, returnFn, fnArgs );
1608
+
1609
+ return returnFn;
1610
+ };
1611
+
1612
+ /**
1613
+ * .numberParser( [options] )
1614
+ *
1615
+ * @options [Object]:
1616
+ * - style: [String] "decimal" (default) or "percent".
1617
+ *
1618
+ * Return the number parser according to the default/instance locale.
1619
+ */
1620
+ Globalize.numberParser =
1621
+ Globalize.prototype.numberParser = function( options ) {
1622
+ var args, cldr, pattern, properties, returnFn;
1623
+
1624
+ validateParameterTypePlainObject( options, "options" );
1625
+
1626
+ options = options || {};
1627
+ cldr = this.cldr;
1628
+
1629
+ args = [ options ];
1630
+
1631
+ validateDefaultLocale( cldr );
1632
+ if ( options.compact ) {
1633
+ throw createErrorUnsupportedFeature({
1634
+ feature: "compact number parsing (not implemented)"
1635
+ });
1636
+ }
1637
+
1638
+ cldr.on( "get", validateCldr );
1639
+
1640
+ if ( options.raw ) {
1641
+ pattern = options.raw;
1642
+ } else {
1643
+ pattern = numberPattern( options.style || "decimal", cldr );
1644
+ }
1645
+
1646
+ properties = numberParseProperties( pattern, cldr, options );
1647
+
1648
+ cldr.off( "get", validateCldr );
1649
+
1650
+ returnFn = numberParserFn( properties );
1651
+
1652
+ runtimeBind( args, cldr, returnFn, [ properties ] );
1653
+
1654
+ return returnFn;
1655
+ };
1656
+
1657
+ /**
1658
+ * .formatNumber( value [, options] )
1659
+ *
1660
+ * @value [Number] number to be formatted.
1661
+ *
1662
+ * @options [Object]: see number/format-properties.
1663
+ *
1664
+ * Format a number according to the given options and default/instance locale.
1665
+ */
1666
+ Globalize.formatNumber =
1667
+ Globalize.prototype.formatNumber = function( value, options ) {
1668
+ validateParameterPresence( value, "value" );
1669
+ validateParameterTypeNumber( value, "value" );
1670
+
1671
+ return this.numberFormatter( options )( value );
1672
+ };
1673
+
1674
+ /**
1675
+ * .formatNumberToParts( value [, options] )
1676
+ *
1677
+ * @value [Number] number to be formatted.
1678
+ *
1679
+ * @options [Object]: see number/format-properties.
1680
+ *
1681
+ * Format a number to pars according to the given options and default/instance locale.
1682
+ */
1683
+ Globalize.formatNumberToParts =
1684
+ Globalize.prototype.formatNumberToParts = function( value, options ) {
1685
+ validateParameterPresence( value, "value" );
1686
+ validateParameterTypeNumber( value, "value" );
1687
+
1688
+ return this.numberToPartsFormatter( options )( value );
1689
+ };
1690
+
1691
+ /**
1692
+ * .parseNumber( value [, options] )
1693
+ *
1694
+ * @value [String]
1695
+ *
1696
+ * @options [Object]: See numberParser().
1697
+ *
1698
+ * Return the parsed Number (including Infinity) or NaN when value is invalid.
1699
+ */
1700
+ Globalize.parseNumber =
1701
+ Globalize.prototype.parseNumber = function( value, options ) {
1702
+ validateParameterPresence( value, "value" );
1703
+ validateParameterTypeString( value, "value" );
1704
+
1705
+ return this.numberParser( options )( value );
1706
+ };
1707
+
1708
+ /**
1709
+ * Optimization to avoid duplicating some internal functions across modules.
1710
+ */
1711
+ Globalize._createErrorUnsupportedFeature = createErrorUnsupportedFeature;
1712
+ Globalize._numberNumberingSystem = numberNumberingSystem;
1713
+ Globalize._numberNumberingSystemDigitsMap = numberNumberingSystemDigitsMap;
1714
+ Globalize._numberPattern = numberPattern;
1715
+ Globalize._numberSymbol = numberSymbol;
1716
+ Globalize._looseMatching = looseMatching;
1717
+ Globalize._removeLiteralQuotes = removeLiteralQuotes;
1718
+ Globalize._stringPad = stringPad;
1719
+ Globalize._validateParameterTypeNumber = validateParameterTypeNumber;
1720
+ Globalize._validateParameterTypeString = validateParameterTypeString;
1721
+
1722
+ return Globalize;
1723
+
1724
+
1725
+
1726
+
1727
+ }));