mustardscript 0.1.0 → 0.1.2

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 (96) hide show
  1. package/README.md +65 -22
  2. package/SECURITY.md +1 -1
  3. package/dist/index.js +2 -0
  4. package/dist/lib/executor.js +16 -1
  5. package/dist/lib/policy.js +301 -22
  6. package/dist/lib/progress.js +499 -113
  7. package/dist/lib/runtime.js +109 -40
  8. package/dist/lib/structured.js +327 -11
  9. package/dist/native-loader.js +11 -12
  10. package/index.d.ts +54 -6
  11. package/mustard.d.ts +23 -1
  12. package/package.json +34 -25
  13. package/Cargo.lock +0 -1579
  14. package/Cargo.toml +0 -40
  15. package/crates/mustard/Cargo.toml +0 -31
  16. package/crates/mustard/src/cancellation.rs +0 -28
  17. package/crates/mustard/src/diagnostic.rs +0 -145
  18. package/crates/mustard/src/ir.rs +0 -435
  19. package/crates/mustard/src/lib.rs +0 -21
  20. package/crates/mustard/src/limits.rs +0 -22
  21. package/crates/mustard/src/parser/expressions.rs +0 -723
  22. package/crates/mustard/src/parser/mod.rs +0 -115
  23. package/crates/mustard/src/parser/operators.rs +0 -105
  24. package/crates/mustard/src/parser/patterns.rs +0 -123
  25. package/crates/mustard/src/parser/scope.rs +0 -107
  26. package/crates/mustard/src/parser/statements.rs +0 -298
  27. package/crates/mustard/src/parser/tests/acceptance.rs +0 -339
  28. package/crates/mustard/src/parser/tests/mod.rs +0 -2
  29. package/crates/mustard/src/parser/tests/rejections.rs +0 -107
  30. package/crates/mustard/src/runtime/accounting.rs +0 -613
  31. package/crates/mustard/src/runtime/api.rs +0 -192
  32. package/crates/mustard/src/runtime/async_runtime/mod.rs +0 -5
  33. package/crates/mustard/src/runtime/async_runtime/promises.rs +0 -246
  34. package/crates/mustard/src/runtime/async_runtime/reactions.rs +0 -400
  35. package/crates/mustard/src/runtime/async_runtime/scheduler.rs +0 -224
  36. package/crates/mustard/src/runtime/builtins/arrays.rs +0 -1205
  37. package/crates/mustard/src/runtime/builtins/collections.rs +0 -573
  38. package/crates/mustard/src/runtime/builtins/install.rs +0 -501
  39. package/crates/mustard/src/runtime/builtins/intl.rs +0 -553
  40. package/crates/mustard/src/runtime/builtins/mod.rs +0 -25
  41. package/crates/mustard/src/runtime/builtins/objects.rs +0 -405
  42. package/crates/mustard/src/runtime/builtins/primitives.rs +0 -859
  43. package/crates/mustard/src/runtime/builtins/promises.rs +0 -335
  44. package/crates/mustard/src/runtime/builtins/regexp.rs +0 -356
  45. package/crates/mustard/src/runtime/builtins/strings.rs +0 -803
  46. package/crates/mustard/src/runtime/builtins/support.rs +0 -561
  47. package/crates/mustard/src/runtime/bytecode.rs +0 -123
  48. package/crates/mustard/src/runtime/compiler/assignments.rs +0 -690
  49. package/crates/mustard/src/runtime/compiler/bindings.rs +0 -92
  50. package/crates/mustard/src/runtime/compiler/context.rs +0 -46
  51. package/crates/mustard/src/runtime/compiler/control.rs +0 -342
  52. package/crates/mustard/src/runtime/compiler/expressions.rs +0 -372
  53. package/crates/mustard/src/runtime/compiler/mod.rs +0 -173
  54. package/crates/mustard/src/runtime/compiler/statements.rs +0 -459
  55. package/crates/mustard/src/runtime/conversions/boundary.rs +0 -293
  56. package/crates/mustard/src/runtime/conversions/coercions.rs +0 -217
  57. package/crates/mustard/src/runtime/conversions/errors.rs +0 -118
  58. package/crates/mustard/src/runtime/conversions/mod.rs +0 -14
  59. package/crates/mustard/src/runtime/conversions/operators.rs +0 -334
  60. package/crates/mustard/src/runtime/env.rs +0 -355
  61. package/crates/mustard/src/runtime/exceptions.rs +0 -377
  62. package/crates/mustard/src/runtime/gc.rs +0 -595
  63. package/crates/mustard/src/runtime/mod.rs +0 -318
  64. package/crates/mustard/src/runtime/properties.rs +0 -1762
  65. package/crates/mustard/src/runtime/serialization.rs +0 -127
  66. package/crates/mustard/src/runtime/shared.rs +0 -108
  67. package/crates/mustard/src/runtime/snapshot_validation_tests.rs +0 -93
  68. package/crates/mustard/src/runtime/state.rs +0 -652
  69. package/crates/mustard/src/runtime/tests/async_host.rs +0 -104
  70. package/crates/mustard/src/runtime/tests/collections.rs +0 -50
  71. package/crates/mustard/src/runtime/tests/diagnostics.rs +0 -36
  72. package/crates/mustard/src/runtime/tests/exceptions.rs +0 -122
  73. package/crates/mustard/src/runtime/tests/execution.rs +0 -553
  74. package/crates/mustard/src/runtime/tests/gc.rs +0 -533
  75. package/crates/mustard/src/runtime/tests/mod.rs +0 -56
  76. package/crates/mustard/src/runtime/tests/serialization.rs +0 -170
  77. package/crates/mustard/src/runtime/validation/bytecode.rs +0 -484
  78. package/crates/mustard/src/runtime/validation/mod.rs +0 -14
  79. package/crates/mustard/src/runtime/validation/policy.rs +0 -94
  80. package/crates/mustard/src/runtime/validation/snapshot.rs +0 -406
  81. package/crates/mustard/src/runtime/validation/walk.rs +0 -206
  82. package/crates/mustard/src/runtime/vm.rs +0 -1016
  83. package/crates/mustard/src/span.rs +0 -22
  84. package/crates/mustard/src/structured.rs +0 -107
  85. package/crates/mustard-bridge/Cargo.toml +0 -17
  86. package/crates/mustard-bridge/src/codec.rs +0 -46
  87. package/crates/mustard-bridge/src/dto.rs +0 -99
  88. package/crates/mustard-bridge/src/lib.rs +0 -12
  89. package/crates/mustard-bridge/src/operations.rs +0 -142
  90. package/crates/mustard-node/Cargo.toml +0 -24
  91. package/crates/mustard-node/build.rs +0 -3
  92. package/crates/mustard-node/src/lib.rs +0 -236
  93. package/crates/mustard-sidecar/Cargo.toml +0 -21
  94. package/crates/mustard-sidecar/src/lib.rs +0 -134
  95. package/crates/mustard-sidecar/src/main.rs +0 -36
  96. package/dist/install.js +0 -117
@@ -1,553 +0,0 @@
1
- use super::*;
2
-
3
- impl Runtime {
4
- fn normalize_intl_locale(&self, value: Option<Value>) -> MustardResult<String> {
5
- let Some(value) = value else {
6
- return Ok("en-US".to_string());
7
- };
8
- match value {
9
- Value::Undefined => Ok("en-US".to_string()),
10
- Value::String(locale) if locale == "en-US" => Ok(locale),
11
- Value::Array(array) => {
12
- let first = self
13
- .arrays
14
- .get(array)
15
- .ok_or_else(|| MustardError::runtime("array missing"))?
16
- .elements
17
- .iter()
18
- .flatten()
19
- .next()
20
- .cloned()
21
- .unwrap_or(Value::String("en-US".to_string()));
22
- self.normalize_intl_locale(Some(first))
23
- }
24
- _ => Err(MustardError::runtime(
25
- "TypeError: Intl currently supports only the `en-US` locale",
26
- )),
27
- }
28
- }
29
-
30
- fn intl_options_object(&self, value: Option<Value>) -> MustardResult<Option<ObjectKey>> {
31
- match value.unwrap_or(Value::Undefined) {
32
- Value::Undefined | Value::Null => Ok(None),
33
- Value::Object(object) => Ok(Some(object)),
34
- _ => Err(MustardError::runtime(
35
- "TypeError: Intl options must be a plain object in the supported surface",
36
- )),
37
- }
38
- }
39
-
40
- fn intl_option_value(&self, object: Option<ObjectKey>, key: &str) -> MustardResult<Value> {
41
- let Some(object) = object else {
42
- return Ok(Value::Undefined);
43
- };
44
- Ok(self
45
- .objects
46
- .get(object)
47
- .ok_or_else(|| MustardError::runtime("object missing"))?
48
- .properties
49
- .get(key)
50
- .cloned()
51
- .unwrap_or(Value::Undefined))
52
- }
53
-
54
- fn intl_option_field_style(
55
- &self,
56
- object: Option<ObjectKey>,
57
- key: &str,
58
- ) -> MustardResult<Option<IntlFieldStyle>> {
59
- Ok(match self.intl_option_value(object, key)? {
60
- Value::Undefined => None,
61
- Value::String(value) if value == "numeric" => Some(IntlFieldStyle::Numeric),
62
- Value::String(value) if value == "2-digit" => Some(IntlFieldStyle::TwoDigit),
63
- _ => {
64
- return Err(MustardError::runtime(format!(
65
- "TypeError: Intl.{key} only supports `numeric` or `2-digit`",
66
- )));
67
- }
68
- })
69
- }
70
-
71
- fn intl_option_string(
72
- &self,
73
- object: Option<ObjectKey>,
74
- key: &str,
75
- ) -> MustardResult<Option<String>> {
76
- Ok(match self.intl_option_value(object, key)? {
77
- Value::Undefined => None,
78
- value => Some(self.to_string(value)?),
79
- })
80
- }
81
-
82
- fn intl_option_bool(
83
- &self,
84
- object: Option<ObjectKey>,
85
- key: &str,
86
- ) -> MustardResult<Option<bool>> {
87
- Ok(match self.intl_option_value(object, key)? {
88
- Value::Undefined => None,
89
- Value::Bool(value) => Some(value),
90
- _ => {
91
- return Err(MustardError::runtime(format!(
92
- "TypeError: Intl `{key}` must be a boolean in the supported surface",
93
- )));
94
- }
95
- })
96
- }
97
-
98
- fn intl_option_digits(
99
- &self,
100
- object: Option<ObjectKey>,
101
- key: &str,
102
- ) -> MustardResult<Option<usize>> {
103
- match self.intl_option_value(object, key)? {
104
- Value::Undefined => Ok(None),
105
- value => {
106
- let digits = self.to_integer(value)?;
107
- if !(0..=20).contains(&digits) {
108
- return Err(MustardError::runtime(format!(
109
- "RangeError: Intl `{key}` must be between 0 and 20",
110
- )));
111
- }
112
- Ok(Some(digits as usize))
113
- }
114
- }
115
- }
116
-
117
- fn intl_assert_supported_option_keys(
118
- &self,
119
- object: Option<ObjectKey>,
120
- ctor: &str,
121
- allowed: &[&str],
122
- ) -> MustardResult<()> {
123
- let Some(object) = object else {
124
- return Ok(());
125
- };
126
- for key in self
127
- .objects
128
- .get(object)
129
- .ok_or_else(|| MustardError::runtime("object missing"))?
130
- .properties
131
- .keys()
132
- {
133
- if !allowed
134
- .iter()
135
- .any(|allowed_key| allowed_key == &key.as_str())
136
- {
137
- return Err(MustardError::runtime(format!(
138
- "TypeError: Intl.{ctor} does not support the `{key}` option",
139
- )));
140
- }
141
- }
142
- Ok(())
143
- }
144
-
145
- pub(crate) fn construct_intl_date_time_format(
146
- &mut self,
147
- args: &[Value],
148
- ) -> MustardResult<Value> {
149
- let locale = self.normalize_intl_locale(args.first().cloned())?;
150
- let options = self.intl_options_object(args.get(1).cloned())?;
151
- self.intl_assert_supported_option_keys(
152
- options,
153
- "DateTimeFormat",
154
- &[
155
- "timeZone", "year", "month", "day", "hour", "minute", "second",
156
- ],
157
- )?;
158
- let time_zone = match self.intl_option_string(options, "timeZone")? {
159
- None => "UTC".to_string(),
160
- Some(value) if value == "UTC" => value,
161
- Some(_) => {
162
- return Err(MustardError::runtime(
163
- "TypeError: Intl.DateTimeFormat currently supports only the `UTC` timeZone",
164
- ));
165
- }
166
- };
167
- let mut year = self.intl_option_field_style(options, "year")?;
168
- let mut month = self.intl_option_field_style(options, "month")?;
169
- let mut day = self.intl_option_field_style(options, "day")?;
170
- let hour = self.intl_option_field_style(options, "hour")?;
171
- let minute = self.intl_option_field_style(options, "minute")?;
172
- let second = self.intl_option_field_style(options, "second")?;
173
- if year.is_none()
174
- && month.is_none()
175
- && day.is_none()
176
- && hour.is_none()
177
- && minute.is_none()
178
- && second.is_none()
179
- {
180
- year = Some(IntlFieldStyle::Numeric);
181
- month = Some(IntlFieldStyle::Numeric);
182
- day = Some(IntlFieldStyle::Numeric);
183
- }
184
- Ok(Value::Object(self.insert_object(
185
- IndexMap::new(),
186
- ObjectKind::IntlDateTimeFormat(IntlDateTimeFormatObject {
187
- locale,
188
- time_zone,
189
- year,
190
- month,
191
- day,
192
- hour,
193
- minute,
194
- second,
195
- }),
196
- )?))
197
- }
198
-
199
- pub(crate) fn construct_intl_number_format(&mut self, args: &[Value]) -> MustardResult<Value> {
200
- let locale = self.normalize_intl_locale(args.first().cloned())?;
201
- let options = self.intl_options_object(args.get(1).cloned())?;
202
- self.intl_assert_supported_option_keys(
203
- options,
204
- "NumberFormat",
205
- &[
206
- "style",
207
- "currency",
208
- "minimumFractionDigits",
209
- "maximumFractionDigits",
210
- "useGrouping",
211
- ],
212
- )?;
213
- let style = match self.intl_option_string(options, "style")? {
214
- None => IntlNumberStyle::Decimal,
215
- Some(value) if value == "decimal" => IntlNumberStyle::Decimal,
216
- Some(value) if value == "percent" => IntlNumberStyle::Percent,
217
- Some(value) if value == "currency" => IntlNumberStyle::Currency,
218
- Some(_) => {
219
- return Err(MustardError::runtime(
220
- "TypeError: Intl.NumberFormat currently supports `decimal`, `percent`, or `currency` styles",
221
- ));
222
- }
223
- };
224
- let currency = self.intl_option_string(options, "currency")?;
225
- if style == IntlNumberStyle::Currency && currency.as_deref() != Some("USD") {
226
- return Err(MustardError::runtime(
227
- "TypeError: Intl.NumberFormat currency style currently supports only `USD`",
228
- ));
229
- }
230
- let minimum_fraction_digits = self
231
- .intl_option_digits(options, "minimumFractionDigits")?
232
- .unwrap_or(match style {
233
- IntlNumberStyle::Currency => 2,
234
- _ => 0,
235
- });
236
- let maximum_fraction_digits = self
237
- .intl_option_digits(options, "maximumFractionDigits")?
238
- .unwrap_or(match style {
239
- IntlNumberStyle::Currency => 2,
240
- IntlNumberStyle::Percent => 0,
241
- IntlNumberStyle::Decimal => 3,
242
- });
243
- if minimum_fraction_digits > maximum_fraction_digits {
244
- return Err(MustardError::runtime(
245
- "RangeError: Intl.NumberFormat minimumFractionDigits cannot exceed maximumFractionDigits",
246
- ));
247
- }
248
- let use_grouping = self
249
- .intl_option_bool(options, "useGrouping")?
250
- .unwrap_or(true);
251
- Ok(Value::Object(self.insert_object(
252
- IndexMap::new(),
253
- ObjectKind::IntlNumberFormat(IntlNumberFormatObject {
254
- locale,
255
- style,
256
- currency,
257
- minimum_fraction_digits,
258
- maximum_fraction_digits,
259
- use_grouping,
260
- }),
261
- )?))
262
- }
263
-
264
- fn intl_date_time_format_receiver(
265
- &self,
266
- value: Value,
267
- method: &str,
268
- ) -> MustardResult<&IntlDateTimeFormatObject> {
269
- match value {
270
- Value::Object(object) => match &self
271
- .objects
272
- .get(object)
273
- .ok_or_else(|| MustardError::runtime("object missing"))?
274
- .kind
275
- {
276
- ObjectKind::IntlDateTimeFormat(formatter) => Ok(formatter),
277
- _ => Err(MustardError::runtime(format!(
278
- "TypeError: Intl.DateTimeFormat.prototype.{method} called on incompatible receiver",
279
- ))),
280
- },
281
- _ => Err(MustardError::runtime(format!(
282
- "TypeError: Intl.DateTimeFormat.prototype.{method} called on incompatible receiver",
283
- ))),
284
- }
285
- }
286
-
287
- fn intl_number_format_receiver(
288
- &self,
289
- value: Value,
290
- method: &str,
291
- ) -> MustardResult<&IntlNumberFormatObject> {
292
- match value {
293
- Value::Object(object) => match &self
294
- .objects
295
- .get(object)
296
- .ok_or_else(|| MustardError::runtime("object missing"))?
297
- .kind
298
- {
299
- ObjectKind::IntlNumberFormat(formatter) => Ok(formatter),
300
- _ => Err(MustardError::runtime(format!(
301
- "TypeError: Intl.NumberFormat.prototype.{method} called on incompatible receiver",
302
- ))),
303
- },
304
- _ => Err(MustardError::runtime(format!(
305
- "TypeError: Intl.NumberFormat.prototype.{method} called on incompatible receiver",
306
- ))),
307
- }
308
- }
309
-
310
- fn format_intl_field(value: u8, style: IntlFieldStyle) -> String {
311
- match style {
312
- IntlFieldStyle::Numeric => value.to_string(),
313
- IntlFieldStyle::TwoDigit => format!("{value:02}"),
314
- }
315
- }
316
-
317
- pub(crate) fn call_intl_date_time_format_format(
318
- &self,
319
- this_value: Value,
320
- args: &[Value],
321
- ) -> MustardResult<Value> {
322
- let formatter = self.intl_date_time_format_receiver(this_value, "format")?;
323
- let timestamp_ms = match args.first().cloned().unwrap_or(Value::Undefined) {
324
- Value::Undefined => current_time_millis(),
325
- value => self.date_timestamp_ms_from_value(value)?,
326
- };
327
- let Some(datetime) = date_time_fields_from_timestamp_ms(timestamp_ms) else {
328
- return Err(MustardError::runtime("RangeError: Invalid time value"));
329
- };
330
- let mut date_parts = Vec::new();
331
- if let Some(month) = formatter.month {
332
- date_parts.push(Self::format_intl_field(datetime.month, month));
333
- }
334
- if let Some(day) = formatter.day {
335
- date_parts.push(Self::format_intl_field(datetime.day, day));
336
- }
337
- if let Some(year) = formatter.year {
338
- date_parts.push(match year {
339
- IntlFieldStyle::Numeric => datetime.year.to_string(),
340
- IntlFieldStyle::TwoDigit => format!("{:02}", datetime.year.rem_euclid(100)),
341
- });
342
- }
343
- let mut rendered = if date_parts.is_empty() {
344
- String::new()
345
- } else {
346
- date_parts.join("/")
347
- };
348
- let mut rendered_time = None;
349
- if let Some(hour_style) = formatter.hour {
350
- let hour_24 = datetime.hour;
351
- let meridiem = if hour_24 < 12 { "AM" } else { "PM" };
352
- let hour_12 = match hour_24 % 12 {
353
- 0 => 12,
354
- value => value,
355
- };
356
- let mut time_parts = vec![match hour_style {
357
- IntlFieldStyle::Numeric => hour_12.to_string(),
358
- IntlFieldStyle::TwoDigit => format!("{hour_12:02}"),
359
- }];
360
- if let Some(minute) = formatter.minute {
361
- time_parts.push(Self::format_intl_field(datetime.minute, minute));
362
- }
363
- if let Some(second) = formatter.second {
364
- time_parts.push(Self::format_intl_field(datetime.second, second));
365
- }
366
- rendered_time = Some(format!("{} {meridiem}", time_parts.join(":")));
367
- } else {
368
- let mut time_parts = Vec::new();
369
- if let Some(minute) = formatter.minute {
370
- time_parts.push(Self::format_intl_field(datetime.minute, minute));
371
- }
372
- if let Some(second) = formatter.second {
373
- time_parts.push(Self::format_intl_field(datetime.second, second));
374
- }
375
- if !time_parts.is_empty() {
376
- rendered_time = Some(time_parts.join(":"));
377
- }
378
- }
379
- if let Some(time) = rendered_time {
380
- if !rendered.is_empty() {
381
- rendered.push_str(", ");
382
- }
383
- rendered.push_str(&time);
384
- }
385
- Ok(Value::String(rendered))
386
- }
387
-
388
- pub(crate) fn call_intl_date_time_format_resolved_options(
389
- &mut self,
390
- this_value: Value,
391
- ) -> MustardResult<Value> {
392
- let formatter = self
393
- .intl_date_time_format_receiver(this_value, "resolvedOptions")?
394
- .clone();
395
- let mut properties = IndexMap::new();
396
- properties.insert("locale".to_string(), Value::String(formatter.locale));
397
- properties.insert("timeZone".to_string(), Value::String(formatter.time_zone));
398
- if let Some(year) = formatter.year {
399
- properties.insert(
400
- "year".to_string(),
401
- Value::String(match year {
402
- IntlFieldStyle::Numeric => "numeric".to_string(),
403
- IntlFieldStyle::TwoDigit => "2-digit".to_string(),
404
- }),
405
- );
406
- }
407
- if let Some(month) = formatter.month {
408
- properties.insert(
409
- "month".to_string(),
410
- Value::String(match month {
411
- IntlFieldStyle::Numeric => "numeric".to_string(),
412
- IntlFieldStyle::TwoDigit => "2-digit".to_string(),
413
- }),
414
- );
415
- }
416
- if let Some(day) = formatter.day {
417
- properties.insert(
418
- "day".to_string(),
419
- Value::String(match day {
420
- IntlFieldStyle::Numeric => "numeric".to_string(),
421
- IntlFieldStyle::TwoDigit => "2-digit".to_string(),
422
- }),
423
- );
424
- }
425
- if let Some(hour) = formatter.hour {
426
- properties.insert(
427
- "hour".to_string(),
428
- Value::String(match hour {
429
- IntlFieldStyle::Numeric => "numeric".to_string(),
430
- IntlFieldStyle::TwoDigit => "2-digit".to_string(),
431
- }),
432
- );
433
- }
434
- if let Some(minute) = formatter.minute {
435
- properties.insert(
436
- "minute".to_string(),
437
- Value::String(match minute {
438
- IntlFieldStyle::Numeric => "numeric".to_string(),
439
- IntlFieldStyle::TwoDigit => "2-digit".to_string(),
440
- }),
441
- );
442
- }
443
- if let Some(second) = formatter.second {
444
- properties.insert(
445
- "second".to_string(),
446
- Value::String(match second {
447
- IntlFieldStyle::Numeric => "numeric".to_string(),
448
- IntlFieldStyle::TwoDigit => "2-digit".to_string(),
449
- }),
450
- );
451
- }
452
- Ok(Value::Object(
453
- self.insert_object(properties, ObjectKind::Plain)?,
454
- ))
455
- }
456
-
457
- fn format_intl_number(&self, formatter: &IntlNumberFormatObject, number: f64) -> String {
458
- let value = match formatter.style {
459
- IntlNumberStyle::Percent => number * 100.0,
460
- _ => number,
461
- };
462
- if !value.is_finite() {
463
- return value.to_string();
464
- }
465
- let rounded = format!("{:.*}", formatter.maximum_fraction_digits, value.abs());
466
- let mut parts = rounded.split('.').collect::<Vec<_>>();
467
- let mut integer = parts.remove(0).to_string();
468
- let mut fraction = parts.first().copied().unwrap_or("").to_string();
469
- while fraction.len() > formatter.minimum_fraction_digits && fraction.ends_with('0') {
470
- fraction.pop();
471
- }
472
- if formatter.use_grouping {
473
- integer = format_en_us_number_grouped(&integer);
474
- }
475
- let rendered = if fraction.is_empty() {
476
- integer
477
- } else {
478
- format!("{integer}.{fraction}")
479
- };
480
- match formatter.style {
481
- IntlNumberStyle::Decimal => {
482
- if value.is_sign_negative() {
483
- format!("-{rendered}")
484
- } else {
485
- rendered
486
- }
487
- }
488
- IntlNumberStyle::Percent => {
489
- let mut rendered = if value.is_sign_negative() {
490
- format!("-{rendered}")
491
- } else {
492
- rendered
493
- };
494
- rendered.push('%');
495
- rendered
496
- }
497
- IntlNumberStyle::Currency => {
498
- if value.is_sign_negative() {
499
- format!("-${rendered}")
500
- } else {
501
- format!("${rendered}")
502
- }
503
- }
504
- }
505
- }
506
-
507
- pub(crate) fn call_intl_number_format_format(
508
- &self,
509
- this_value: Value,
510
- args: &[Value],
511
- ) -> MustardResult<Value> {
512
- let formatter = self.intl_number_format_receiver(this_value, "format")?;
513
- let number = self.to_number(args.first().cloned().unwrap_or(Value::Undefined))?;
514
- Ok(Value::String(self.format_intl_number(formatter, number)))
515
- }
516
-
517
- pub(crate) fn call_intl_number_format_resolved_options(
518
- &mut self,
519
- this_value: Value,
520
- ) -> MustardResult<Value> {
521
- let formatter = self
522
- .intl_number_format_receiver(this_value, "resolvedOptions")?
523
- .clone();
524
- let mut properties = IndexMap::new();
525
- properties.insert("locale".to_string(), Value::String(formatter.locale));
526
- properties.insert(
527
- "style".to_string(),
528
- Value::String(match formatter.style {
529
- IntlNumberStyle::Decimal => "decimal".to_string(),
530
- IntlNumberStyle::Percent => "percent".to_string(),
531
- IntlNumberStyle::Currency => "currency".to_string(),
532
- }),
533
- );
534
- if let Some(currency) = formatter.currency {
535
- properties.insert("currency".to_string(), Value::String(currency));
536
- }
537
- properties.insert(
538
- "minimumFractionDigits".to_string(),
539
- Value::Number(formatter.minimum_fraction_digits as f64),
540
- );
541
- properties.insert(
542
- "maximumFractionDigits".to_string(),
543
- Value::Number(formatter.maximum_fraction_digits as f64),
544
- );
545
- properties.insert(
546
- "useGrouping".to_string(),
547
- Value::Bool(formatter.use_grouping),
548
- );
549
- Ok(Value::Object(
550
- self.insert_object(properties, ObjectKind::Plain)?,
551
- ))
552
- }
553
- }
@@ -1,25 +0,0 @@
1
- use super::*;
2
-
3
- use indexmap::IndexMap;
4
-
5
- mod arrays;
6
- mod collections;
7
- mod install;
8
- mod intl;
9
- mod objects;
10
- mod primitives;
11
- mod promises;
12
- mod regexp;
13
- mod strings;
14
- mod support;
15
-
16
- use self::support::{
17
- DateTimeFields, RegExpFlagsState, StringSearchPattern, advance_char_index,
18
- byte_index_to_char_index, char_index_to_byte_index, clamp_index, collect_literal_matches,
19
- current_time_millis, date_time_fields_from_timestamp_ms, expand_regexp_replacement_template,
20
- find_string_pattern, format_en_us_number_grouped, format_iso_datetime,
21
- normalize_relative_bound, normalize_search_index, parse_date_timestamp_ms,
22
- replace_all_string_matches, replace_first_string_match, split_string_by_pattern, time_clip,
23
- };
24
- pub(crate) use promises::PromiseSetupPolicy;
25
- pub(crate) use support::RegExpMatchData;