Module: DiffMatchPatchES::JsString

Defined in:
lib/diff_match_patch_es/js_string.rb,
sig/diff_match_patch_es/js_string.rbs

Overview

Helpers that reproduce JavaScript string semantics exactly.

Defined Under Namespace

Classes: UriError

Constant Summary collapse

JS_PARSE_INT =

JS Number.parseInt(str, 10): optional leading whitespace and sign, JS StrWhiteSpace: ASCII whitespace, NBSP, BOM, and Unicode space separators.

Returns:

  • (Regexp)
/\A[\t\n\v\f\r \u00A0\u1680\u2000-\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF]*([+-]?\d+)/
ENCODE_URI_UNESCAPED =

Characters encodeURI leaves unescaped.

Returns:

  • (Regexp)
/\A[A-Za-z0-9;,\/?:@&=+$\-_.!~*'()#]\z/
DECODE_URI_RESERVED =

Characters whose escape sequences decodeURI refuses to decode (uriReserved plus '#').

Returns:

  • (String)
";/?:@&=+$,#"

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.char_at(str, index) ⇒ Object

JS String.prototype.charAt: '' when out of range.



18
19
20
21
22
# File 'lib/diff_match_patch_es/js_string.rb', line 18

def char_at(str, index)
  return '' if index.negative? || index >= str.length

  str[index]
end

.decode_uri(str) ⇒ Object

JS decodeURI: decodes %XX escape sequences as strict UTF-8 (rejecting malformed, overlong, surrogate, and out-of-range sequences) while leaving escapes of reserved characters (";/?:@&=+$,#") untouched.



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
# File 'lib/diff_match_patch_es/js_string.rb', line 71

def decode_uri(str)
  out = +''
  i = 0
  n = str.length
  while i < n
    ch = str[i]
    unless ch == '%'
      out << ch
      i += 1
      next
    end
    start = i
    b0 = read_escaped_byte(str, i)
    i += 3
    if b0 < 0x80
      decoded = b0.chr
      if DECODE_URI_RESERVED.include?(decoded)
        out << str[start, 3]
      else
        out << decoded
      end
    else
      extra =
        case b0
        when 0xC2..0xDF then 1
        when 0xE0..0xEF then 2
        when 0xF0..0xF4 then 3
        else raise UriError, 'URI malformed'
        end
      codepoint = b0 & (0x3F >> extra)
      extra.times do
        raise UriError, 'URI malformed' unless str[i] == '%'

        byte = read_escaped_byte(str, i)
        raise UriError, 'URI malformed' unless (byte & 0xC0) == 0x80

        codepoint = (codepoint << 6) | (byte & 0x3F)
        i += 3
      end
      minimum = [0x80, 0x800, 0x10000][extra - 1]
      if codepoint < minimum || codepoint > 0x10FFFF || (0xD800..0xDFFF).cover?(codepoint)
        raise UriError, 'URI malformed'
      end

      out << codepoint.chr(Encoding::UTF_8)
    end
  end
  out
end

.encode_uri(str) ⇒ Object

JS encodeURI: percent-encodes the UTF-8 bytes of every character outside the unescaped set, using uppercase hex.



54
55
56
57
58
59
60
61
62
63
64
# File 'lib/diff_match_patch_es/js_string.rb', line 54

def encode_uri(str)
  out = +''
  str.each_char do |ch|
    if ENCODE_URI_UNESCAPED.match?(ch)
      out << ch
    else
      ch.each_byte { |b| out << format('%%%02X', b) }
    end
  end
  out
end

.index_of(str, pattern, from = 0) ⇒ Object

JS String.prototype.indexOf.



25
26
27
28
# File 'lib/diff_match_patch_es/js_string.rb', line 25

def index_of(str, pattern, from = 0)
  from = from.clamp(0, str.length)
  str.index(pattern, from) || -1
end

.last_index_of(str, pattern, from) ⇒ Object

JS String.prototype.lastIndexOf: the match may start at or before from.



31
32
33
34
# File 'lib/diff_match_patch_es/js_string.rb', line 31

def last_index_of(str, pattern, from)
  from = from.clamp(0, str.length)
  str.rindex(pattern, from) || -1
end

.parse_int(str) ⇒ Object

then as many digits as possible. Returns nil where JS returns NaN.



41
42
43
44
# File 'lib/diff_match_patch_es/js_string.rb', line 41

def parse_int(str)
  match = JS_PARSE_INT.match(str)
  match && match[1].to_i
end

.read_escaped_byte(str, index) ⇒ Object

Raises:



121
122
123
124
125
126
# File 'lib/diff_match_patch_es/js_string.rb', line 121

def read_escaped_byte(str, index)
  hex = str[index + 1, 2]
  raise UriError, 'URI malformed' unless hex&.length == 2 && /\A\h\h\z/.match?(hex)

  hex.to_i(16)
end

.substring(str, start_index, end_index = nil) ⇒ Object

JS String.prototype.substring: negative/overflowing indices clamp to [0, length] and the arguments swap when start > end.



9
10
11
12
13
14
15
# File 'lib/diff_match_patch_es/js_string.rb', line 9

def substring(str, start_index, end_index = nil)
  len = str.length
  a = start_index.clamp(0, len)
  b = end_index.nil? ? len : end_index.clamp(0, len)
  a, b = b, a if a > b
  str[a...b]
end

Instance Method Details

#self?.char_atString

JS String.prototype.charAt: '' when out of range.

Parameters:

  • str (String)
  • index (Integer)

Returns:

  • (String)


18
# File 'sig/diff_match_patch_es/js_string.rbs', line 18

def self?.char_at: (String str, Integer index) -> String

#self?.decode_uriString

JS decodeURI. Raises UriError where JS throws URIError.

Parameters:

  • str (String)

Returns:

  • (String)


33
# File 'sig/diff_match_patch_es/js_string.rbs', line 33

def self?.decode_uri: (String str) -> String

#self?.encode_uriString

JS encodeURI.

Parameters:

  • str (String)

Returns:

  • (String)


30
# File 'sig/diff_match_patch_es/js_string.rbs', line 30

def self?.encode_uri: (String str) -> String

#self?.index_ofInteger

JS String.prototype.indexOf.

Parameters:

  • str (String)
  • pattern (String)
  • from (Integer)

Returns:

  • (Integer)


21
# File 'sig/diff_match_patch_es/js_string.rbs', line 21

def self?.index_of: (String str, String pattern, ?Integer from) -> Integer

#self?.last_index_ofInteger

JS String.prototype.lastIndexOf: the match may start at or before from.

Parameters:

  • str (String)
  • pattern (String)
  • from (Integer)

Returns:

  • (Integer)


24
# File 'sig/diff_match_patch_es/js_string.rbs', line 24

def self?.last_index_of: (String str, String pattern, Integer from) -> Integer

#self?.parse_intInteger?

JS Number.parseInt(str, 10). Returns nil where JS returns NaN.

Parameters:

  • str (String)

Returns:

  • (Integer, nil)


27
# File 'sig/diff_match_patch_es/js_string.rbs', line 27

def self?.parse_int: (String str) -> Integer?

#self?.read_escaped_byteInteger

Parameters:

  • str (String)
  • index (Integer)

Returns:

  • (Integer)


35
# File 'sig/diff_match_patch_es/js_string.rbs', line 35

def self?.read_escaped_byte: (String str, Integer index) -> Integer

#self?.substringString

JS String.prototype.substring: negative/overflowing indices clamp to [0, length] and the arguments swap when start > end.

Parameters:

  • str (String)
  • start_index (Integer)
  • end_index (Integer, nil)

Returns:

  • (String)


15
# File 'sig/diff_match_patch_es/js_string.rbs', line 15

def self?.substring: (String str, Integer start_index, ?Integer? end_index) -> String