-
Notifications
You must be signed in to change notification settings - Fork 9
Expand file tree
/
Copy pathspec.emu
More file actions
374 lines (355 loc) · 24.4 KB
/
spec.emu
File metadata and controls
374 lines (355 loc) · 24.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
<!doctype html>
<meta charset="utf8">
<link rel="stylesheet" href="./spec.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.4/styles/github.min.css">
<script src="./spec.js"></script>
<pre class="metadata">
title: Amount
status: proposal
stage: 1
contributors: Ben Allen, Jesse Alama
location: https://github.com/tc39/proposal-amount/
</pre>
<emu-intro id="sec-decimal-intro-">
<h1>Introduction</h1>
<p>This specification consists of two parts:</p>
<ul>
<li>The specification of the <a href="https://github.com/tc39/proposal-amount/" title="Amount proposal (GitHub)">Amount proposal</a> and everything related to it, proposed to be added to ECMA​-262 in new sections;</li>
<li>A list of amendments to be made to ECMA-402.</li>
</ul>
<emu-note type="editor">
<p>
The changes proposed here are stacked on top of the <a href="https://tc39.es/proposal-intl-keep-trailing-zeros/">Keep Trailing Zeros</a> ECMA-402 proposal,
and include calls to ECMA-402 Abstract Operations from ECMA​-262 algorithms.
Where necessary, we intend to promote those semantics to ECMA​-262.
</p>
</emu-note>
</emu-intro>
<emu-clause id="sec-the-amount-object">
<h1>The Amount Object</h1>
<emu-intro id="sec-amount-intro">
<h1>Introduction</h1>
<p>An Amount is an object that wraps a numeric value—as a Number, BigInt, or String—together with an optional unit (e.g., mile, kilogram, EUR, JPY, USD-per-mile). One can intuitively understand an Amount as a value that, so to speak, knows what it is measuring.</p>
<p>When precision options (such as fractionDigits or significantDigits) are applied, or when unit conversion is performed, the numeric value is stored as a <dfn id="dfn-decimal-digit-string">decimal digit string</dfn>, which is a String in |StrDecimalLiteral| form or *"NaN"*. Otherwise, the original JavaScript value type (Number, BigInt, or String) is retained.</p>
<p>Rounding a mathematical value is an important part of this spec. When we say <dfn id="dfn-amount-rounding-mode">rounding mode</dfn> in this specification we simply refer to <emu-xref href="#table-intl-rounding-modes">ECMA-402's definition</emu-xref>.</p>
</emu-intro>
<emu-clause id="sec-amount-abstract-operations">
<h1>Abstract Operations</h1>
<!-- Copied and modified from ECMA-402 GetOption -->
<!-- The difference: -->
<!-- Added support for ~number~ as an expected data type -->
<emu-clause id="sec-getoption" type="abstract operation">
<h1>
GetOption (
_options_: an Object,
_property_: a property key,
_type_: ~boolean~, ~string~ or ~number~,
_values_: ~empty~ or a List of ECMAScript language values,
_default_: ~required~ or an ECMAScript language value,
): either a normal completion containing an ECMAScript language value or a throw completion
</h1>
<dl class="header">
<dt>description</dt>
<dd>It extracts the value of the specified property of _options_, converts it to the required _type_, checks whether it is allowed by _values_ if _values_ is not ~empty~, and substitutes _default_ if the value is *undefined*.</dd>
</dl>
<emu-alg>
1. Let _value_ be ? Get(_options_, _property_).
1. If _value_ is *undefined*, then
1. If _default_ is ~required~, throw a *RangeError* exception.
1. Return _default_.
1. If _type_ is ~boolean~, then
1. Set _value_ to ToBoolean(_value_).
1. Else if _type_ is ~number~, then
1. Set _value_ to ? ToNumber(_value_).
1. Else,
1. Assert: _type_ is ~string~.
1. Set _value_ to ? ToString(_value_).
1. If _values_ is not ~empty~ and _values_ does not contain _value_, throw a *RangeError* exception.
1. Return _value_.
</emu-alg>
</emu-clause>
<emu-clause id="sec-amount-getamountoptions" type="abstract operation">
<h1>GetAmountOptions (
_opts_: an Object
): either a normal completion containing a Record with fields [[FractionDigits]] (a non-negative integer or *undefined*), [[RoundingMode]] (a <emu-xref href="#dfn-amount-rounding-mode">rounding mode</emu-xref>), [[SignificantDigits]] (a positive integer or *undefined*), and [[Unit]] (a String or *undefined*) or a throw completion
</h1>
<dl class="header">
<dt>description</dt>
<dd>It validates the given _options_ (an ECMAScript object) for creating an Amount and returns a Record with slots set to appropriate marthematical values (or *undefined*).</dd>
</dl>
<emu-alg>
1. Let _opts_ be ? GetOptionsObject(_opts_).
1. Let _fractionDigits_ be ? GetOption(_opts_, *"fractionDigits"*, ~number~, ~empty~, *undefined*).
1. Let _roundingMode_ be ? GetOption(_opts_, *"roundingMode"*, ~string~, « *"ceil"*, *"floor"*, *"expand"*, *"trunc"*, *"halfCeil"*, *"halfFloor"*, *"halfExpand"*, *"halfTrunc"*, *"halfEven"* », *"halfEven"*).
1. Let _significantDigits_ be ? GetOption(_opts_, *"significantDigits"*, ~number~, ~empty~, *undefined*).
1. Let _unit_ be ? GetOption(_opts_, *"unit"*, ~string~, ~empty~, *undefined*).
1. If _fractionDigits_ is not *undefined*, then
1. If _significantDigits_ is not *undefined*, throw a *RangeError* exception.
1. If _fractionDigits_ is not an integral Number, throw a *RangeError* exception.
1. Else if _significantDigits_ is not *undefined*, then
1. If _significantDigits_ is not an integral Number, throw a *RangeError* exception.
1. If _significantDigits_ < *1*<sub>𝔽</sub>, throw a *RangeError* exception.
1. If _unit_ is the empty String, throw a *RangeError* exception.
1. Return the Record { [[FractionDigits]]: _fractionDigits_, [[RoundingMode]]: _roundingMode_, [[SignificantDigits]]: _significantDigits_, [[Unit]]: _unit_ }.
</emu-alg>
</emu-clause>
<emu-clause id="sec-amount-getamountconverttooptions" type="abstract operation">
<h1>GetAmountConvertToOptions (
_opts_: an Object
): either a normal completion containing a Record with fields [[MinFractionDigits]] (a non-negative integer or *undefined*), [[MaxFractionDigits]] (a non-negative integer or *undefined*), [[RoundingMode]] (a <emu-xref href="#dfn-amount-rounding-mode">rounding mode</emu-xref>), [[RoundingPriority]] (a String), [[MinSignificantDigits]] (a positive integer or *undefined*), [[MaxSignificantDigits]] (a positive integer or *undefined*), [[Locale]] (a String or *undefined*), [[Usage]] (a String or *undefined*), and [[Unit]] (a String or *undefined*) or a throw completion
</h1>
<dl class="header">
<dt>description</dt>
<dd>It validates the given _options_ (an ECMAScript object) for converting an Amount to another Amount and returns a Record with slots set to appropriate marthematical values (or *undefined*).</dd>
</dl>
<emu-alg>
1. Let _opts_ be ? GetOptionsObject(_opts_).
1. Let _minFractionDigits_ be ? GetOption(_opts_, *"minimumfractionDigits"*, ~number~, ~empty~, *undefined*).
1. Let _maxFractionDigits_ be ? GetOption(_opts_, *"maximumfractionDigits"*, ~number~, ~empty~, *undefined*).
1. Let _roundingMode_ be ? GetOption(_opts_, *"roundingMode"*, ~string~, « *"ceil"*, *"floor"*, *"expand"*, *"trunc"*, *"halfCeil"*, *"halfFloor"*, *"halfExpand"*, *"halfTrunc"*, *"halfEven"* », *"halfEven"*).
1. Let _roundingPriority_ be ? GetOption(_opts_, *"roundingPriority"*, ~string~, ~empty~, *undefined*).
1. Let _minSignificantDigits_ be ? GetOption(_opts_, *"minimumSignificantDigits"*, ~number~, ~empty~, *undefined*).
1. Let _maxSignificantDigits_ be ? GetOption(_opts_, *"maximumSignificantDigits"*, ~number~, ~empty~, *undefined*).
1. Let _significantDigits_ be ? GetOption(_opts_, *"maximumSignificantDigits"*, ~number~, ~empty~, *undefined*).
1. Let _unit_ be ? GetOption(_opts_, *"unit"*, ~string~, ~empty~, *undefined*).
1. If _minFractionDigits_ is not *undefined* and not an integral Number, throw a *RangeError* exception.
1. If _maxFractionDigits_ is not *undefined* and not an integral Number, throw a *RangeError* exception.
1. If _minSignificantDigits_ is not *undefined* and not an integral Number, throw a *RangeError* exception.
1. If _maxSignificantDigits_ is not *undefined* and not an integral Number, throw a *RangeError* exception.
1. If _unit_ is the empty String, throw a *RangeError* exception.
1. Return the Record { [[MinimumFractionDigits]]: _minFractionDigits_, [[MaximumFractionDigits]]: _maxFractionDigits_, [[MinimumSignificantDigits]]: _minSignificantDigits_, [[MaximumSignificantDigits]]: _maxSignificantDigits_, [[RoundingMode]]: _roundingMode_, [[RoundingPriority]]: _roundingPriority_, [[SignificantDigits]]: _significantDigits_, [[Unit]]: _unit_ }.
</emu-alg>
<emu-note type="editor">
<p>
This abstract operation will need to be overridden in the 402 part because it will read additional Intl-specific properties beyond these.
</p>
</emu-note>
</emu-clause>
<emu-clause id="sec-amount-unit-conversion-data">
<h1>Unit Conversion Data</h1>
<p>Unit conversion data is derived from CLDR file <a href="https://github.com/unicode-org/cldr/blob/main/common/supplemental/units.xml"><code>units.xml</code></a>. As described in <a href="https://unicode.org/reports/tr35/tr35-info.html#conversion-data">Unicode Technical Standard #35 Part 6 Supplemental, Conversion Data</a>, each <code><convertUnit></code> element defines how to convert a <code>source</code> unit into a compatible <code>baseUnit</code>. An ECMAScript implementation must ignore all <code>special</code> conversions and support all conversions based on <code>factor</code> and/or <code>offset</code>, interpreting the value for each as an arithmetic expression with mathematical value operands (noting the respective defaults of 1 and 0 and the implicit presence of an identity mapping for each unit identified as the value of a <code>baseUnit</code>).</p>
<p>Two units are convertible if and only if they share the same <code>baseUnit</code> value in CLDR. A unit that appears as a <code>baseUnit</code> value has an implicit identity conversion (<code>factor</code> 1, <code>offset</code> 0).</p>
<emu-note>
<p>In <code>factor</code> and <code>offset</code> expressions, <code>*</code> multiplication binds more tightly than <code>/</code> division, and constants defined by <code><unitConstant></code> elements are valid operands.</p>
<p>For example:</p>
<ul>
<li><code><convertUnit source='celsius' baseUnit='kelvin' offset='273.15' systems="si metric"/></code> specifies that conversion from unit "celsius" to unit "kelvin" requires addition of 273.15.</li>
<li><code><convertUnit source='fahrenheit' baseUnit='kelvin' factor='5/9' offset='2298.35/9' systems="ussystem uksystem"/></code> specifies that conversion from unit "fahrenheit" to unit "kelvin" requires multiplication by (5 / 9) followed by addition of (2298.35 / 9).</li>
<li><code><convertUnit source='radian' baseUnit='revolution' factor='1/2*PI' systems="si metric"/></code> specifies that conversion from unit "radian" to unit "revolution" requires multiplication by (1 / (2 × <code>PI</code>)), which references <code><unitConstant constant="PI" value="411557987 / 131002976" status='approximate'/></code> and is thus equivalent to multiplication by (1 / (2 × (411557987 / 131002976))) = (131002976 / 823115974).</li>
<li><code><convertUnit source='solar-mass' baseUnit='kilogram' factor='1.98847E+30' systems="astronomical"/></code> specifies that conversion from unit "solar-mass" to unit "kilogram" requires multiplication by (1.98847 × 10<sup>30</sup>).</li>
</ul>
</emu-note>
</emu-clause>
<emu-clause id="sec-amount-getunitconversionfactor" type="abstract operation">
<h1>GetUnitConversionFactor (
_unit_: a String
): either a normal completion containing a Record with fields [[BaseUnit]] (a String), [[Factor]] (a mathematical value), and [[Offset]] (a mathematical value) or a throw completion
</h1>
<dl class="header">
<dt>description</dt>
<dd>It returns the conversion data for converting _unit_ to its base unit.</dd>
</dl>
<emu-alg>
1. If _unit_ is the <code>source</code> of a <code><convertUnit></code> element in the <emu-xref href="#sec-amount-unit-conversion-data">unit conversion data</emu-xref>, then
1. Let _element_ be that <code><convertUnit></code> element.
1. If _element_ has an attribute <code>special</code>, throw a *TypeError* exception.
1. Let _baseUnit_ be the <code>baseUnit</code> of _element_.
1. Let _factor_ be the mathematical value of the <code>factor</code> attribute of _element_ if present, or 1 otherwise.
1. Let _offset_ be the mathematical value of the <code>offset</code> attribute of _element_ if present, or 0 otherwise.
1. Else if _unit_ is a <code>baseUnit</code> value in the <emu-xref href="#sec-amount-unit-conversion-data">unit conversion data</emu-xref>, then
1. Let _baseUnit_ be _unit_.
1. Let _factor_ be 1.
1. Let _offset_ be 0.
1. Else,
1. Throw a *TypeError* exception.
1. Return the Record { [[BaseUnit]]: _baseUnit_, [[Factor]]: _factor_, [[Offset]]: _offset_ }.
</emu-alg>
<emu-note>
<p>The formula for converting a value in _unit_ to its base unit is: <i>baseValue</i> = <i>value</i> × [[Factor]] + [[Offset]].</p>
</emu-note>
</emu-clause>
<emu-clause id="sec-amount-convertunitvalue" type="abstract operation">
<h1>ConvertUnitValue (
_value_: a Number,
_sourceUnit_: a String,
_targetUnit_: a String
): either a normal completion containing a Number or a throw completion
</h1>
<dl class="header">
<dt>description</dt>
<dd>It converts _value_ from _sourceUnit_ to _targetUnit_ using Number arithmetic.</dd>
</dl>
<emu-alg>
1. If SameValue(_sourceUnit_, _targetUnit_) is *true*, return _value_.
1. Let _sourceConv_ be ? GetUnitConversionFactor(_sourceUnit_).
1. Let _targetConv_ be ? GetUnitConversionFactor(_targetUnit_).
1. If _sourceConv_.[[BaseUnit]] is not _targetConv_.[[BaseUnit]], throw a *TypeError* exception.
1. If _value_ is *NaN*, return *NaN*.
1. Let _sourceFactor_ be _sourceConv_.[[Factor]].
1. Let _sourceOffset_ be _sourceConv_.[[Offset]].
1. Let _targetFactor_ be _targetConv_.[[Factor]].
1. Let _targetOffset_ be _targetConv_.[[Offset]].
1. If _sourceOffset_ is _targetOffset_, then
1. NOTE: This preserves a _value_ of *-0*<sub>𝔽</sub>.
1. Return _value_ × 𝔽(_sourceFactor_ / _targetFactor_).
1. Return _value_ × 𝔽(_sourceFactor_ / _targetFactor_) + 𝔽((_sourceOffset_ - _targetOffset_) / _targetFactor_).
</emu-alg>
<emu-note>
<p>The factor term _sourceFactor_ / _targetFactor_ and the offset term (_sourceOffset_ − _targetOffset_) / _targetFactor_ are computed as mathematical values, and then converted to Number values for the multiplication and addition. For non-offset conversions (the vast majority), the offset term is 0 and addition is skipped in order to preserve an input _value_ of *-0*<sub>𝔽</sub>.</p>
</emu-note>
</emu-clause>
</emu-clause>
<emu-clause id="sec-the-amount-constructor">
<h1>The Amount Constructor</h1>
<p>The Amount constructor:</p>
<ul>
<li>is <dfn>%Amount%</dfn>.</li>
<li>is the initial value of the the *"Amount"* property of the global object.</li>
<li>creates and initializes a new Amount object when called as a constructor</li>
<li>may be used as the value of an *extends* clause of a class definition.</li>
</ul>
<emu-clause id="sec-the-amount-constructor-value">
<h1>Amount ( _x_ [ , _opts_ ] )</h1>
<emu-alg>
1. If NewTarget is *undefined*, throw a *TypeError* exception.
1. If _x_ is not a Number, not a BigInt, and not a String, throw a *TypeError* exception.
1. If _x_ is a String, then
1. Let _text_ be StringToCodePoints(_x_).
1. Let _parsed_ be ParseText(_text_, |StringNumericLiteral|).
1. If _parsed_ is a List of errors, throw a *RangeError* exception.
1. Let _validatedOpts_ be ? GetAmountOptions(_opts_).
1. Let _roundingMode_ be _validatedOpts_.[[RoundingMode]].
1. Let _fractionDigits_ be _validatedOpts_.[[FractionDigits]].
1. Let _significantDigits_ be _validatedOpts_.[[SignificantDigits]].
1. Let _unit_ be _validatedOpts_.[[Unit]].
1. If _x_ is a Number or _x_ is a BigInt, then
1. Let _value_ be _x_.
1. Else,
1. Assert: _x_ is a String.
1. TODO Let _intlObject_ be an Object suitable as a first argument <emu-xref href="#sec-formatnumerictostring">FormatNumericToString</emu-xref>, using _fractionDigits_, _significantDigits_, and _roundingMode_.
1. Let _intlMV_ be ! ToIntlMathematicalValue(_x_).
1. Let _formatted_ be FormatNumericToString(_intlObject_, _intlMV_.[[Value]], _intlMV_.[[StringDigitCount]]).
1. Let _value_ be _formatted_.[[FormattedString]].
1. Let _O_ be OrdinaryObjectCreate(%Amount.prototype%, « [[AmountValue]], [[Unit]] »).
1. Set _O_.[[AmountValue]] to _value_.
1. Set _O_.[[Unit]] to _unit_.
1. Return _O_.
</emu-alg>
<emu-note>
<p>When no precision options are given, Number and BigInt arguments are stored directly in [[AmountValue]], preserving the original type. String arguments are normalized to StrDecimalLiteral form. When precision options are specified, [[AmountValue]] always holds a String.</p>
</emu-note>
<emu-note type="editor">
<p>
We intend to move 402's FormatNumericToString, and its dependent AOs, to 262, possibly renamed.
</p>
</emu-note>
</emu-clause>
</emu-clause>
</emu-clause>
<emu-clause id="sec-amount-prototype-properties">
<h1>Properties of the Amount Prototype</h1>
<emu-clause id="sec-amount.prototype.value">
<h1>get Amount.prototype.value</h1>
<p>This accessor property, whose set accessor function is *undefined*, returns the numeric value of the Amount. Its get accessor function performs the following steps when called:</p>
<emu-alg>
1. Let _O_ be the *this* value.
1. Perform ? RequireInternalSlot(_O_, [[AmountValue]]).
1. Return _O_.[[AmountValue]].
</emu-alg>
<emu-note>
<p>The value may be a Number, BigInt, or String. It is a String when precision options were applied during construction or when the Amount is the result of unit conversion.</p>
</emu-note>
</emu-clause>
<emu-clause id="sec-amount.prototype.unit">
<h1>get Amount.prototype.unit</h1>
<p>This accessor property, whose set accessor function is *undefined*, returns a String value (or *undefined*) indicating the unit that this Amount has. Its get accessor function performs the following steps when called:</p>
<emu-alg>
1. Let _O_ be the *this* value.
1. Perform ? RequireInternalSlot(_O_, [[AmountValue]]).
1. Return _O_.[[Unit]].
</emu-alg>
</emu-clause>
<emu-clause id="sec-amount.prototype.tostring">
<h1>Amount.prototype.toString ( )</h1>
<p>This method returns a String representation of the Amount, including a unit indicator in bracket notation.</p>
<p>It performs the following steps when called:</p>
<emu-alg>
1. Let _O_ be the *this* value.
1. Perform ? RequireInternalSlot(_O_, [[AmountValue]]).
1. Let _v_ be _O_.[[AmountValue]].
1. Let _u_ be _O_.[[Unit]].
1. If _v_ is a String, then
1. Let _valueStr_ be _v_.
1. Else if _v_ is a Number, then
1. Let _valueStr_ be Number::toString(_v_, 10).
1. Else,
1. Assert: _v_ is a BigInt.
1. Let _valueStr_ be BigInt::toString(_v_, 10).
1. If _u_ is *undefined*, return the string-concatenation of _valueStr_ and *"[]"*.
1. Return the string-concatenation of _valueStr_, *"["*, _u_, and *"]"*.
</emu-alg>
</emu-clause>
<emu-clause id="sec-amount.prototype.tolocalestring">
<h1>Amount.prototype.toLocaleString ( [ _reserved1_ [ , _reserved2_ ] ] )</h1>
<p>An ECMAScript implementation that includes the ECMA-402 Internationalization API must implement this method as specified in the ECMA-402 specification. If an ECMAScript implementation does not include the ECMA-402 API the following specification of this method is used:</p>
<p>It performs the following steps when called:</p>
<emu-alg>
1. Let _O_ be the *this* value.
1. Perform ? RequireInternalSlot(_O_, [[AmountValue]]).
1. Return ? Call(%Amount.prototype.toString%, _O_, « »).
</emu-alg>
<p>The meanings of the optional parameters to this method are defined in the ECMA-402 specification; implementations that do not include ECMA-402 support must not use those parameter positions for anything else.</p>
</emu-clause>
<emu-clause id="sec-amount.prototype.convertto">
<h1>Amount.prototype.convertTo ( _options_ )</h1>
<p>This method returns a new Amount whose value is the result of converting this Amount’s value from its current unit to a target unit. The target unit is specified by _options_.</p>
<p>It performs the following steps when called:</p>
<emu-alg>
1. Let _O_ be the *this* value.
1. Perform ? RequireInternalSlot(_O_, [[AmountValue]]).
1. Let _sourceUnit_ be _O_.[[Unit]].
1. If _sourceUnit_ is *undefined*, throw a *TypeError* exception.
1. Let _validatedOpts_ be ? GetAmountConvertToOptions(_options_).
1. Let _targetUnit_ be _validatedOpts_.[[Unit]].
1. If _targetUnit_ is *undefined*, throw a *TypeError* exception.
1. Let _roundingMode_ be _validatedOpts_.[[RoundingMode]].
1. Let _roundingPriority_ be _validatedOpts_.[[RoundingPriority]].
1. Let _minFractionDigits_ be _validatedOpts_.[[MinimumFractionDigits]].
1. Let _maxFractionDigits_ be _validatedOpts_.[[MaximumFractionDigits]].
1. Let _minSignificantDigits_ be _validatedOpts_.[[MinimumSignificantDigits]].
1. Let _maxSignificantDigits_ be _validatedOpts_.[[MaximumSignificantDigits]].
1. Let _v_ be _O_.[[AmountValue]].
1. If _v_ is a Number, then
1. Let _sourceValue_ be _v_.
1. Else if _v_ is a BigInt, then
1. Let _sourceValue_ be 𝔽(ℝ(_v_)).
1. Else,
1. Assert: _v_ is a String.
1. Let _sourceValue_ be StringToNumber(_v_).
1. Let _convertedValue_ be ? ConvertUnitValue(_sourceValue_, _sourceUnit_, _targetUnit_).
1. TODO Let _intlObject_ be an Object suitable as the first argument of <emu-xref href="#sec-formatnumerictostring">FormatNumericToString</emu-xref>, using _minFractionDigits_, _maxFractionDigits_, _minSignificantDigits_, _maxSignificantDigits_, _roundingPriority_, and _roundingMode_.
1. Let _formatted_ be FormatNumericToString(_intlObject_, _convertedValue_, 0).
1. Let _result_ be OrdinaryObjectCreate(%Amount.prototype%, « [[AmountValue]], [[Unit]] »).
1. Set _result_.[[AmountValue]] to _formatted_.[[FormattedString]].
1. Set _result_.[[Unit]] to _targetUnit_.
1. Return _result_.
</emu-alg>
<emu-note>
<p>An ECMAScript implementation that includes the ECMA-402 Internationalization API supersedes this method to additionally support locale-based and usage-based unit conversion via CLDR unit preferences data. Without ECMA-402, only explicit unit-to-unit conversion (via the *"unit"* option) is supported.</p>
</emu-note>
</emu-clause>
</emu-clause>
<emu-import href="./intl.emu"></emu-import>
<emu-clause id="sec-normative-references">
<h1>Normative References</h1>
<ul>
<li>
<a href="https://unicode.org/reports/tr35/">Unicode Technical Standard #35: Unicode Locale Data Markup Language (LDML)</a>
<ul>
<li>
<a href="https://unicode.org/reports/tr35/tr35-info.html#Unit_Conversion">Part 6 Supplemental, Unit Conversion</a>
</li>
</ul>
</li>
</ul>
</emu-clause>