forked from instructure/canvas-lms
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrender_json_lint
executable file
·34 lines (30 loc) · 1.29 KB
/
render_json_lint
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
#!/usr/bin/env ruby
require 'ruby_parser'
def deep_inspect(expr)
return unless expr.is_a?(Sexp)
yield expr
expr.each{ |subexpr| deep_inspect(subexpr) { |x| yield x } }
end
def bad_to_json_in_render?(expr)
# "render json: value.to_json(args), ..." parses as
# s(:call, nil, :render, s(:hash, s(:lit, :json), s(:call, value, :to_json, args), ...))
# look for that structure, but skip if the value is a literal. known not to catch
# "render status: 200, json: value.to_json(args)"
# but that's ok for now
expr[0] == :call && expr[1] == nil && expr[2] == :render &&
expr[3].is_a?(Sexp) && expr[3].first == :hash &&
expr[3][1].is_a?(Sexp) && expr[3][1].first == :lit && expr[3][1].last == :json &&
expr[3][2].is_a?(Sexp) && expr[3][2].first == :call && expr[3][2][2] == :to_json &&
!(expr[3][2][1].is_a?(Sexp) && [:str, :lit, :true, :false, :nil].include?(expr[3][2][1].first))
end
errored = false
controllers = Dir.glob("app/controllers/*.rb") + Dir.glob("vendor/plugins/*/app/controllers/*.rb")
controllers.each do |file|
deep_inspect(RubyParser.new.parse(File.read(file))) do |expr|
if bad_to_json_in_render?(expr)
puts "ERROR (in #{file} near #{expr.line}): call to `to_json' on value for `render json'. Use `as_json' instead."
errored = true
end
end
end
exit 1 if errored