starscope 1.5.3 → 1.5.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,138 +2,140 @@ require 'rkelly'
2
2
  require 'babel/transpiler'
3
3
  require 'sourcemap'
4
4
 
5
- module Starscope::Lang
6
- module Javascript
7
- VERSION = 1
5
+ module Starscope
6
+ module Lang
7
+ module Javascript
8
+ VERSION = 1
8
9
 
9
- def self.match_file(name)
10
- name.end_with?('.js')
11
- end
10
+ def self.match_file(name)
11
+ name.end_with?('.js')
12
+ end
12
13
 
13
- def self.extract(path, contents, &block)
14
- return if path.end_with?('.min.js')
14
+ def self.extract(path, contents, &block)
15
+ return if path.end_with?('.min.js')
15
16
 
16
- transform = Babel::Transpiler.transform(contents,
17
- 'stage' => 0,
18
- 'blacklist' => ['validation.react'],
19
- 'externalHelpers' => true,
20
- 'compact' => false,
21
- 'sourceMaps' => true)
22
- map = SourceMap::Map.from_hash(transform['map'])
23
- ast = RKelly::Parser.new.parse(transform['code'])
24
- lines = contents.lines.to_a
17
+ transform = Babel::Transpiler.transform(contents,
18
+ 'stage' => 0,
19
+ 'blacklist' => ['validation.react'],
20
+ 'externalHelpers' => true,
21
+ 'compact' => false,
22
+ 'sourceMaps' => true)
23
+ map = SourceMap::Map.from_hash(transform['map'])
24
+ ast = RKelly::Parser.new.parse(transform['code'])
25
+ lines = contents.lines.to_a
25
26
 
26
- return unless ast
27
+ return unless ast
27
28
 
28
- found = extract_methods(ast, map, lines, &block)
29
+ found = extract_methods(ast, map, lines, &block)
29
30
 
30
- found = extract_var_decls(ast, map, lines, found, &block)
31
+ found = extract_var_decls(ast, map, lines, found, &block)
31
32
 
32
- extract_var_reads(ast, map, lines, found, &block)
33
- end
33
+ extract_var_reads(ast, map, lines, found, &block)
34
+ end
34
35
 
35
- def self.extract_methods(ast, map, lines, &block)
36
- found = {}
36
+ def self.extract_methods(ast, map, lines)
37
+ found = {}
37
38
 
38
- ast.each do |node|
39
- case node
40
- when RKelly::Nodes::FunctionExprNode, RKelly::Nodes::FunctionDeclNode
41
- line = find_line(node.range.from, map, lines, node.value)
42
- next unless line
39
+ ast.each do |node|
40
+ case node
41
+ when RKelly::Nodes::FunctionExprNode, RKelly::Nodes::FunctionDeclNode
42
+ line = find_line(node.range.from, map, lines, node.value)
43
+ next unless line
43
44
 
44
- type = :func
45
- type = :class if lines[line - 1].include?("class #{node.value}")
45
+ type = :func
46
+ type = :class if lines[line - 1].include?("class #{node.value}")
46
47
 
47
- yield :defs, node.value, line_no: line, type: type
48
- found[node.value] ||= Set.new
49
- found[node.value].add(line)
48
+ yield :defs, node.value, line_no: line, type: type
49
+ found[node.value] ||= Set.new
50
+ found[node.value].add(line)
50
51
 
51
- next if type == :class
52
+ next if type == :class
52
53
 
53
- mapping = map.bsearch(SourceMap::Offset.new(node.range.to.line, node.range.to.char))
54
- if lines[mapping.original.line - 1].include? '}'
55
- yield :end, '}', line_no: mapping.original.line, type: type
56
- else
57
- yield :end, '', line_no: mapping.original.line, type: type, col: mapping.original.column
58
- end
59
- when RKelly::Nodes::FunctionCallNode
60
- name = node_name(node.value)
61
- next unless name
54
+ mapping = map.bsearch(SourceMap::Offset.new(node.range.to.line, node.range.to.char))
55
+ if lines[mapping.original.line - 1].include? '}'
56
+ yield :end, '}', line_no: mapping.original.line, type: type
57
+ else
58
+ yield :end, '', line_no: mapping.original.line, type: type, col: mapping.original.column
59
+ end
60
+ when RKelly::Nodes::FunctionCallNode
61
+ name = node_name(node.value)
62
+ next unless name
62
63
 
63
- node = node.arguments.value[0] if name == 'require' && !node.value.is_a?(RKelly::Nodes::DotAccessorNode)
64
+ node = node.arguments.value[0] if name == 'require' && !node.value.is_a?(RKelly::Nodes::DotAccessorNode)
64
65
 
65
- line = find_line(node.range.from, map, lines, name)
66
- next unless line
66
+ line = find_line(node.range.from, map, lines, name)
67
+ next unless line
67
68
 
68
- found[name] ||= Set.new
69
- found[name].add(line)
69
+ found[name] ||= Set.new
70
+ found[name].add(line)
70
71
 
71
- if name == 'require' && node.is_a?(RKelly::Nodes::StringNode)
72
- yield :requires, node.value[1...-1], line_no: line
73
- else
74
- yield :calls, name, line_no: line
72
+ if name == 'require' && node.is_a?(RKelly::Nodes::StringNode)
73
+ yield :requires, node.value[1...-1], line_no: line
74
+ else
75
+ yield :calls, name, line_no: line
76
+ end
75
77
  end
76
78
  end
79
+
80
+ found
77
81
  end
78
82
 
79
- found
80
- end
83
+ def self.extract_var_decls(ast, map, lines, found)
84
+ ast.each do |node|
85
+ next unless node.is_a? RKelly::Nodes::VarDeclNode
81
86
 
82
- def self.extract_var_decls(ast, map, lines, found, &block)
83
- ast.each do |node|
84
- next unless node.is_a? RKelly::Nodes::VarDeclNode
87
+ line = find_line(node.range.from, map, lines, node.name)
88
+ next unless line
85
89
 
86
- line = find_line(node.range.from, map, lines, node.name)
87
- next unless line
90
+ if node.value.is_a?(RKelly::Nodes::AssignExprNode) &&
91
+ node.value.value.is_a?(RKelly::Nodes::FunctionCallNode) &&
92
+ node.value.value.value.is_a?(RKelly::Nodes::ResolveNode) &&
93
+ node.value.value.value.value == 'require'
94
+ found[node.name] ||= Set.new
95
+ found[node.name].add(line)
96
+ next
97
+ end
88
98
 
89
- if node.value.is_a?(RKelly::Nodes::AssignExprNode) &&
90
- node.value.value.is_a?(RKelly::Nodes::FunctionCallNode) &&
91
- node.value.value.value.is_a?(RKelly::Nodes::ResolveNode) &&
92
- node.value.value.value.value == 'require'
99
+ next if found[node.name] && found[node.name].include?(line)
100
+ yield :defs, node.name, line_no: line
93
101
  found[node.name] ||= Set.new
94
102
  found[node.name].add(line)
95
- next
96
103
  end
97
104
 
98
- next if found[node.name] && found[node.name].include?(line)
99
- yield :defs, node.name, line_no: line
100
- found[node.name] ||= Set.new
101
- found[node.name].add(line)
105
+ found
102
106
  end
103
107
 
104
- found
105
- end
106
-
107
- def self.extract_var_reads(ast, map, lines, found, &block)
108
- ast.each do |node|
109
- name = node_name(node)
110
- next unless name
108
+ def self.extract_var_reads(ast, map, lines, found)
109
+ ast.each do |node|
110
+ name = node_name(node)
111
+ next unless name
111
112
 
112
- line = find_line(node.range.from, map, lines, name)
113
- next unless line
113
+ line = find_line(node.range.from, map, lines, name)
114
+ next unless line
114
115
 
115
- next if found[name] && found[name].include?(line)
116
- yield :reads, name, line_no: line
116
+ next if found[name] && found[name].include?(line)
117
+ yield :reads, name, line_no: line
118
+ end
117
119
  end
118
- end
119
120
 
120
- def self.node_name(node)
121
- case node
122
- when RKelly::Nodes::DotAccessorNode
123
- node.accessor
124
- when RKelly::Nodes::ResolveNode
125
- node.value
121
+ def self.node_name(node)
122
+ case node
123
+ when RKelly::Nodes::DotAccessorNode
124
+ node.accessor
125
+ when RKelly::Nodes::ResolveNode
126
+ node.value
127
+ end
126
128
  end
127
- end
128
129
 
129
- def self.find_line(from, map, lines, name)
130
- mapping = map.bsearch(SourceMap::Offset.new(from.line, from.char))
131
- return unless mapping
130
+ def self.find_line(from, map, lines, name)
131
+ mapping = map.bsearch(SourceMap::Offset.new(from.line, from.char))
132
+ return unless mapping
132
133
 
133
- line = lines[mapping.original.line - 1]
134
- return unless line.include?(name) || (name == 'require' && line.include?('import'))
134
+ line = lines[mapping.original.line - 1]
135
+ return unless line.include?(name) || (name == 'require' && line.include?('import'))
135
136
 
136
- mapping.original.line
137
+ mapping.original.line
138
+ end
137
139
  end
138
140
  end
139
141
  end
@@ -1,111 +1,129 @@
1
1
  require 'parser/current'
2
2
 
3
- module Starscope::Lang
4
- module Ruby
5
- VERSION = 2
6
-
7
- def self.match_file(name)
8
- return true if name.end_with?('.rb', '.rake')
9
- File.open(name) do |f|
10
- head = f.read(2)
11
- return false if head.nil? || !head.start_with?('#!')
12
- return f.readline.include?('ruby')
3
+ module Starscope
4
+ module Lang
5
+ module Ruby
6
+ # This class exists solely to workaround/suppress issues from upstream's handling of invalid unicode.
7
+ # See https://github.com/whitequark/parser/issues/283; workaround borrowed from
8
+ # https://github.com/bbatsov/rubocop/commit/5e820eb5cfddf5e0f7efd2c0fa99e6b8a4c7b7e0
9
+ class Builder < Parser::Builders::Default
10
+ def string_value(token)
11
+ value(token)
12
+ end
13
13
  end
14
- end
15
-
16
- def self.extract(path, contents, &block)
17
- ast = Parser::CurrentRuby.parse(contents)
18
- extract_tree(ast, [], &block) unless ast.nil?
19
- end
20
14
 
21
- def self.extract_tree(tree, scope, &block)
22
- extract_node(tree, scope, &block)
15
+ VERSION = 2
23
16
 
24
- new_scope = []
25
- if [:class, :module].include? tree.type
26
- new_scope = scoped_name(tree.children[0], scope)
27
- scope += new_scope
17
+ def self.match_file(name)
18
+ return true if name.end_with?('.rb', '.rake')
19
+ File.open(name) do |f|
20
+ head = f.read(2)
21
+ return false if head.nil? || !head.start_with?('#!')
22
+ return f.readline.include?('ruby')
23
+ end
28
24
  end
29
25
 
30
- tree.children.each { |node| extract_tree(node, scope, &block) if node.is_a? AST::Node }
26
+ def self.extract(path, contents, &block)
27
+ buffer = Parser::Source::Buffer.new(path, 1)
28
+ buffer.source = contents.force_encoding(Encoding::UTF_8)
31
29
 
32
- scope.pop(new_scope.count)
33
- end
30
+ parser = Parser::CurrentRuby.new(Builder.new)
31
+ parser.diagnostics.ignore_warnings = true
32
+ parser.diagnostics.all_errors_are_fatal = false
34
33
 
35
- def self.extract_node(node, scope)
36
- loc = node.location
34
+ ast = parser.parse(buffer)
35
+ extract_tree(ast, [], &block) unless ast.nil?
36
+ end
37
37
 
38
- case node.type
39
- when :send
40
- name = scoped_name(node, scope)
41
- yield :calls, name, line_no: loc.line, col: loc.column
38
+ def self.extract_tree(tree, scope, &block)
39
+ extract_node(tree, scope, &block)
42
40
 
43
- if name.last =~ /\w+=$/
44
- name[-1] = name.last.to_s.chop.to_sym
45
- yield :assigns, name, line_no: loc.line, col: loc.column
46
- elsif node.children[0].nil? && node.children[1] == :require && node.children[2].type == :str
47
- yield :requires, node.children[2].children[0].split('/'),
48
- line_no: loc.line, col: loc.column
41
+ new_scope = []
42
+ if [:class, :module].include? tree.type
43
+ new_scope = scoped_name(tree.children[0], scope)
44
+ scope += new_scope
49
45
  end
50
46
 
51
- when :def
52
- yield :defs, scope + [node.children[0]],
53
- line_no: loc.line, type: :func, col: loc.name.column
54
- yield :end, :end, line_no: loc.end.line, type: :func, col: loc.end.column
55
-
56
- when :defs
57
- yield :defs, scope + [node.children[1]],
58
- line_no: loc.line, type: :func, col: loc.name.column
59
- yield :end, :end, line_no: loc.end.line, type: :func, col: loc.end.column
60
-
61
- when :module, :class
62
- yield :defs, scope + scoped_name(node.children[0], scope),
63
- line_no: loc.line, type: node.type, col: loc.name.column
64
- yield :end, :end, line_no: loc.end.line, type: node.type, col: loc.end.column
65
-
66
- when :casgn
67
- name = scoped_name(node, scope)
68
- yield :assigns, name, line_no: loc.line, col: loc.name.column
69
- yield :defs, name, line_no: loc.line, col: loc.name.column
70
-
71
- when :lvasgn, :ivasgn, :cvasgn, :gvasgn
72
- yield :assigns, scope + [node.children[0]], line_no: loc.line, col: loc.name.column
73
-
74
- when :const
75
- name = scoped_name(node, scope)
76
- yield :reads, name, line_no: loc.line, col: loc.name.column
77
-
78
- when :lvar, :ivar, :cvar, :gvar
79
- yield :reads, scope + [node.children[0]], line_no: loc.line, col: loc.name.column
80
-
81
- when :sym
82
- # handle `:foo` vs `foo: 1`
83
- col = if loc.begin
84
- loc.begin.column + 1
85
- else
86
- loc.expression.column
87
- end
88
- yield :sym, [node.children[0]], line_no: loc.line, col: col
47
+ tree.children.each { |node| extract_tree(node, scope, &block) if node.is_a? AST::Node }
48
+
49
+ scope.pop(new_scope.count)
50
+ end
51
+
52
+ def self.extract_node(node, scope)
53
+ loc = node.location
54
+
55
+ case node.type
56
+ when :send
57
+ name = scoped_name(node, scope)
58
+ yield :calls, name, line_no: loc.line, col: loc.column
59
+
60
+ if name.last =~ /\w+=$/
61
+ name[-1] = name.last.to_s.chop.to_sym
62
+ yield :assigns, name, line_no: loc.line, col: loc.column
63
+ elsif node.children[0].nil? && node.children[1] == :require && node.children[2].type == :str
64
+ yield :requires, node.children[2].children[0].split('/'),
65
+ line_no: loc.line, col: loc.column
66
+ end
67
+
68
+ when :def
69
+ yield :defs, scope + [node.children[0]],
70
+ line_no: loc.line, type: :func, col: loc.name.column
71
+ yield :end, :end, line_no: loc.end.line, type: :func, col: loc.end.column
72
+
73
+ when :defs
74
+ yield :defs, scope + [node.children[1]],
75
+ line_no: loc.line, type: :func, col: loc.name.column
76
+ yield :end, :end, line_no: loc.end.line, type: :func, col: loc.end.column
77
+
78
+ when :module, :class
79
+ yield :defs, scope + scoped_name(node.children[0], scope),
80
+ line_no: loc.line, type: node.type, col: loc.name.column
81
+ yield :end, :end, line_no: loc.end.line, type: node.type, col: loc.end.column
82
+
83
+ when :casgn
84
+ name = scoped_name(node, scope)
85
+ yield :assigns, name, line_no: loc.line, col: loc.name.column
86
+ yield :defs, name, line_no: loc.line, col: loc.name.column
87
+
88
+ when :lvasgn, :ivasgn, :cvasgn, :gvasgn
89
+ yield :assigns, scope + [node.children[0]], line_no: loc.line, col: loc.name.column
90
+
91
+ when :const
92
+ name = scoped_name(node, scope)
93
+ yield :reads, name, line_no: loc.line, col: loc.name.column
94
+
95
+ when :lvar, :ivar, :cvar, :gvar
96
+ yield :reads, scope + [node.children[0]], line_no: loc.line, col: loc.name.column
97
+
98
+ when :sym
99
+ # handle `:foo` vs `foo: 1`
100
+ col = if loc.begin
101
+ loc.begin.column + 1
102
+ else
103
+ loc.expression.column
104
+ end
105
+ yield :sym, [node.children[0]], line_no: loc.line, col: col
106
+ end
89
107
  end
90
- end
91
108
 
92
- def self.scoped_name(node, scope)
93
- if node.type == :block
94
- scoped_name(node.children[0], scope)
95
- elsif [:lvar, :ivar, :cvar, :gvar, :const, :send, :casgn].include? node.type
96
- if node.children[0].is_a? Symbol
97
- [node.children[0]]
98
- elsif node.children[0].is_a? AST::Node
99
- scoped_name(node.children[0], scope) << node.children[1]
100
- elsif node.children[0].nil?
101
- if node.type == :const
102
- [node.children[1]]
103
- else
104
- scope + [node.children[1]]
109
+ def self.scoped_name(node, scope)
110
+ if node.type == :block
111
+ scoped_name(node.children[0], scope)
112
+ elsif [:lvar, :ivar, :cvar, :gvar, :const, :send, :casgn].include? node.type
113
+ if node.children[0].is_a? Symbol
114
+ [node.children[0]]
115
+ elsif node.children[0].is_a? AST::Node
116
+ scoped_name(node.children[0], scope) << node.children[1]
117
+ elsif node.children[0].nil?
118
+ if node.type == :const
119
+ [node.children[1]]
120
+ else
121
+ scope + [node.children[1]]
122
+ end
105
123
  end
124
+ else
125
+ [node.type]
106
126
  end
107
- else
108
- [node.type]
109
127
  end
110
128
  end
111
129
  end