mdurl-rb-1.0.5/0000755000175100017510000000000014123311515013417 5ustar vivekdebvivekdebmdurl-rb-1.0.5/mdurl-rb.gemspec0000644000175100017510000000361214123311515016512 0ustar vivekdebvivekdeb######################################################### # This file has been automatically generated by gem2tgz # ######################################################### # -*- encoding: utf-8 -*- # stub: mdurl-rb 1.0.5 ruby lib Gem::Specification.new do |s| s.name = "mdurl-rb".freeze s.version = "1.0.5" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["Brett Walker".freeze, "Vitaly Puzrin".freeze, "Alex Kocharin".freeze] s.date = "2018-04-01" s.description = "Ruby version of MDUrl for motion-markdown-it for use with Ruby and RubyMotion".freeze s.email = "github@digitalmoksha.com".freeze s.files = ["README.md".freeze, "lib/mdurl-rb.rb".freeze, "lib/mdurl-rb/cgi.rb".freeze, "lib/mdurl-rb/decode.rb".freeze, "lib/mdurl-rb/encode.rb".freeze, "lib/mdurl-rb/format.rb".freeze, "lib/mdurl-rb/parse.rb".freeze, "lib/mdurl-rb/version.rb".freeze, "spec/mdurl-rb/decode_spec.rb".freeze, "spec/mdurl-rb/encode_spec.rb".freeze, "spec/mdurl-rb/fixtures/url_spec.rb".freeze, "spec/mdurl-rb/format_spec.rb".freeze, "spec/mdurl-rb/parse_spec.rb".freeze, "spec/spec_helper.rb".freeze] s.homepage = "https://github.com/digitalmoksha/mdurl-rb".freeze s.licenses = ["MIT".freeze] s.rubygems_version = "3.2.5".freeze s.summary = "MDUrl for motion-markdown-it in Ruby".freeze s.test_files = ["spec/mdurl-rb/decode_spec.rb".freeze, "spec/mdurl-rb/encode_spec.rb".freeze, "spec/mdurl-rb/fixtures/url_spec.rb".freeze, "spec/mdurl-rb/format_spec.rb".freeze, "spec/mdurl-rb/parse_spec.rb".freeze, "spec/spec_helper.rb".freeze] if s.respond_to? :specification_version then s.specification_version = 4 end if s.respond_to? :add_runtime_dependency then s.add_development_dependency(%q.freeze, ["~> 1.0"]) else s.add_dependency(%q.freeze, ["~> 1.0"]) end end mdurl-rb-1.0.5/spec/0000755000175100017510000000000014123311515014351 5ustar vivekdebvivekdebmdurl-rb-1.0.5/spec/spec_helper.rb0000644000175100017510000000007514123311515017171 0ustar vivekdebvivekdeb# rspec needs this file require 'byebug' require 'mdurl-rb' mdurl-rb-1.0.5/spec/mdurl-rb/0000755000175100017510000000000014123311515016075 5ustar vivekdebvivekdebmdurl-rb-1.0.5/spec/mdurl-rb/parse_spec.rb0000755000175100017510000000070014123311515020546 0ustar vivekdebvivekdebdescribe 'parse' do URL_TEST_DATA.each_pair do |url, result| it "#{url}" do parsed = MDUrl::Url.urlParse(url) (expect(parsed.protocol).to eq result['protocol']) if parsed.protocol (expect(parsed.slashes).to eq result['slashes']) if parsed.slashes (expect(parsed.hostname).to eq result['hostname']) if parsed.hostname (expect(parsed.pathname).to eq result['pathname']) if parsed.pathname end end endmdurl-rb-1.0.5/spec/mdurl-rb/format_spec.rb0000755000175100017510000000030314123311515020723 0ustar vivekdebvivekdebdescribe 'format' do URL_TEST_DATA.each_pair do |url, result| it "#{url}" do parsed = MDUrl::Url.urlParse(url) expect(MDUrl::Format.format(parsed)).to eq url end end end mdurl-rb-1.0.5/spec/mdurl-rb/fixtures/0000755000175100017510000000000014123311515017746 5ustar vivekdebvivekdebmdurl-rb-1.0.5/spec/mdurl-rb/fixtures/url_spec.rb0000755000175100017510000004154514123311515022123 0ustar vivekdebvivekdeb# Copyright Joyent, Inc. and other Node contributors. # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to permit # persons to whom the Software is furnished to do so, subject to the # following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN # NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, # DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE # USE OR OTHER DEALINGS IN THE SOFTWARE. # URLs to parse, and expected data # { url : parsed } URL_TEST_DATA = { '//some_path' => { 'pathname' => '//some_path' }, 'HTTP://www.example.com/' => { 'protocol' => 'HTTP:', 'slashes' => true, 'hostname' => 'www.example.com', 'pathname' => '/' }, 'HTTP://www.example.com' => { 'protocol' => 'HTTP:', 'slashes' => true, 'hostname' => 'www.example.com', 'pathname' => '' }, 'http://www.ExAmPlE.com/' => { 'protocol' => 'http:', 'slashes' => true, 'hostname' => 'www.ExAmPlE.com', 'pathname' => '/' }, 'http://user:pw@www.ExAmPlE.com/' => { 'protocol' => 'http:', 'slashes' => true, 'auth' => 'user:pw', 'hostname' => 'www.ExAmPlE.com', 'pathname' => '/' }, 'http://USER:PW@www.ExAmPlE.com/' => { 'protocol' => 'http:', 'slashes' => true, 'auth' => 'USER:PW', 'hostname' => 'www.ExAmPlE.com', 'pathname' => '/' }, 'http://user@www.example.com/' => { 'protocol' => 'http:', 'slashes' => true, 'auth' => 'user', 'hostname' => 'www.example.com', 'pathname' => '/' }, 'http://user%3Apw@www.example.com/' => { 'protocol' => 'http:', 'slashes' => true, 'auth' => 'user%3Apw', 'hostname' => 'www.example.com', 'pathname' => '/' }, 'http://x.com/path?that\'s#all, folks' => { 'protocol' => 'http:', 'hostname' => 'x.com', 'slashes' => true, 'search' => '?that\'s', 'pathname' => '/path', 'hash' => '#all, folks' }, 'HTTP://X.COM/Y' => { 'protocol' => 'HTTP:', 'slashes' => true, 'hostname' => 'X.COM', 'pathname' => '/Y' }, # + not an invalid host character # per https://url.spec.whatwg.org/#host-parsing 'http://x.y.com+a/b/c' => { 'protocol' => 'http:', 'slashes' => true, 'hostname' => 'x.y.com+a', 'pathname' => '/b/c' }, # an unexpected invalid char in the hostname. 'HtTp://x.y.cOm;a/b/c?d=e#f gi' => { 'protocol' => 'HtTp:', 'slashes' => true, 'hostname' => 'x.y.cOm', 'pathname' => ';a/b/c', 'search' => '?d=e', 'hash' => '#f gi' }, # make sure that we don't accidentally lcast the path parts. 'HtTp://x.y.cOm;A/b/c?d=e#f gi' => { 'protocol' => 'HtTp:', 'slashes' => true, 'hostname' => 'x.y.cOm', 'pathname' => ';A/b/c', 'search' => '?d=e', 'hash' => '#f gi' }, 'http://x...y...#p' => { 'protocol' => 'http:', 'slashes' => true, 'hostname' => 'x...y...', 'hash' => '#p', 'pathname' => '' }, 'http://x/p/"quoted"' => { 'protocol' => 'http:', 'slashes' => true, 'hostname' => 'x', 'pathname' => '/p/"quoted"' }, ' Is a URL!' => { 'pathname' => ' Is a URL!' }, 'http://www.narwhaljs.org/blog/categories?id=news' => { 'protocol' => 'http:', 'slashes' => true, 'hostname' => 'www.narwhaljs.org', 'search' => '?id=news', 'pathname' => '/blog/categories' }, 'http://mt0.google.com/vt/lyrs=m@114&hl=en&src=api&x=2&y=2&z=3&s=' => { 'protocol' => 'http:', 'slashes' => true, 'hostname' => 'mt0.google.com', 'pathname' => '/vt/lyrs=m@114&hl=en&src=api&x=2&y=2&z=3&s=' }, 'http://mt0.google.com/vt/lyrs=m@114???&hl=en&src=api&x=2&y=2&z=3&s=' => { 'protocol' => 'http:', 'slashes' => true, 'hostname' => 'mt0.google.com', 'search' => '???&hl=en&src=api&x=2&y=2&z=3&s=', 'pathname' => '/vt/lyrs=m@114' }, 'http://user:pass@mt0.google.com/vt/lyrs=m@114???&hl=en&src=api&x=2&y=2&z=3&s=' => { 'protocol' => 'http:', 'slashes' => true, 'auth' => 'user:pass', 'hostname' => 'mt0.google.com', 'search' => '???&hl=en&src=api&x=2&y=2&z=3&s=', 'pathname' => '/vt/lyrs=m@114' }, 'file:///etc/passwd' => { 'slashes' => true, 'protocol' => 'file:', 'pathname' => '/etc/passwd', 'hostname' => '' }, 'file://localhost/etc/passwd' => { 'protocol' => 'file:', 'slashes' => true, 'pathname' => '/etc/passwd', 'hostname' => 'localhost' }, 'file://foo/etc/passwd' => { 'protocol' => 'file:', 'slashes' => true, 'pathname' => '/etc/passwd', 'hostname' => 'foo' }, 'file:///etc/node/' => { 'slashes' => true, 'protocol' => 'file:', 'pathname' => '/etc/node/', 'hostname' => '' }, 'file://localhost/etc/node/' => { 'protocol' => 'file:', 'slashes' => true, 'pathname' => '/etc/node/', 'hostname' => 'localhost' }, 'file://foo/etc/node/' => { 'protocol' => 'file:', 'slashes' => true, 'pathname' => '/etc/node/', 'hostname' => 'foo' }, 'http:/baz/../foo/bar' => { 'protocol' => 'http:', 'pathname' => '/baz/../foo/bar' }, 'http://user:pass@example.com:8000/foo/bar?baz=quux#frag' => { 'protocol' => 'http:', 'slashes' => true, 'auth' => 'user:pass', 'port' => '8000', 'hostname' => 'example.com', 'hash' => '#frag', 'search' => '?baz=quux', 'pathname' => '/foo/bar' }, '//user:pass@example.com:8000/foo/bar?baz=quux#frag' => { 'slashes' => true, 'auth' => 'user:pass', 'port' => '8000', 'hostname' => 'example.com', 'hash' => '#frag', 'search' => '?baz=quux', 'pathname' => '/foo/bar' }, '/foo/bar?baz=quux#frag' => { 'hash' => '#frag', 'search' => '?baz=quux', 'pathname' => '/foo/bar' }, 'http:/foo/bar?baz=quux#frag' => { 'protocol' => 'http:', 'hash' => '#frag', 'search' => '?baz=quux', 'pathname' => '/foo/bar' }, 'mailto:foo@bar.com?subject=hello' => { 'protocol' => 'mailto:', 'auth' => 'foo', 'hostname' => 'bar.com', 'search' => '?subject=hello', 'pathname' => '' }, 'javascript:alert(\'hello\');' => { 'protocol' => 'javascript:', 'pathname' => 'alert(\'hello\');' }, 'xmpp:isaacschlueter@jabber.org' => { 'protocol' => 'xmpp:', 'auth' => 'isaacschlueter', 'hostname' => 'jabber.org' }, 'http://atpass:foo%40bar@127.0.0.1:8080/path?search=foo#bar' => { 'protocol' => 'http:', 'slashes' => true, 'auth' => 'atpass:foo%40bar', 'hostname' => '127.0.0.1', 'port' => '8080', 'pathname' => '/path', 'search' => '?search=foo', 'hash' => '#bar' }, 'svn+ssh://foo/bar' => { 'hostname' => 'foo', 'protocol' => 'svn+ssh:', 'pathname' => '/bar', 'slashes' => true }, 'dash-test://foo/bar' => { 'hostname' => 'foo', 'protocol' => 'dash-test:', 'pathname' => '/bar', 'slashes' => true }, 'dash-test:foo/bar' => { 'hostname' => 'foo', 'protocol' => 'dash-test:', 'pathname' => '/bar' }, 'dot.test://foo/bar' => { 'hostname' => 'foo', 'protocol' => 'dot.test:', 'pathname' => '/bar', 'slashes' => true }, 'dot.test:foo/bar' => { 'hostname' => 'foo', 'protocol' => 'dot.test:', 'pathname' => '/bar' }, # IDNA tests 'http://www.日本語.com/' => { 'protocol' => 'http:', 'slashes' => true, 'hostname' => 'www.日本語.com', 'pathname' => '/' }, 'http://example.Bücher.com/' => { 'protocol' => 'http:', 'slashes' => true, 'hostname' => 'example.Bücher.com', 'pathname' => '/' }, 'http://www.Äffchen.com/' => { 'protocol' => 'http:', 'slashes' => true, 'hostname' => 'www.Äffchen.com', 'pathname' => '/' }, 'http://www.Äffchen.cOm;A/b/c?d=e#f gi' => { 'protocol' => 'http:', 'slashes' => true, 'hostname' => 'www.Äffchen.cOm', 'pathname' => ';A/b/c', 'search' => '?d=e', 'hash' => '#f gi' }, 'http://SÉLIER.COM/' => { 'protocol' => 'http:', 'slashes' => true, 'hostname' => 'SÉLIER.COM', 'pathname' => '/' }, 'http://ليهمابتكلموشعربي؟.ي؟/' => { 'protocol' => 'http:', 'slashes' => true, 'hostname' => 'ليهمابتكلموشعربي؟.ي؟', 'pathname' => '/' }, 'http://➡.ws/➡' => { 'protocol' => 'http:', 'slashes' => true, 'hostname' => '➡.ws', 'pathname' => '/➡' }, 'http://bucket_name.s3.amazonaws.com/image.jpg' => { 'protocol' => 'http:', 'slashes' => true, 'hostname' => 'bucket_name.s3.amazonaws.com', 'pathname' => '/image.jpg' }, 'git+http://github.com/joyent/node.git' => { 'protocol' => 'git+http:', 'slashes' => true, 'hostname' => 'github.com', 'pathname' => '/joyent/node.git' }, # if local1@domain1 is uses as a relative URL it may # be parse into auth@hostname, but here there is no # way to make it work in url.parse, I add the test to be explicit 'local1@domain1' => { 'pathname' => 'local1@domain1' }, # While this may seem counter-intuitive, a browser will parse # as a path. 'www.example.com' => { 'pathname' => 'www.example.com' }, # ipv6 support '[fe80::1]' => { 'pathname' => '[fe80::1]' }, 'coap://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]' => { 'protocol' => 'coap:', 'slashes' => true, 'hostname' => 'FEDC:BA98:7654:3210:FEDC:BA98:7654:3210' }, 'coap://[1080:0:0:0:8:800:200C:417A]:61616/' => { 'protocol' => 'coap:', 'slashes' => true, 'port' => '61616', 'hostname' => '1080:0:0:0:8:800:200C:417A', 'pathname' => '/' }, 'http://user:password@[3ffe:2a00:100:7031::1]:8080' => { 'protocol' => 'http:', 'slashes' => true, 'auth' => 'user:password', 'port' => '8080', 'hostname' => '3ffe:2a00:100:7031::1', 'pathname' => '' }, 'coap://u:p@[::192.9.5.5]:61616/.well-known/r?n=Temperature' => { 'protocol' => 'coap:', 'slashes' => true, 'auth' => 'u:p', 'port' => '61616', 'hostname' => '::192.9.5.5', 'search' => '?n=Temperature', 'pathname' => '/.well-known/r' }, # empty port 'http://example.com:' => { 'protocol' => 'http:', 'slashes' => true, 'hostname' => 'example.com', 'pathname' => ':' }, 'http://example.com:/a/b.html' => { 'protocol' => 'http:', 'slashes' => true, 'hostname' => 'example.com', 'pathname' => ':/a/b.html' }, 'http://example.com:?a=b' => { 'protocol' => 'http:', 'slashes' => true, 'hostname' => 'example.com', 'search' => '?a=b', 'pathname' => ':' }, 'http://example.com:#abc' => { 'protocol' => 'http:', 'slashes' => true, 'hostname' => 'example.com', 'hash' => '#abc', 'pathname' => ':' }, 'http://[fe80::1]:/a/b?a=b#abc' => { 'protocol' => 'http:', 'slashes' => true, 'hostname' => 'fe80::1', 'search' => '?a=b', 'hash' => '#abc', 'pathname' => ':/a/b' }, 'http://-lovemonsterz.tumblr.com/rss' => { 'protocol' => 'http:', 'slashes' => true, 'hostname' => '-lovemonsterz.tumblr.com', 'pathname' => '/rss' }, 'http://-lovemonsterz.tumblr.com:80/rss' => { 'protocol' => 'http:', 'slashes' => true, 'port' => '80', 'hostname' => '-lovemonsterz.tumblr.com', 'pathname' => '/rss' }, 'http://user:pass@-lovemonsterz.tumblr.com/rss' => { 'protocol' => 'http:', 'slashes' => true, 'auth' => 'user:pass', 'hostname' => '-lovemonsterz.tumblr.com', 'pathname' => '/rss' }, 'http://user:pass@-lovemonsterz.tumblr.com:80/rss' => { 'protocol' => 'http:', 'slashes' => true, 'auth' => 'user:pass', 'port' => '80', 'hostname' => '-lovemonsterz.tumblr.com', 'pathname' => '/rss' }, 'http://_jabber._tcp.google.com/test' => { 'protocol' => 'http:', 'slashes' => true, 'hostname' => '_jabber._tcp.google.com', 'pathname' => '/test' }, 'http://user:pass@_jabber._tcp.google.com/test' => { 'protocol' => 'http:', 'slashes' => true, 'auth' => 'user:pass', 'hostname' => '_jabber._tcp.google.com', 'pathname' => '/test' }, 'http://_jabber._tcp.google.com:80/test' => { 'protocol' => 'http:', 'slashes' => true, 'port' => '80', 'hostname' => '_jabber._tcp.google.com', 'pathname' => '/test' }, 'http://user:pass@_jabber._tcp.google.com:80/test' => { 'protocol' => 'http:', 'slashes' => true, 'auth' => 'user:pass', 'port' => '80', 'hostname' => '_jabber._tcp.google.com', 'pathname' => '/test' }, 'http://x:1/\' <>"`/{}|\\^~`/' => { 'protocol' => 'http:', 'slashes' => true, 'port' => '1', 'hostname' => 'x', 'pathname' => '/\' <>"`/{}|\\^~`/' }, 'http://a@b@c/' => { 'protocol' => 'http:', 'slashes' => true, 'auth' => 'a@b', 'hostname' => 'c', 'pathname' => '/' }, 'http://a@b?@c' => { 'protocol' => 'http:', 'slashes' => true, 'auth' => 'a', 'hostname' => 'b', 'pathname' => '', 'search' => '?@c' }, 'http://a\r" \t\n<\'b:b@c\r\nd/e?f' =>{ 'protocol' => 'http:', 'slashes' => true, 'auth' => 'a\r" \t\n<\'b:b', 'hostname' => 'c', 'search' => '?f', 'pathname' => '\r\nd/e' }, # git urls used by npm 'git+ssh://git@github.com:npm/npm' => { 'protocol' => 'git+ssh:', 'slashes' => true, 'auth' => 'git', 'hostname' => 'github.com', 'pathname' => ':npm/npm' }, 'http://example.com?foo=bar#frag' => { 'protocol' => 'http:', 'slashes' => true, 'hostname' => 'example.com', 'hash' => '#frag', 'search' => '?foo=bar', 'pathname' => '' }, 'http://example.com?foo=@bar#frag' => { 'protocol' => 'http:', 'slashes' => true, 'hostname' => 'example.com', 'hash' => '#frag', 'search' => '?foo=@bar', 'pathname' => '' }, 'http://example.com?foo=/bar/#frag' => { 'protocol' => 'http:', 'slashes' => true, 'hostname' => 'example.com', 'hash' => '#frag', 'search' => '?foo=/bar/', 'pathname' => '' }, 'http://example.com?foo=?bar/#frag' => { 'protocol' => 'http:', 'slashes' => true, 'hostname' => 'example.com', 'hash' => '#frag', 'search' => '?foo=?bar/', 'pathname' => '' }, 'http://example.com#frag=?bar/#frag' => { 'protocol' => 'http:', 'slashes' => true, 'hostname' => 'example.com', 'hash' => '#frag=?bar/#frag', 'pathname' => '' }, 'http://google.com" onload="alert(42)/' => { 'hostname' => 'google.com', 'protocol' => 'http:', 'slashes' => true, 'pathname' => '" onload="alert(42)/' }, 'http://a.com/a/b/c?s#h' => { 'protocol' => 'http:', 'slashes' => true, 'pathname' => '/a/b/c', 'hostname' => 'a.com', 'hash' => '#h', 'search' => '?s' }, 'http://atpass:foo%40bar@127.0.0.1/' => { 'auth' => 'atpass:foo%40bar', 'slashes' => true, 'hostname' => '127.0.0.1', 'protocol' => 'http:', 'pathname' => '/' }, 'http://atslash%2F%40:%2F%40@foo/' => { 'auth' => 'atslash%2F%40:%2F%40', 'hostname' => 'foo', 'protocol' => 'http:', 'pathname' => '/', 'slashes' => true }, # ipv6 support 'coap:u:p@[::1]:61616/.well-known/r?n=Temperature' => { 'protocol' => 'coap:', 'auth' => 'u:p', 'hostname' => '::1', 'port' => '61616', 'pathname' => '/.well-known/r', 'search' => '?n=Temperature' }, 'coap:[fedc:ba98:7654:3210:fedc:ba98:7654:3210]:61616/s/stopButton' => { 'hostname' => 'fedc:ba98:7654:3210:fedc:ba98:7654:3210', 'port' => '61616', 'protocol' => 'coap:', 'pathname' => '/s/stopButton' }, # encode context-specific delimiters in path and query, but do not touch # other non-delimiter chars like `%`. # # `?` and `#` in path and search 'http://ex.com/foo%3F100%m%23r?abc=the%231?&foo=bar#frag' => { 'protocol' => 'http:', 'hostname' => 'ex.com', 'hash' => '#frag', 'search' => '?abc=the%231?&foo=bar', 'pathname' => '/foo%3F100%m%23r', 'slashes' => true }, # `?` and `#` in search only 'http://ex.com/fooA100%mBr?abc=the%231?&foo=bar#frag' => { 'protocol' => 'http:', 'hostname' => 'ex.com', 'hash' => '#frag', 'search' => '?abc=the%231?&foo=bar', 'pathname' => '/fooA100%mBr', 'slashes' => true } }; mdurl-rb-1.0.5/spec/mdurl-rb/encode_spec.rb0000755000175100017510000000423014123311515020673 0ustar vivekdebvivekdebdescribe 'encode' do it 'should encode percent' do expect(MDUrl::Encode.encode("%%%")).to eq '%25%25%25' end it 'should encode control chars' do expect(MDUrl::Encode.encode("\r\n")).to eq '%0D%0A' end it 'should not encode parts of an url' do expect(MDUrl::Encode.encode('?#')).to eq '?#' end it 'should not encode []^ - commonmark tests' do expect(MDUrl::Encode.encode('[]^')).to eq '%5B%5D%5E' end it 'should encode spaces' do expect(MDUrl::Encode.encode('my url')).to eq 'my%20url' end it 'should encode unicode' do expect(MDUrl::Encode.encode('φου')).to eq '%CF%86%CE%BF%CF%85' end it 'should encode % if it doesn\'t start a valid escape seq' do expect(MDUrl::Encode.encode('%FG')).to eq '%25FG' end it 'should preserve non-utf8 encoded characters' do expect(MDUrl::Encode.encode('%00%FF')).to eq '%00%FF' end # it 'should encode characters on the cache borders' do # # protects against off-by-one in cache implementation # expect(MDUrl::Encode.encode("\x00\x7F\x80")).to eq '%00%7F%C2%80' # end describe 'arguments' do it 'encode(string, unescapedSet)' do expect(MDUrl::Encode.encode('!@#$', '@$')).to eq '%21@%23$' end it 'encode(string, keepEscaped=true)' do expect(MDUrl::Encode.encode('%20%2G', true)).to eq '%20%252G' end it 'encode(string, keepEscaped=false)' do expect(MDUrl::Encode.encode('%20%2G', false)).to eq '%2520%252G' end it 'encode(string, unescapedSet, keepEscaped)' do expect(MDUrl::Encode.encode('!@%25', '@', false)).to eq '%21@%2525' end end # TODO don't know how to fix utf8 issue yet # describe 'surrogates' do # it 'bad surrogates (high)' do # expect(MDUrl::Encode.encode("\uD800foo")).to eq '%EF%BF%BDfoo' # expect(MDUrl::Encode.encode("foo\uD800")).to eq 'foo%EF%BF%BD' # end # # it 'bad surrogates (low)' do # expect(MDUrl::Encode.encode("\uDD00foo")).to eq '%EF%BF%BDfoo' # expect(MDUrl::Encode.encode("foo\uDD00")).to eq 'foo%EF%BF%BD' # end # # it 'valid one' do # expect(MDUrl::Encode.encode("\uD800\uDD00")).to eq '%F0%90%84%80' # end # end end mdurl-rb-1.0.5/spec/mdurl-rb/decode_spec.rb0000755000175100017510000000614014123311515020663 0ustar vivekdebvivekdebdef encodeBinary(str) result = '' str = str.gsub(/\s+/, '') while (str.length > 0) result = '%' + ('0' + str.slice(-8..-1).to_i(2).to_s(16)).slice(-2, 2) + result str = str.slice(0...-8) end return result end samples = { '00000000' => true, '01010101' => true, '01111111' => true, # invalid as 1st byte '10000000' => false, '10111111' => false, # invalid sequences, 2nd byte should be >= 0x80 '11000111 01010101' => false, '11100011 01010101' => false, '11110001 01010101' => false, # invalid sequences, 2nd byte should be < 0xc0 '11000111 11000000' => false, '11100011 11000000' => false, '11110001 11000000' => false, # invalid 3rd byte '11100011 10010101 01010101' => false, '11110001 10010101 01010101' => false, # invalid 4th byte '11110001 10010101 10010101 01010101' => false, # valid sequences '11000111 10101010' => true, '11100011 10101010 10101010' => true, # '11110001 10101010 10101010 10101010' => true, # TODO don't know how to handle surrogate pairs # minimal chars with given length '11000010 10000000' => true, '11100000 10100000 10000000' => true, # impossible sequences '11000001 10111111' => false, '11100000 10011111 10111111' => false, '11000001 10000000' => false, '11100000 10010000 10000000' => false, # maximum chars with given length '11011111 10111111' => true, '11101111 10111111 10111111' => true, # '11110000 10010000 10000000 10000000' => true, # TODO don't know how to handle surrogate pairs # '11110000 10010000 10001111 10001111' => true, # TODO don't know how to handle surrogate pairs # '11110100 10001111 10110000 10000000' => true, # TODO don't know how to handle surrogate pairs # '11110100 10001111 10111111 10111111' => true, # TODO don't know how to handle surrogate pairs # too low '11110000 10001111 10111111 10111111' => false, # too high '11110100 10010000 10000000 10000000' => false, '11110100 10011111 10111111 10111111' => false, # surrogate range '11101101 10011111 10111111' => true, '11101101 10100000 10000000' => false, '11101101 10111111 10111111' => false, '11101110 10000000 10000000' => true } describe 'decode' do it 'should decode %xx' do expect(MDUrl::Decode.decode('x%20xx%20%2520')).to eq 'x xx %20' end it 'should not decode invalid sequences' do expect(MDUrl::Decode.decode('%2g%z1%%')).to eq '%2g%z1%%' end it 'should not decode reservedSet' do expect(MDUrl::Decode.decode('%20%25%20', '%')).to eq ' %25 ' expect(MDUrl::Decode.decode('%20%25%20', ' ')).to eq '%20%%20' expect(MDUrl::Decode.decode('%20%25%20', ' %')).to eq '%20%25%20' end describe 'utf8' do samples.each_pair do |k, v| it "#{k}" do er = nil str = encodeBinary(k) if v == true res1 = CGI::unescape(str, Encoding::UTF_8) res2 = MDUrl::Decode.decode(str) expect(res1).to eq res2 expect(res2.index("\ufffd")).to eq nil else res2 = MDUrl::Decode.decode(str) expect(res2.index("\ufffd")).not_to eq nil end end end end end mdurl-rb-1.0.5/lib/0000755000175100017510000000000014123311515014165 5ustar vivekdebvivekdebmdurl-rb-1.0.5/lib/mdurl-rb/0000755000175100017510000000000014123311515015711 5ustar vivekdebvivekdebmdurl-rb-1.0.5/lib/mdurl-rb/version.rb0000644000175100017510000000004714123311515017724 0ustar vivekdebvivekdebmodule MDUrl VERSION = '1.0.5' end mdurl-rb-1.0.5/lib/mdurl-rb/parse.rb0000755000175100017510000002411714123311515017360 0ustar vivekdebvivekdeb# Copyright Joyent, Inc. and other Node contributors. # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to permit # persons to whom the Software is furnished to do so, subject to the # following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN # NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, # DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE # USE OR OTHER DEALINGS IN THE SOFTWARE. # # Changes from joyent/node: # # 1. No leading slash in paths, # e.g. in `url.parse('http://foo?bar')` pathname is ``, not `/` # # 2. Backslashes are not replaced with slashes, # so `http:\\example.org\` is treated like a relative path # # 3. Trailing colon is treated like a part of the path, # i.e. in `http://example.org:foo` pathname is `:foo` # # 4. Nothing is URL-encoded in the resulting object, # (in joyent/node some chars in auth and paths are encoded) # # 5. `url.parse()` does not have `parseQueryString` argument # # 6. Removed extraneous result properties: `host`, `path`, `query`, etc., # which can be constructed using other parts of the url. # module MDUrl class Url attr_accessor :protocol, :slashes, :hostname, :pathname, :auth, :port, :search, :hash # Reference: RFC 3986, RFC 1808, RFC 2396 # define these here so at least they only have to be # compiled once on the first module load. PROTOCOL_PATTERN = /^([a-z0-9.+-]+:)/i PORT_PATTERN = /:[0-9]*$/ # Special case for a simple path URL SIMPLE_PATH_PATTERN = /^(\/\/?(?!\/)[^\?\s]*)(\?[^\s]*)?$/ # RFC 2396: characters reserved for delimiting URLs. # We actually just auto-escape these. DELIMS = [ '<', '>', '"', '`', ' ', '\r', '\n', '\t' ] # RFC 2396: characters not allowed for various reasons. UNWISE = [ '{', '}', '|', '\\', '^', '`' ].concat(DELIMS) # Allowed by RFCs, but cause of XSS attacks. Always escape these. AUTO_ESCAPE = [ '\'' ].concat(UNWISE) # Characters that are never ever allowed in a hostname. # Note that any invalid chars are also handled, but these # are the ones that are *expected* to be seen, so we fast-path # them. NON_HOST_CHARS = [ '%', '/', '?', ';', '#' ].concat(AUTO_ESCAPE) HOST_ENDING_CHARS = [ '/', '?', '#' ] HOSTNAME_MAX_LEN = 255 HOSTNAME_PART_PATTERN = /^[+a-z0-9A-Z_-]{0,63}$/ HOSTNAME_PART_START = /^([+a-z0-9A-Z_-]{0,63})(.*)$/ # protocols that can allow "unsafe" and "unwise" chars. # protocols that never have a hostname. HOSTLESS_PROTOCOL = { 'javascript' => true, 'javascript:' => true } # protocols that always contain a # bit. SLASHED_PROTOCOL = { 'http' => true, 'https' => true, 'ftp' => true, 'gopher' => true, 'file' => true, 'http:' => true, 'https:' => true, 'ftp:' => true, 'gopher:' => true, 'file:' => true } #------------------------------------------------------------------------------ def self.urlParse(url, slashesDenoteHost = false) return url if (url && url.is_a?(Url)) u = Url.new u.parse(url, slashesDenoteHost) return u end #------------------------------------------------------------------------------ def parse(url, slashesDenoteHost = false) rest = url # trim before proceeding. # This is to support parse stuff like " http://foo.com \n" rest = rest.strip if (!slashesDenoteHost && url.split('#').length == 1) # Try fast path regexp simplePath = SIMPLE_PATH_PATTERN.match(rest) if (simplePath) @pathname = simplePath[1] if (simplePath[2]) @search = simplePath[2] end return self end end proto = PROTOCOL_PATTERN.match(rest) if (proto) proto = proto[0] lowerProto = proto.downcase @protocol = proto rest = rest[proto.length..-1] end # figure out if it's got a host # user@server is *always* interpreted as a hostname, and url # resolution will treat //foo/bar as host=foo,path=bar because that's # how the browser resolves relative URLs. if (slashesDenoteHost || proto || rest.match(/^\/\/[^@\/]+@[^@\/]+/)) slashes = rest[0...2] == '//' if (slashes && !(proto && HOSTLESS_PROTOCOL[proto])) rest = rest[2..-1] @slashes = true end end if (!HOSTLESS_PROTOCOL[proto] && (slashes || (proto && !SLASHED_PROTOCOL[proto]))) # there's a hostname. # the first instance of /, ?, ;, or # ends the host. # # If there is an @ in the hostname, then non-host chars *are* allowed # to the left of the last @ sign, unless some host-ending character # comes *before* the @-sign. # URLs are obnoxious. # # ex: # http://a@b@c/ => user:a@b host:c # http://a@b?@c => user:a host:c path:/?@c # v0.12 TODO(isaacs): This is not quite how Chrome does things. # Review our test case against browsers more comprehensively. # find the first instance of any HOST_ENDING_CHARS hostEnd = -1 (0...HOST_ENDING_CHARS.length).each do |i| hec = rest.index(HOST_ENDING_CHARS[i]) if (hec != nil && (hostEnd == -1 || hec < hostEnd)) hostEnd = hec end end # at this point, either we have an explicit point where the # auth portion cannot go past, or the last @ char is the decider. if (hostEnd == -1) # atSign can be anywhere. atSign = rest.rindex('@') else # atSign must be in auth portion. # http://a@b/c@d => host:b auth:a path:/c@d # atSign = rest.lastIndexOf('@', hostEnd); atSign = rest[0..hostEnd].rindex('@') end # Now we have a portion which is definitely the auth. # Pull that off. if (atSign != nil) auth = rest.slice(0...atSign) rest = rest.slice((atSign + 1)..-1) @auth = auth end # the host is the remaining to the left of the first non-host char hostEnd = -1 (0...NON_HOST_CHARS.length).each do |i| hec = rest.index(NON_HOST_CHARS[i]) if (hec != nil && (hostEnd == -1 || hec < hostEnd)) hostEnd = hec end end # if we still have not hit it, then the entire thing is a host. if (hostEnd === -1) hostEnd = rest.length end hostEnd -= 1 if (rest[hostEnd - 1] == ':') host = rest.slice(0...hostEnd) rest = rest.slice(hostEnd..-1) # pull out port. self.parseHost(host) # we've indicated that there is a hostname, # so even if it's empty, it has to be present. @hostname = @hostname || '' # if hostname begins with [ and ends with ] # assume that it's an IPv6 address. ipv6Hostname = @hostname[0] == '[' && @hostname[@hostname.length - 1] == ']' # validate a little. if (!ipv6Hostname) hostparts = @hostname.split(/\./) (0...hostparts.length).each do |i| part = hostparts[i] next if (!part) if (!part.match(HOSTNAME_PART_PATTERN)) newpart = '' (0...part.length).each do |j| if (part[j].ord > 127) # we replace non-ASCII char with a temporary placeholder # we need this to make sure size of hostname is not # broken by replacing non-ASCII by nothing newpart += 'x' else newpart += part[j] end end # we test again with ASCII char only if (!newpart.match(HOSTNAME_PART_PATTERN)) validParts = hostparts.slice(0...i) notHost = hostparts.slice((i + 1)..-1) bit = part.match(HOSTNAME_PART_START) if (bit) validParts.push(bit[1]) notHost.unshift(bit[2]) end if (notHost.length) rest = notHost.join('.') + rest end @hostname = validParts.join('.') break end end end end if (@hostname.length > HOSTNAME_MAX_LEN) @hostname = '' end # strip [ and ] from the hostname # the host field still retains them, though if (ipv6Hostname) @hostname = @hostname[1, @hostname.length - 2] end end # chop off from the tail first. hash = rest.index('#') if (hash != nil) # got a fragment string. @hash = rest.slice(hash..-1) rest = rest.slice(0...hash) end qm = rest.index('?') if (qm != nil) @search = rest.slice(qm..-1) rest = rest.slice(0...qm) end @pathname = rest if !rest.nil? && rest != '' if (SLASHED_PROTOCOL[lowerProto] && @hostname && !@pathname) @pathname = '' end return self end #------------------------------------------------------------------------------ def parseHost(host) port = PORT_PATTERN.match(host) if (port) port = port[0] if (port != ':') @port = port.slice(1..-1) end host = host[0, host.length - port.length] end @hostname = host if (host) end end endmdurl-rb-1.0.5/lib/mdurl-rb/format.rb0000755000175100017510000000121614123311515017531 0ustar vivekdebvivekdebmodule MDUrl module Format #------------------------------------------------------------------------------ def self.format(url) result = '' result += url.protocol || '' result += url.slashes ? '//' : '' result += url.auth ? url.auth + '@' : '' if (url.hostname && url.hostname.index(':') != nil) # ipv6 address result += '[' + url.hostname + ']' else result += url.hostname || '' end result += url.port ? ':' + url.port : '' result += url.pathname || '' result += url.search || '' result += url.hash || '' return result end end end mdurl-rb-1.0.5/lib/mdurl-rb/encode.rb0000755000175100017510000000500214123311515017473 0ustar vivekdebvivekdebmodule MDUrl module Encode DEFAULT_CHARACTERS = ";/?:@&=+$,-_.!~*'()#" COMPONENT_CHARACTERS = "-_.!~*'()" @@encodeCache = {} # Create a lookup array where anything but characters in `chars` string # and alphanumeric chars is percent-encoded. #------------------------------------------------------------------------------ def self.getEncodeCache(exclude) cache = @@encodeCache[exclude] return cache if (cache) cache = @@encodeCache[exclude] = [] (0...128).each do |i| ch = i.chr if (/^[0-9a-z]$/i =~ ch) # always allow unencoded alphanumeric characters cache.push(ch) else cache.push('%' + ('0' + i.to_s(16).upcase).slice(-2, 2)) end end (0...exclude.length).each do |i| cache[exclude[i].ord] = exclude[i] end return cache end # Encode unsafe characters with percent-encoding, skipping already # encoded sequences. # # - string - string to encode # - exclude - list of characters to ignore (in addition to a-zA-Z0-9) # - keepEscaped - don't encode '%' in a correct escape sequence (default: true) #------------------------------------------------------------------------------ def self.encode(string, exclude = nil, keepEscaped = nil) result = '' if !exclude.is_a? String # encode(string, keepEscaped) keepEscaped = exclude exclude = DEFAULT_CHARACTERS end if keepEscaped == nil keepEscaped = true end cache = getEncodeCache(exclude) i = 0 l = string.length while i < l code = string[i].ord if (keepEscaped && code == 0x25 && i + 2 < l) # % if (/^[0-9a-f]{2}$/i =~ (string.slice((i + 1)...(i + 3)))) result += string.slice(i...(i + 3)) i += 3 next end end if (code < 128) result += cache[code] i += 1 next end if (code >= 0xD800 && code <= 0xDFFF) if (code >= 0xD800 && code <= 0xDBFF && i + 1 < l) nextCode = string[i + 1].ord if (nextCode >= 0xDC00 && nextCode <= 0xDFFF) result += CGI::escape(string[i] + string[i + 1]) i += 2 next end end result += '%EF%BF%BD' i += 1 next end result += CGI::escape(string[i]) i += 1 end return result end end endmdurl-rb-1.0.5/lib/mdurl-rb/decode.rb0000755000175100017510000000746614123311515017501 0ustar vivekdebvivekdebmodule MDUrl module Decode @@decodeCache = {}; DEFTAULT_CHARS = ';/?:@&=+$,#' COMPONENT_CHARS = '' #------------------------------------------------------------------------------ def self.getDecodeCache(exclude) cache = @@decodeCache[exclude] return cache if (cache) cache = @@decodeCache[exclude] = [] (0...128).each do |i| ch = i.chr cache.push(ch) end (0...exclude.length).each do |i| ch = exclude[i].ord cache[ch] = '%' + ('0' + ch.to_s(16).upcase).slice(-2, 2) end return cache end # Decode percent-encoded string. #------------------------------------------------------------------------------ def self.decode(string, exclude = nil) if !exclude.is_a? String exclude = DEFTAULT_CHARS end cache = getDecodeCache(exclude) return string.gsub(/(%[a-f0-9]{2})+/i) do |seq| result = '' i = 0 l = seq.length while i < l b1 = seq.slice((i + 1)...(i + 3)).to_i(16) if (b1 < 0x80) result += cache[b1] i += 3 next end if ((b1 & 0xE0) == 0xC0 && (i + 3 < l)) # 110xxxxx 10xxxxxx b2 = seq.slice((i + 4)...(i + 6)).to_i(16) if ((b2 & 0xC0) == 0x80) char = ((b1 << 6) & 0x7C0) | (b2 & 0x3F) if (char < 0x80) result += "\ufffd\ufffd" else result += char.chr(Encoding::UTF_8) end i += 6 next end end if ((b1 & 0xF0) == 0xE0 && (i + 6 < l)) # 1110xxxx 10xxxxxx 10xxxxxx b2 = seq.slice((i + 4)...(i + 6)).to_i(16) b3 = seq.slice((i + 7)...(i + 9)).to_i(16) if ((b2 & 0xC0) == 0x80 && (b3 & 0xC0) == 0x80) char = ((b1 << 12) & 0xF000) | ((b2 << 6) & 0xFC0) | (b3 & 0x3F) if (char < 0x800 || (char >= 0xD800 && char <= 0xDFFF)) result += "\ufffd\ufffd\ufffd" else result += char.chr(Encoding::UTF_8) end i += 9 next end end if ((b1 & 0xF8) == 0xF0 && (i + 9 < l)) # 111110xx 10xxxxxx 10xxxxxx 10xxxxxx b2 = seq.slice((i + 4)...(i + 6)).to_i(16) b3 = seq.slice((i + 7)...(i + 9)).to_i(16) b4 = seq.slice((i + 10)...(i + 12)).to_i(16) if ((b2 & 0xC0) == 0x80 && (b3 & 0xC0) == 0x80 && (b4 & 0xC0) == 0x80) char = ((b1 << 18) & 0x1C0000) | ((b2 << 12) & 0x3F000) | ((b3 << 6) & 0xFC0) | (b4 & 0x3F) if (char < 0x10000 || char > 0x10FFFF) result += "\ufffd\ufffd\ufffd\ufffd" else # TODO don't know how to handle surrogate pairs properly. char -= 0x10000 result += [0xD800 + (char >> 10), 0xDC00 + (char & 0x3FF)].map{|c| c.chr(Encoding::UTF_8)}.join # high = ((char - 0x10000) / 0x400).floor + 0xD800 # low = ((char - 0x10000) % 0x400) + 0xDC00 # result += '\u' + [high, low].map { |x| x.to_s(16) }.join('\u').downcase end i += 12 next end end result += "\ufffd" i += 3 end result end end end end # https://gist.github.com/kreeger/4480326 # class Fixnum # def to_surrogate_pair # if self >= 0x10000 && self <= 0x10FFFF # high = ((self - 0x10000) / 0x400).floor + 0xD800 # low = ((self - 0x10000) % 0x400) + 0xDC00 # end # '\U' + [high, low].map { |x| x.to_s(16) }.join('\U').upcase # end # # end # # class String # def to_hex # self.gsub('\U000', '0x').to_i(16) # end # end # mdurl-rb-1.0.5/lib/mdurl-rb/cgi.rb0000644000175100017510000000202214123311515016774 0ustar vivekdebvivekdeb# Borrowed this from motion-support 0.2.6, as it's all we need. Don't want the # dependency #------------------------------------------------------------------------------ # This is a very small part of the CGI class, borrowed from the Rubinius sources class CGI @@accept_charset="UTF-8" unless defined?(@@accept_charset) # URL-encode a string. # url_encoded_string = CGI::escape("'Stop!' said Fred") # # => "%27Stop%21%27+said+Fred" def CGI::escape(string) string.gsub(/([^ a-zA-Z0-9_.-]+)/) do '%' + $1.unpack('H2' * $1.bytesize).join('%').upcase end.tr(' ', '+') end # URL-decode a string with encoding(optional). # string = CGI::unescape("%27Stop%21%27+said+Fred") # # => "'Stop!' said Fred" def CGI::unescape(string,encoding=@@accept_charset) str=string.tr('+', ' ').force_encoding(Encoding::ASCII_8BIT).gsub(/((?:%[0-9a-fA-F]{2})+)/) do [$1.delete('%')].pack('H*') end.force_encoding(encoding) str.valid_encoding? ? str : str.force_encoding(string.encoding) end end mdurl-rb-1.0.5/lib/mdurl-rb.rb0000644000175100017510000000055414123311515016242 0ustar vivekdebvivekdeb# encoding: utf-8 if defined?(Motion::Project::Config) lib_dir_path = File.dirname(File.expand_path(__FILE__)) Motion::Project::App.setup do |app| app.files.unshift(Dir.glob(File.join(lib_dir_path, "mdurl-rb/**/*.rb"))) end else require 'mdurl-rb/parse' require 'mdurl-rb/format' require 'mdurl-rb/encode' require 'mdurl-rb/decode' endmdurl-rb-1.0.5/README.md0000755000175100017510000000764614123311515014716 0ustar vivekdebvivekdeb# mdurl-rb [![Gem Version](https://badge.fury.io/rb/mdurl-rb.svg)](http://badge.fury.io/rb/mdurl-rb) [![Build Status](https://travis-ci.org/digitalmoksha/mdurl-rb.svg?branch=master)](https://travis-ci.org/digitalmoksha/mdurl-rb) This gem is a port of the [mdurl javascript package](https://github.com/markdown-it/mdurl) by Vitaly Puzrin and Alex Kocharin, that is used for the [markdown-it](https://github.com/markdown-it/markdown-it) package. Currently synced with mdurl 1.0.5 --- URL utilities for [motion-markdown-it](https://github.com/digitalmoksha/motion-markdown-it) parser, for both Ruby and RubyMotion ## API _As this gem was ported from the Javascript version, there may still be some mixture of Javascript terminology below'_ ### MDUrl::Encode.encode(str [, exclude, keepEncoded]) -> String Percent-encode a string, avoiding double encoding. Don't touch `/a-zA-Z0-9/` + excluded chars + `/%[a-fA-F0-9]{2}/` (if not disabled). Broken surrorates are replaced with `U+FFFD`. Params: - __str__ - input string. - __exclude__ - optional, `;/?:@&=+$,-_.!~*'()#`. Additional chars to keep intact (except `/a-zA-Z0-9/`). - __keepEncoded__ - optional, `true`. By default it skips already encoded sequences (`/%[a-fA-F0-9]{2}/`). If set to `false`, `%` will be encoded. ### MDUrl::Encode::DEFAULT_CHARACTERS, MDUrl::Encode::COMPONENT_CHARACTERS You can use these constants as second argument to `encode` function. - `DEFAULT_CHARACTERS` is the same exclude set as in the standard `encodeURI()` function - `COMPONENT_CHARACTERS` is the same exclude set as in the `encodeURIComponent()` function For example, `MDUrl::Encode.encode('something', MDUrl::Encode::COMPONENT_CHARACTERS, true)` is roughly the equivalent of the `encodeURIComponent()` function in Javascript (except `encode()` doesn't throw). ### MDUrl::Decode.decode(str [, exclude]) -> String Decode percent-encoded string. Invalid percent-encoded sequences (e.g. `%2G`) are left as is. Invalid UTF-8 characters are replaced with `U+FFFD`. Params: - __str__ - input string. - __exclude__ - set of characters to leave encoded, optional, `;/?:@&=+$,#`. ### MDUrl::Decode::DEFTAULT_CHARS, MDUrl::Decode::COMPONENT_CHARS You can use these constants as second argument to `decode` function. - `DEFTAULT_CHARS` is the same exclude set as in the standard `decodeURI()` function - `COMPONENT_CHARS` is the same exclude set as in the `decodeURIComponent()` function For example, `MDUrl::Decode.decode('something', MDUrl::Decode::DEFTAULT_CHARS)` has the same behavior as `decodeURI('something')` in javascript on a correctly encoded input. ### MDUrl::Url.parse(url, slashesDenoteHost) -> urlObs Parse url string. Similar to node's [url.parse](http://nodejs.org/api/url.html#url_url_parse_urlstr_parsequerystring_slashesdenotehost), but without any normalizations and query string parse. - __url__ - input url (string) - __slashesDenoteHost__ - if url starts with `//`, expect a hostname after it. Optional, `false`. Result (hash): - protocol - slashes - auth - port - hostname - hash - search - pathname Difference with node's `url`: 1. No leading slash in paths, e.g. in `url.parse('http://foo?bar')` pathname is ``, not `/` 2. Backslashes are not replaced with slashes, so `http:\\example.org\` is treated like a relative path 3. Trailing colon is treated like a part of the path, i.e. in `http://example.org:foo` pathname is `:foo` 4. Nothing is URL-encoded in the resulting object, (in joyent/node some chars in auth and paths are encoded) 5. `url.parse()` does not have `parseQueryString` argument 6. Removed extraneous result properties: `host`, `path`, `query`, etc., which can be constructed using other parts of the url. ### MDUrl::Format.format(urlObject) Format an object previously obtained with `.parse()` function. Similar to node's [url.format](http://nodejs.org/api/url.html#url_url_format_urlobj). ## License [MIT](https://github.com/markdown-it/mdurl/blob/master/LICENSE)