barefoot_js 0.39.8 → 0.40.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/lib/barefoot_js.rb +67 -5
  3. metadata +1 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 727248cd6dcc7a533846854d5a8d4675ac946390d5750df49b03e25dad8cd3e5
4
- data.tar.gz: 508a38a3a2d56d99af75875be59b6989103ab3adf3fe6e42bae3e040cd69d608
3
+ metadata.gz: 5683e188c57d0ed7b6101db57828d8bfb0a6f8ffdbb6939052e5132fbd099fd9
4
+ data.tar.gz: 546f0e92374f3947eae8965b2771a3ba6928526eddaa8b9f1e3ced6883deed1f
5
5
  SHA512:
6
- metadata.gz: e91debd9fe87d53e154cd53a7be218efd5c3dec07e64f3b57cb3c4cd0d2406f1a5846f84bde2d9cb49f73a5236c6979649e89f50879f2511e31dda9191ed060b
7
- data.tar.gz: 5b617131eebba68e976d362993fba1f85e8cadd86fff1258ab029d44a4bdbdf64013aa3b8d739229deff1497c411af7205e016b05ff1bfbf877cf85b2ab27e22
6
+ metadata.gz: 99c0e7ceaf4e6e92c1a0b9c462a43983b91de28555e6032c11e0b904156088e7ba08177043f3a3658140a18de3d1cae365746c01193d87b5c83e5db6cbf21a1a
7
+ data.tar.gz: dc2aa7213b1e63646a13f0c9340377731ab62baf7731ffcbed0bb517a78ff79d866f08a3a7c985990f666f01532a79237be42c346791d7bff213fa1e83f3a5c6
data/lib/barefoot_js.rb CHANGED
@@ -1034,18 +1034,28 @@ module BarefootJS
1034
1034
  end
1035
1035
 
1036
1036
  # `Array.prototype.indexOf(x)` / `.lastIndexOf(x)` -- value-equality
1037
- # 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.
1038
1039
  def index_of(recv, elem)
1040
+ return utf16_index_of(recv, elem, false) if recv.is_a?(String)
1041
+
1039
1042
  array_index_of(recv, elem, false)
1040
1043
  end
1041
1044
 
1042
1045
  def last_index_of(recv, elem)
1046
+ return utf16_index_of(recv, elem, true) if recv.is_a?(String)
1047
+
1043
1048
  array_index_of(recv, elem, true)
1044
1049
  end
1045
1050
 
1046
1051
  # `Array.prototype.at(i)` -- negative indices count from the end;
1047
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`).
1048
1057
  def at(recv, i)
1058
+ return utf16_at(recv, i) if recv.is_a?(String)
1049
1059
  return nil unless recv.is_a?(Array)
1050
1060
  return nil if i.nil?
1051
1061
 
@@ -1237,9 +1247,10 @@ module BarefootJS
1237
1247
  def starts_with(recv, prefix, position = nil)
1238
1248
  s = recv.nil? ? '' : string(recv)
1239
1249
  p = prefix.nil? ? '' : string(prefix)
1250
+ # `position` counts UTF-16 code units, like JS (#3613).
1240
1251
  unless position.nil?
1241
- n = clamp_index(position.to_i, s.length)
1242
- 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))
1243
1254
  end
1244
1255
  s.start_with?(p)
1245
1256
  end
@@ -1248,9 +1259,11 @@ module BarefootJS
1248
1259
  def ends_with(recv, suffix, end_position = nil)
1249
1260
  s = recv.nil? ? '' : string(recv)
1250
1261
  x = suffix.nil? ? '' : string(suffix)
1262
+ # `endPosition` counts UTF-16 code units, like JS (#3613).
1251
1263
  unless end_position.nil?
1252
- e = clamp_index(end_position.to_i, s.length)
1253
- 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)
1254
1267
  end
1255
1268
  s.end_with?(x)
1256
1269
  end
@@ -1706,6 +1719,55 @@ module BarefootJS
1706
1719
  -1
1707
1720
  end
1708
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
+
1709
1771
  def clamp_index(n, len)
1710
1772
  n = 0 if n.negative?
1711
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.8
4
+ version: 0.40.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - kobaken