barefoot_js 0.39.7 → 0.39.9

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f2dee751fa656f2231c7d6cee7f3ab165f508ad988a58c0930419dbc3de1132e
4
- data.tar.gz: 5ecd00ba7237eac6ef23a9172e53c9b7968077d6097080ba86c0759c8b9dfc64
3
+ metadata.gz: ca01f4cd2478ff3996932ab0ea7102c799e74c2602f63313ca3ea6ed1e3e7ef7
4
+ data.tar.gz: 546f0e92374f3947eae8965b2771a3ba6928526eddaa8b9f1e3ced6883deed1f
5
5
  SHA512:
6
- metadata.gz: 8c781e4df474f753e1c58fe3c1e2e25ca7cf1af53fdae23909e98cc5382d3156103abac6ca4d97ce78a180d64213c52aec0e2674cc56f5e7250ced001843ef6f
7
- data.tar.gz: 7e96d3a6a087381bce7afcb51f746f82bc6276b465cce68b57f8ac978dd32c960ada3b846fb0e11652a7c79c0511de41068fb5b831f229ba672fc0ae62f5a790
6
+ metadata.gz: de992621414ebaf15ae3237dc62c1190bab959f516ed0047026af8a64a1dc87db978d8d43c86e30278f3087c6e45953ff676c9ffb486d8499dc3eb010586cfa5
7
+ data.tar.gz: dc2aa7213b1e63646a13f0c9340377731ab62baf7731ffcbed0bb517a78ff79d866f08a3a7c985990f666f01532a79237be42c346791d7bff213fa1e83f3a5c6
@@ -286,6 +286,26 @@ module BarefootJS
286
286
  to_number(l).to_f / to_number(r).to_f
287
287
  end
288
288
 
289
+ # JS `%`: the truncated remainder, which takes the dividend's sign
290
+ # (`-7 % 2` -> -1) and keeps a fraction (`7.5 % 2` -> 1.5); Ruby's `%`
291
+ # floors instead (`-7 % 2` -> 1). A zero divisor, or a NaN / infinite
292
+ # dividend, gives NaN. Two Integer operands keep an Integer result, as
293
+ # Ruby's own `%` did, except for a zero remainder of a negative dividend:
294
+ # JS gives -0 there (`-4 % 2`), which only shows through later
295
+ # arithmetic (`1 / (-4 % 2)` is -Infinity), so it is the Float -0.0. An
296
+ # Array still takes it as index 0 and `number_to_string` spells it "0".
297
+ # Shared by callback-body evaluation (`binary`) and the template-emitted
298
+ # remainder (`Context#mod`, #3474).
299
+ def remainder(l, r)
300
+ ln = to_number(l)
301
+ rn = to_number(r)
302
+ return Float::NAN if rn.zero?
303
+ return ln.to_f.remainder(rn.to_f) unless ln.is_a?(Integer) && rn.is_a?(Integer)
304
+
305
+ m = ln.remainder(rn)
306
+ m.zero? && ln.negative? ? -0.0 : m
307
+ end
308
+
289
309
  def binary(op, l, r)
290
310
  case op
291
311
  when '+'
@@ -297,9 +317,7 @@ module BarefootJS
297
317
  when '-' then to_number(l) - to_number(r)
298
318
  when '*' then to_number(l) * to_number(r)
299
319
  when '/' then divide(l, r)
300
- when '%'
301
- rn = to_number(r).to_f
302
- rn.zero? ? Float::NAN : to_number(l).to_f.remainder(rn)
320
+ when '%' then remainder(l, r)
303
321
  when '<', '<=', '>', '>=' then relational(op, l, r)
304
322
  when '===' then strict_eq(l, r)
305
323
  when '!==' then !strict_eq(l, r)
data/lib/barefoot_js.rb CHANGED
@@ -530,6 +530,15 @@ module BarefootJS
530
530
  Evaluator.divide(left, right)
531
531
  end
532
532
 
533
+ # JS `%`: the truncated remainder, which takes the dividend's sign
534
+ # (`-7 % 2` -> -1). Ruby's `%` floors (`-7 % 2` -> 1), so
535
+ # template-emitted remainders go through the shared evaluator's JS
536
+ # remainder instead: a fraction is kept, and a zero divisor gives NaN
537
+ # rather than raising (#3474).
538
+ def mod(left, right)
539
+ Evaluator.remainder(left, right)
540
+ end
541
+
533
542
  # JS truthiness (falsy: false, nil, 0, NaN, ""). Delegates to the
534
543
  # shared evaluator so template-emitted conditionals
535
544
  # (`if bf.truthy?(x)`) and callback-body evaluation agree byte-for-byte.
@@ -1025,18 +1034,28 @@ module BarefootJS
1025
1034
  end
1026
1035
 
1027
1036
  # `Array.prototype.indexOf(x)` / `.lastIndexOf(x)` -- value-equality
1028
- # search. Non-array receivers return -1.
1037
+ # search. A String receiver is `String.prototype.indexOf`, counted in
1038
+ # UTF-16 code units like JS (#3613). Other receivers return -1.
1029
1039
  def index_of(recv, elem)
1040
+ return utf16_index_of(recv, elem, false) if recv.is_a?(String)
1041
+
1030
1042
  array_index_of(recv, elem, false)
1031
1043
  end
1032
1044
 
1033
1045
  def last_index_of(recv, elem)
1046
+ return utf16_index_of(recv, elem, true) if recv.is_a?(String)
1047
+
1034
1048
  array_index_of(recv, elem, true)
1035
1049
  end
1036
1050
 
1037
1051
  # `Array.prototype.at(i)` -- negative indices count from the end;
1038
1052
  # out-of-bounds -> nil (renders as '' via `h`, matching JS `undefined`).
1053
+ # A String receiver is indexed in UTF-16 code units (#3613). Half of a
1054
+ # surrogate pair, a lone surrogate in JS, comes back as U+FFFD: a
1055
+ # UTF-8 Ruby String can't hold one, so the halves compare equal and
1056
+ # don't rejoin (limitation `string-at-lone-surrogate`).
1039
1057
  def at(recv, i)
1058
+ return utf16_at(recv, i) if recv.is_a?(String)
1040
1059
  return nil unless recv.is_a?(Array)
1041
1060
  return nil if i.nil?
1042
1061
 
@@ -1228,9 +1247,10 @@ module BarefootJS
1228
1247
  def starts_with(recv, prefix, position = nil)
1229
1248
  s = recv.nil? ? '' : string(recv)
1230
1249
  p = prefix.nil? ? '' : string(prefix)
1250
+ # `position` counts UTF-16 code units, like JS (#3613).
1231
1251
  unless position.nil?
1232
- n = clamp_index(position.to_i, s.length)
1233
- s = s[n..] || ''
1252
+ units = utf16_units(s)
1253
+ return utf16_has_at?(units, utf16_units(p), clamp_index(to_integer_or_infinity(position), units.length))
1234
1254
  end
1235
1255
  s.start_with?(p)
1236
1256
  end
@@ -1239,9 +1259,11 @@ module BarefootJS
1239
1259
  def ends_with(recv, suffix, end_position = nil)
1240
1260
  s = recv.nil? ? '' : string(recv)
1241
1261
  x = suffix.nil? ? '' : string(suffix)
1262
+ # `endPosition` counts UTF-16 code units, like JS (#3613).
1242
1263
  unless end_position.nil?
1243
- e = clamp_index(end_position.to_i, s.length)
1244
- s = s[0...e]
1264
+ units = utf16_units(s)
1265
+ needle = utf16_units(x)
1266
+ return utf16_has_at?(units, needle, clamp_index(to_integer_or_infinity(end_position), units.length) - needle.length)
1245
1267
  end
1246
1268
  s.end_with?(x)
1247
1269
  end
@@ -1697,6 +1719,55 @@ module BarefootJS
1697
1719
  -1
1698
1720
  end
1699
1721
 
1722
+ # `s` as JS sees it: an Array of UTF-16 code units. JS string positions
1723
+ # (`indexOf`, `at`, `startsWith`'s position, ...) count these, so an
1724
+ # astral character such as '😀' is two units (#3613).
1725
+ def utf16_units(s)
1726
+ s.to_s.encode('UTF-16LE', invalid: :replace, undef: :replace).unpack('v*')
1727
+ end
1728
+
1729
+ MAX_SAFE_INDEX = 2**53
1730
+
1731
+ # JS `ToIntegerOrInfinity` for a string position or index (#3613): NaN
1732
+ # -> 0, truncation toward zero, and +/-Infinity clamped to +/-2**53 so
1733
+ # the caller's range check treats it as out of range instead of
1734
+ # `Float#to_i` raising FloatDomainError.
1735
+ def to_integer_or_infinity(value)
1736
+ n = number(value)
1737
+ return 0 if n.respond_to?(:nan?) && n.nan?
1738
+ return MAX_SAFE_INDEX if n >= MAX_SAFE_INDEX
1739
+ return -MAX_SAFE_INDEX if n <= -MAX_SAFE_INDEX
1740
+
1741
+ n.to_i
1742
+ end
1743
+
1744
+ def utf16_has_at?(hay, needle, at)
1745
+ return false if at.negative? || at + needle.length > hay.length
1746
+
1747
+ hay[at, needle.length] == needle
1748
+ end
1749
+
1750
+ def utf16_index_of(recv, elem, reverse)
1751
+ hay = utf16_units(recv)
1752
+ needle = utf16_units(string(elem))
1753
+ last = hay.length - needle.length
1754
+ indices = reverse ? last.downto(0) : 0.upto(last)
1755
+ indices.each { |i| return i if utf16_has_at?(hay, needle, i) }
1756
+ -1
1757
+ end
1758
+
1759
+ def utf16_at(recv, i)
1760
+ return nil if i.nil?
1761
+
1762
+ units = utf16_units(recv)
1763
+ idx = to_integer_or_infinity(i)
1764
+ idx += units.length if idx.negative?
1765
+ return nil if idx.negative? || idx >= units.length
1766
+
1767
+ u = units[idx]
1768
+ (0xD800..0xDFFF).cover?(u) ? "\uFFFD" : [u].pack('U')
1769
+ end
1770
+
1700
1771
  def clamp_index(n, len)
1701
1772
  n = 0 if n.negative?
1702
1773
  n = len if n > len
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: barefoot_js
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.39.7
4
+ version: 0.39.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - kobaken