uri-whatwg_parser 0.2.1 → 0.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bc2c1e5428af4eaed582a417234dec63ac59554af14bbbbd1cc0c3017e8e32b9
4
- data.tar.gz: 749b4ba051cb58a73f0ef8ebe64d6426a4d1f0803176641ff75af539757130c1
3
+ metadata.gz: 7e3c073b711f9600fd66938070b1cc254a1067b684437f27038a69bc65076c9c
4
+ data.tar.gz: fe833972e0fe8265958d94a97b127983bca064cd29f554c78fb1c2459be008f9
5
5
  SHA512:
6
- metadata.gz: a28ffa266d8013c02ed0da9bfd285eaff113527772019a135ddd092310b942c01b6beab710336d37665f8ec3dcc18829edad14a0a97168ef1fc3c651148eb4f0
7
- data.tar.gz: 1ba90031895fe24a39b1ae7ff127ea7af821cb39a0801b83234c40b63801c9ee6c886f1bb0e423bc9c6e9c817d31bea29661db7e22978c8b66891b9864a953f4
6
+ metadata.gz: 541f8b1b1d02b2ac2f16b4af59e5fe3b02e01b2f291529b2698590d01dfc6e1da528926920af1dad8c2d21a11437030356859b30d6e972d2fd3e54aad04cd89a
7
+ data.tar.gz: 639c0241664afd68d4f0f4c2cea36e71f484cb53215fc12bb89e65749626e1769e9a777420201468e7863a624afe62a0bb8839776a9e565252a35211c845dbf4
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ ## 0.3.0
2
+
3
+ * Fix several incorrect parsing processes
4
+ * Fix serialize URL
5
+
1
6
  ## 0.2.1
2
7
 
3
8
  * Improve the performance of `parse`
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Ruby implementation of the [WHATWG URL Living Standard](https://url.spec.whatwg.org/).
4
4
 
5
- The latest revision that this package implements of the standard is [13 January 2026](https://url.spec.whatwg.org/commit-snapshots/b6b3251fe911ab33d68fb051efe0e4d39ae4145e/).
5
+ The latest revision that this package implements of the standard is [14 April 2026](https://url.spec.whatwg.org/commit-snapshots/b11d73b8caefe90403afe19210db05acba897722/)
6
6
 
7
7
  ## Installation
8
8
 
@@ -3,16 +3,11 @@ require "uri/generic"
3
3
  module URI
4
4
  class WhatwgParser
5
5
  module Generic
6
- def initialize(scheme,
7
- userinfo, host, port, registry,
8
- path, opaque,
9
- query,
10
- fragment,
11
- parser = DEFAULT_PARSER,
12
- arg_check = false)
13
-
14
- return super unless URI::DEFAULT_PARSER.is_a?(URI::WhatwgParser)
15
- return super if registry
6
+ def initialize(scheme, userinfo, host, port, registry, path, opaque, query, fragment, parser = DEFAULT_PARSER, arg_check = false)
7
+ @parsed_by_whatwg_parser = parser.is_a?(URI::WhatwgParser)
8
+ unless parser.is_a?(URI::WhatwgParser)
9
+ return super(scheme, userinfo, host, port, registry, path, opaque, query, fragment)
10
+ end
16
11
 
17
12
  @scheme = nil
18
13
  @user = nil
@@ -20,6 +15,7 @@ module URI
20
15
  @host = nil
21
16
  @port = nil
22
17
  @path = nil
18
+ @raw_path = nil
23
19
  @query = nil
24
20
  @opaque = nil
25
21
  @fragment = nil
@@ -32,64 +28,67 @@ module URI
32
28
  self.set_path(path)
33
29
  self.query = query
34
30
  self.set_opaque(opaque)
35
- self.fragment=(fragment)
31
+ @fragment = fragment
32
+ @raw_path = parser&.path
36
33
 
37
34
  self.set_path("") if !@path && !@opaque
38
- DEFAULT_PARSER.parse(to_s) if arg_check
35
+ parser.parse(to_s) if arg_check
39
36
 
40
37
  @scheme&.freeze
41
38
  self.set_port(self.default_port) if self.default_port && !@port
42
39
  end
43
40
 
44
41
  def merge(oth)
45
- URI::DEFAULT_PARSER.join(self.to_s, oth.to_s)
42
+ return super unless @parsed_by_whatwg_parser
43
+
44
+ parser.join(self.to_s, oth.to_s)
46
45
  end
47
46
  alias + merge
48
47
 
49
48
  def scheme=(v)
50
- return super unless URI::DEFAULT_PARSER.is_a?(URI::WhatwgParser)
49
+ return super unless @parsed_by_whatwg_parser
51
50
  return if v.nil? || v.empty?
52
51
 
53
- parse_result = URI::DEFAULT_PARSER.split("#{v}:", url: self, state_override: :scheme_start_state)
52
+ parse_result = parser.split("#{v}:", url: self, state_override: :scheme_start_state)
54
53
  set_scheme(parse_result[0])
55
54
  set_port(parse_result[3])
56
55
  end
57
56
 
58
57
  def user=(v)
59
- return super unless URI::DEFAULT_PARSER.is_a?(URI::WhatwgParser)
58
+ return super unless @parsed_by_whatwg_parser
60
59
  return v unless v
61
60
 
62
61
  if host.nil? || host.empty? || scheme == "file"
63
62
  raise InvalidURIError, "cannot set user when host is nil or file schme"
64
63
  end
65
- set_user(URI::DEFAULT_PARSER.utf8_percent_encode_string(v, URI::WhatwgParser::USERINFO_PERCENT_ENCODE_SET))
64
+ set_user(parser.utf8_percent_encode_string(v, URI::WhatwgParser::USERINFO_PERCENT_ENCODE_SET))
66
65
  end
67
66
 
68
67
  def password=(v)
69
- return super unless URI::DEFAULT_PARSER.is_a?(URI::WhatwgParser)
68
+ return super unless @parsed_by_whatwg_parser
70
69
  return v unless v
71
70
 
72
71
  if host.nil? || host.empty? || scheme == "file"
73
72
  raise InvalidURIError, "cannot set password when host is nil or file schme"
74
73
  end
75
- set_password(URI::DEFAULT_PARSER.utf8_percent_encode_string(v, URI::WhatwgParser::USERINFO_PERCENT_ENCODE_SET))
74
+ set_password(parser.utf8_percent_encode_string(v, URI::WhatwgParser::USERINFO_PERCENT_ENCODE_SET))
76
75
  end
77
76
 
78
77
  def host=(v)
79
- return super unless URI::DEFAULT_PARSER.is_a?(URI::WhatwgParser)
78
+ return super unless @parsed_by_whatwg_parser
80
79
  return if v.nil?
81
80
 
82
81
  if @opaque
83
- raise InvalidURIError, "cannot set host with registry or opaque"
82
+ raise InvalidURIError, "cannot set host with opaque"
84
83
  end
85
84
 
86
- parse_result = URI::DEFAULT_PARSER.split(v.to_s, url: self, state_override: :host_state)
85
+ parse_result = parser.split(v.to_s, url: self, state_override: :host_state)
87
86
  set_host(parse_result[2])
88
87
  set_port(parse_result[3])
89
88
  end
90
89
 
91
90
  def port=(v)
92
- return super unless URI::DEFAULT_PARSER.is_a?(URI::WhatwgParser)
91
+ return super unless @parsed_by_whatwg_parser
93
92
  return if v.nil?
94
93
 
95
94
  if v.to_s.empty?
@@ -101,24 +100,55 @@ module URI
101
100
  raise InvalidURIError, "cannot set port when host is nil or scheme is file"
102
101
  end
103
102
 
104
- parse_result = URI::DEFAULT_PARSER.split("#{v}:", url: self, state_override: :port_state)
103
+ parse_result = parser.split("#{v}:", url: self, state_override: :port_state)
105
104
  set_port(parse_result[3])
106
105
  end
107
106
 
108
107
  def path=(v)
109
- return super unless URI::DEFAULT_PARSER.is_a?(URI::WhatwgParser)
108
+ return super unless @parsed_by_whatwg_parser
110
109
  return if v.nil?
111
110
 
112
111
  if @opaque
113
112
  raise InvalidURIError, "path conflicts with opaque"
114
113
  end
115
114
 
116
- parse_result = URI::DEFAULT_PARSER.split(v.to_s, url: self, state_override: :path_start_state)
115
+ parse_result = parser.split(v.to_s, url: self, state_override: :path_start_state)
116
+ @raw_path = parser.path
117
117
  set_path(parse_result[5])
118
118
  end
119
119
 
120
+ def query=(v)
121
+ return super unless @parsed_by_whatwg_parser
122
+
123
+ if v.nil? || v.empty?
124
+ @query = nil
125
+ return
126
+ end
127
+
128
+ v = v.start_with?("?") ? v[1..-1] : v
129
+ @query = +""
130
+
131
+ parse_result = parser.split(v, url: self, state_override: :query_state)
132
+ @query = parse_result[7].to_s
133
+ end
134
+
135
+ def fragment=(v)
136
+ return super unless @parsed_by_whatwg_parser
137
+
138
+ if v.nil? || v.empty?
139
+ @fragment = nil
140
+ return
141
+ end
142
+
143
+ v = v.start_with?("#") ? v[1..-1] : v
144
+ @fragment = +""
145
+
146
+ parse_result = parser.split(v, url: self, state_override: :fragment_state)
147
+ @fragment = parse_result[8].to_s
148
+ end
149
+
120
150
  def userinfo=(userinfo)
121
- return super unless URI::DEFAULT_PARSER.is_a?(URI::WhatwgParser)
151
+ return super unless @parsed_by_whatwg_parser
122
152
 
123
153
  user, password = split_userinfo(userinfo)
124
154
  self.user = user
@@ -126,17 +156,59 @@ module URI
126
156
  end
127
157
 
128
158
  def check_opaque(v)
129
- return super unless URI::DEFAULT_PARSER.is_a?(URI::WhatwgParser)
159
+ return super unless @parsed_by_whatwg_parser
160
+
130
161
  return v unless v
131
162
 
132
- if @host || @port || @user || @path
133
- raise InvalidURIError, "cannot set opaque with host, port, userinfo or path"
163
+ if @host || @port || @user
164
+ raise InvalidURIError, "cannot set opaque with host, port, or userinfo"
134
165
  end
135
166
 
136
167
  self.set_opaque(v)
137
- DEFAULT_PARSER.parse(to_s)
168
+ # NOTE: WHATWG URL Living Standard doesn't define "opaque" setter. So parse a URL whole.
169
+ parser.parse(to_s)
138
170
  true
139
171
  end
172
+
173
+ def to_s
174
+ return super unless @parsed_by_whatwg_parser
175
+
176
+ str = "".dup
177
+ if @scheme
178
+ str << @scheme
179
+ str << ":"
180
+ end
181
+
182
+ if @host || %w[file postgres].include?(@scheme)
183
+ str << "//"
184
+ end
185
+ if self.userinfo
186
+ str << self.userinfo
187
+ str << "@"
188
+ end
189
+ if @host
190
+ str << @host
191
+ end
192
+ if @port && @port != self.default_port
193
+ str << ":"
194
+ str << @port.to_s
195
+ end
196
+ if @host.nil? && @opaque.nil? && @raw_path && @raw_path.length > 1 && @raw_path[0] == ""
197
+ str << "/."
198
+ end
199
+ str << @path if @path
200
+ str << @opaque if @opaque
201
+ if @query
202
+ str << "?"
203
+ str << @query
204
+ end
205
+
206
+ if @fragment
207
+ str << "#"
208
+ str << @fragment
209
+ end
210
+ str
211
+ end
140
212
  end
141
213
  end
142
214
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module URI
4
4
  class WhatwgParser
5
- VERSION = "0.2.1"
5
+ VERSION = "0.3.0"
6
6
  end
7
7
  end
@@ -36,6 +36,8 @@ module URI
36
36
  ASCII_ALPHA_UPPERCASE = Set.new(("A".."Z").to_a)
37
37
  ASCII_DIGIT = Set.new(("0".."9").to_a)
38
38
 
39
+ attr_reader :path
40
+
39
41
  def initialize
40
42
  reset
41
43
  @host_parser = HostParser.new
@@ -46,7 +48,7 @@ module URI
46
48
  end
47
49
 
48
50
  def parse(input, base: nil, url: nil, state_override: nil) # :nodoc:
49
- URI.for(*self.split(input, base: base, url: url, state_override: state_override))
51
+ URI.for(*self.split(input, base: base, url: url, state_override: state_override), self)
50
52
  end
51
53
 
52
54
  def split(input, base: nil, url: nil, state_override: nil) # :nodoc:
@@ -54,8 +56,8 @@ module URI
54
56
  @base = nil
55
57
  if base != nil
56
58
  ary = split(base, base: nil)
57
- @base = { scheme: ary[0], userinfo: ary[1], host: ary[2], port: ary[3], registry: ary[4], path: ary[5], opaque: ary[6], query: ary[7], fragment: ary[8]}
58
- @base_paths = @paths
59
+ @base = { scheme: ary[0], userinfo: ary[1], host: ary[2], port: ary[3], query: ary[7], fragment: ary[8]}
60
+ @base_path = @path
59
61
  reset
60
62
  end
61
63
 
@@ -95,8 +97,14 @@ module URI
95
97
  end
96
98
 
97
99
  userinfo = [@username, @password].compact.reject(&:empty?).join(":")
98
- path = "/#{@paths.join("/")}" if @paths && !@paths.empty?
99
- [@parse_result[:scheme], userinfo, @parse_result[:host], @parse_result[:port], @parse_result[:registry], path, @parse_result[:opaque], @parse_result[:query], @parse_result[:fragment]]
100
+ if @path
101
+ if @path.is_a?(Array)
102
+ path = "/#{@path.join("/")}"
103
+ else
104
+ opaque = @path
105
+ end
106
+ end
107
+ [@parse_result[:scheme], userinfo, @parse_result[:host], @parse_result[:port], nil, path, opaque, @parse_result[:query], @parse_result[:fragment]]
100
108
  end
101
109
 
102
110
  def join(*uris)
@@ -143,10 +151,10 @@ module URI
143
151
  @at_sign_seen = nil
144
152
  @password_token_seen = nil
145
153
  @inside_brackets = nil
146
- @paths = nil
154
+ @path = nil
147
155
  @username = nil
148
156
  @password = nil
149
- @parse_result = { scheme: nil, host: nil, port: nil, registry: nil, path: nil, opaque: nil, query: nil, fragment: nil }
157
+ @parse_result = {}
150
158
  @state_override = nil
151
159
  @state = :scheme_start_state
152
160
  @special_url = nil
@@ -207,7 +215,7 @@ module URI
207
215
  @state = :path_or_authority_state
208
216
  @pos += 1
209
217
  else
210
- @parse_result[:opaque] = +""
218
+ @path = +""
211
219
  @state = :opaque_path_state
212
220
  end
213
221
  elsif @state_override.nil?
@@ -220,12 +228,12 @@ module URI
220
228
  end
221
229
 
222
230
  def no_scheme_state(c)
223
- raise ParseError, "scheme is missing" if @base.nil? || (!@base[:opaque].nil? && c != "#")
231
+ raise ParseError, "scheme is missing" if @base.nil? || (has_opaque_path?(@base_path) && c != "#")
224
232
 
225
- if !@base[:opaque].nil? && c == "#"
233
+ if has_opaque_path?(@base_path) && c == "#"
226
234
  @parse_result[:scheme] = @base[:scheme]
227
235
  @special_url = special_url?(@base[:scheme])
228
- @paths = @base_paths
236
+ @path = @base_path
229
237
  @parse_result[:query] = @base[:query]
230
238
  @parse_result[:fragment] = nil
231
239
  @state = :fragment_state
@@ -268,7 +276,7 @@ module URI
268
276
  @username, @password = @base[:userinfo].split(":") if @base[:userinfo]
269
277
  @parse_result[:host] = @base[:host]
270
278
  @parse_result[:port] = @base[:port]
271
- @paths = @base_paths
279
+ @path = @base_path
272
280
  @parse_result[:query] = @base[:query]
273
281
 
274
282
  if c == "?"
@@ -430,7 +438,7 @@ module URI
430
438
  if !starts_with_windows_drive_letter?(rest)
431
439
  shorten_url_path
432
440
  else
433
- @paths = nil
441
+ @path = nil
434
442
  end
435
443
  @state = :path_state
436
444
  @pos -= 1
@@ -447,10 +455,10 @@ module URI
447
455
  else
448
456
  if !@base.nil? && @base[:scheme] == "file"
449
457
  @parse_result[:host] = @base[:host]
450
- if !starts_with_windows_drive_letter?(rest) && @base_paths && normalized_windows_drive_letter?(@base_paths[0])
451
- if @paths.nil?
452
- @paths ||= []
453
- @paths[0] = @base_paths[0]
458
+ if !starts_with_windows_drive_letter?(rest) && @base_path && normalized_windows_drive_letter?(@base_path[0])
459
+ if @path.nil?
460
+ @path ||= []
461
+ @path[0] = @base_path[0]
454
462
  end
455
463
  end
456
464
  end
@@ -500,29 +508,29 @@ module URI
500
508
  @pos -= 1 if c != "/"
501
509
  @state = :path_state
502
510
  elsif @state_override && @parse_result[:host].nil?
503
- @paths ||= []
504
- @paths << ""
511
+ @path ||= []
512
+ @path << ""
505
513
  end
506
514
  end
507
515
 
508
516
  def path_state(c)
509
- @paths ||= []
517
+ @path ||= []
510
518
 
511
519
  if (c.nil? || c == "/") || (@special_url && c == "\\") || (!@state_override && (c == "?" || c == "#"))
512
520
  if double_dot_path_segments?(@buffer)
513
521
  shorten_url_path
514
522
 
515
523
  if c != "/" && !(@special_url && c == "\\")
516
- @paths << ""
524
+ @path << ""
517
525
  end
518
526
  elsif single_dot_path_segments?(@buffer) && c != "/" && !((@special_url && c == "\\"))
519
- @paths << ""
527
+ @path << ""
520
528
  elsif !single_dot_path_segments?(@buffer)
521
- if @parse_result[:scheme] == "file" && @paths.empty? && windows_drive_letter?(@buffer)
529
+ if @parse_result[:scheme] == "file" && @path.empty? && windows_drive_letter?(@buffer)
522
530
  @buffer[1] = ":"
523
531
  end
524
532
 
525
- @paths << @buffer
533
+ @path << @buffer
526
534
  end
527
535
 
528
536
  @buffer = +""
@@ -531,7 +539,7 @@ module URI
531
539
  @parse_result[:query] = nil
532
540
  @state = :query_state
533
541
  elsif c == "#"
534
- @parse_result[:frament] = nil
542
+ @parse_result[:fragment] = nil
535
543
  @state = :fragment_state
536
544
  end
537
545
  else
@@ -549,12 +557,12 @@ module URI
549
557
  elsif c == " "
550
558
  first_of_rest = @input_chars[@pos + 1]
551
559
  if first_of_rest == "?" || first_of_rest == "#"
552
- @parse_result[:opaque] << "%20"
560
+ @path += "%20"
553
561
  else
554
- @parse_result[:opaque] << " "
562
+ @path += " "
555
563
  end
556
564
  elsif !c.nil?
557
- @parse_result[:opaque] << utf8_percent_encode(c, C0_CONTROL_PERCENT_ENCODE_SET)
565
+ @path += utf8_percent_encode(c, C0_CONTROL_PERCENT_ENCODE_SET)
558
566
  end
559
567
  end
560
568
 
@@ -564,7 +572,10 @@ module URI
564
572
  # TODO: We need to consider encoding here.
565
573
  @parse_result[:query] = utf8_percent_encode_string(@buffer, query_percent_encode_set)
566
574
  @buffer.clear
567
- @state = :fragment_state if c == "#"
575
+ if c == "#"
576
+ @parse_result[:fragment] = +""
577
+ @state = :fragment_state
578
+ end
568
579
  elsif !c.nil?
569
580
  @buffer << c
570
581
  end
@@ -600,9 +611,9 @@ module URI
600
611
  end
601
612
 
602
613
  def shorten_url_path
603
- return if @paths.nil?
604
- return if @parse_result[:scheme] == "file" && @paths.length == 1 && normalized_windows_drive_letter?(@paths.first)
605
- @paths.pop
614
+ return if @path.nil? || @path.is_a?(String)
615
+ return if @parse_result[:scheme] == "file" && @path.length == 1 && normalized_windows_drive_letter?(@path.first)
616
+ @path.pop
606
617
  end
607
618
 
608
619
  def includes_credentials?
@@ -638,6 +649,10 @@ module URI
638
649
  end
639
650
  end
640
651
  end
652
+
653
+ def has_opaque_path?(path)
654
+ path.is_a?(String)
655
+ end
641
656
  end
642
657
 
643
658
  WHATWG_PARSER = URI::WhatwgParser.new
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: uri-whatwg_parser
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yuji Yaginuma
@@ -66,14 +66,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
66
66
  requirements:
67
67
  - - ">="
68
68
  - !ruby/object:Gem::Version
69
- version: 3.2.0
69
+ version: 3.0.0
70
70
  required_rubygems_version: !ruby/object:Gem::Requirement
71
71
  requirements:
72
72
  - - ">="
73
73
  - !ruby/object:Gem::Version
74
74
  version: '0'
75
75
  requirements: []
76
- rubygems_version: 4.0.3
76
+ rubygems_version: 4.0.10
77
77
  specification_version: 4
78
78
  summary: Ruby implementation of the WHATWG URL Living Standard
79
79
  test_files: []