summaryrefslogtreecommitdiff
path: root/lib/tasks/frontend/routes.rake
blob: 50669f00cc42563635a47e9c46f4c3676382b5c4 (plain)
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
Route = Struct.new(:name, :path, :has_params?) do
  def <=> (other)
    self.name <=> other.name
  end
end

def placeholder_params_hash(params)
  Hash[params.zip(params.map { |param| "${params.#{param.to_s.camelize(:lower)}}" })]
end

class InternalRouteGenerator
  def self.path_for_route(route, params)
    path = route.format(placeholder_params_hash(params))
    path = path.gsub(/%7B(.+?)%7D/, '{\1}') # undo escaping of JavaScript placeholdes
    path.gsub(/\.\$\{params.format\}$/, '') # we favor ?format=
  end

  def self.all
    routes = Rails.application.routes.routes.named_routes
    routes.map do |name, route|
      params = route.parts
      Route.new("#{name}_path", self.path_for_route(route, params), !params.empty?)
    end
  end
end

class ApiRouteGenerator
  def self.path_for_route(route, params, api_version)
    values = placeholder_params_hash(params).merge(version: api_version)
    segments = route.path_segments_with_values(values).reject { |s| route.optional_segment?(s) }
    '/' + segments.join('/')
  end

  def self.all
    routes = Array(Grape::API.decorated_routes)
    routes.flat_map do |route|
      Array(route.route_options[:version]).map do |api_version|
        params = route.route_options[:params].keys
        name = route.path_helper_name({ version: api_version, format: route.extension })
        Route.new(name, self.path_for_route(route, params, api_version), !params.empty?)
      end
    end
  end
end

namespace :frontend do
  task :routes do
    def write_routes(file, routes)
      routes.each do |route|
        name = route.name.camelize(:lower)
        path = "${baseUrl}#{route.path}"
        if route.has_params?
          file.puts "export const #{name} = params => `#{path}`;"
        else
          file.puts "export const #{name} = () => `#{path}`;"
        end
      end
    end

    all_routes = (InternalRouteGenerator.all + ApiRouteGenerator.all).uniq { |route| route.name }.sort
    output_path = File.join(Rails.root, 'app', 'assets', 'javascripts', 'routes.js')
    File.open(output_path, 'w') do |file|
      file.puts '// This file was generated by bin/rake frontend:routes'
      file.puts "const baseUrl = gon.relative_url_root || '';"
      write_routes(file, all_routes)
    end
  end
end