File: uri_utils.rb

package info (click to toggle)
ruby-sprockets 4.2.1-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 2,964 kB
  • sloc: ruby: 13,014; javascript: 157; makefile: 4
file content (191 lines) | stat: -rw-r--r-- 5,339 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# frozen_string_literal: true
require 'uri'

module Sprockets
  # Internal: Asset URI related parsing utilities. Mixed into Environment.
  #
  # An Asset URI identifies the compiled Asset result. It shares the file:
  # scheme and requires an absolute path.
  #
  # Other query parameters
  #
  # type - String output content type. Otherwise assumed from file extension.
  #        This maybe different than the extension if the asset is transformed
  #        from one content type to another. For an example .coffee -> .js.
  #
  # id - Unique fingerprint of the entire asset and all its metadata. Assets
  #      will only have the same id if they serialize to an identical value.
  #
  # pipeline - String name of pipeline.
  #
  module URIUtils
    extend self

    # Internal: Parse URI into component parts.
    #
    # uri - String uri
    #
    # Returns Array of components.
    def split_uri(uri)
      URI.split(uri)
    end

    # Internal: Join URI component parts into String.
    #
    # Returns String.
    def join_uri(scheme, userinfo, host, port, registry, path, opaque, query, fragment)
      URI::Generic.new(scheme, userinfo, host, port, registry, path, opaque, query, fragment).to_s
    end

    # Internal: Parse file: URI into component parts.
    #
    # uri - String uri
    #
    # Returns [scheme, host, path, query].
    def split_file_uri(uri)
      scheme, _, host, _, _, path, _, query, _ = URI.split(uri)

      path = URI::Generic::DEFAULT_PARSER.unescape(path)
      path.force_encoding(Encoding::UTF_8)

      # Hack for parsing Windows "/C:/Users/IEUser" paths
      if File::ALT_SEPARATOR && path[2] == ':'
        path = path[1..-1]
      end

      [scheme, host || '', path, query]
    end

    # Internal: Join file: URI component parts into String.
    #
    # Returns String.
    def join_file_uri(scheme, host, path, query)
      str = +"#{scheme}://"
      str << host if host
      path = "/#{path}" unless path.start_with?("/".freeze)
      str << URI::Generic::DEFAULT_PARSER.escape(path)
      str << "?#{query}" if query
      str
    end

    # Internal: Check if String is a valid Asset URI.
    #
    # str - Possible String asset URI.
    #
    # Returns true or false.
    def valid_asset_uri?(str)
      # Quick prefix check before attempting a full parse
      str.start_with?("file://".freeze) && parse_asset_uri(str) ? true : false
    rescue URI::InvalidURIError
      false
    end

    # Internal: Parse Asset URI.
    #
    # Examples
    #
    #   parse("file:///tmp/js/application.coffee?type=application/javascript")
    #   # => "/tmp/js/application.coffee", {type: "application/javascript"}
    #
    # uri - String asset URI
    #
    # Returns String path and Hash of symbolized parameters.
    def parse_asset_uri(uri)
      scheme, _, path, query = split_file_uri(uri)

      unless scheme == 'file'
        raise URI::InvalidURIError, "expected file:// scheme: #{uri}"
      end

      return path, parse_uri_query_params(query)
    end

    # Internal: Build Asset URI.
    #
    # Examples
    #
    #   build("/tmp/js/application.coffee", type: "application/javascript")
    #   # => "file:///tmp/js/application.coffee?type=application/javascript"
    #
    # path   - String file path
    # params - Hash of optional parameters
    #
    # Returns String URI.
    def build_asset_uri(path, params = {})
      join_file_uri("file", nil, path, encode_uri_query_params(params))
    end

    # Internal: Parse file-digest dependency URI.
    #
    # Examples
    #
    #   parse("file-digest:/tmp/js/application.js")
    #   # => "/tmp/js/application.js"
    #
    # uri - String file-digest URI
    #
    # Returns String path.
    def parse_file_digest_uri(uri)
      scheme, _, path, _ = split_file_uri(uri)

      unless scheme == 'file-digest'.freeze
        raise URI::InvalidURIError, "expected file-digest scheme: #{uri}"
      end

      path
    end

    # Internal: Build file-digest dependency URI.
    #
    # Examples
    #
    #   build("/tmp/js/application.js")
    #   # => "file-digest:/tmp/js/application.js"
    #
    # path - String file path
    #
    # Returns String URI.
    def build_file_digest_uri(path)
      join_file_uri('file-digest'.freeze, nil, path, nil)
    end

    # Internal: Serialize hash of params into query string.
    #
    # params - Hash of params to serialize
    #
    # Returns String query or nil if empty.
    def encode_uri_query_params(params)
      query = []

      params.each do |key, value|
        case value
        when Integer
          query << "#{key}=#{value}"
        when String, Symbol
          query << "#{key}=#{URI::Generic::DEFAULT_PARSER.escape(value.to_s)}"
        when TrueClass
          query << "#{key}"
        when FalseClass, NilClass
        else
          raise TypeError, "unexpected type: #{value.class}"
        end
      end

      "#{query.join('&'.freeze)}" if query.any?
    end

    # Internal: Parse query string into hash of params
    #
    # query - String query string
    #
    # Return Hash of params.
    def parse_uri_query_params(query)
      query.to_s.split('&'.freeze).reduce({}) do |h, p|
        k, v = p.split('='.freeze, 2)
        v = URI::Generic::DEFAULT_PARSER.unescape(v) if v
        h[k.to_sym] = v || true
        h
      end
    end
  end
end