starscope 1.4.1 → 1.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.rubocop.yml +0 -3
- data/.travis.yml +0 -1
- data/CHANGELOG.md +17 -1
- data/README.md +6 -6
- data/Rakefile +1 -1
- data/bin/starscope +20 -9
- data/doc/LANGUAGE_SUPPORT.md +2 -0
- data/doc/USER_GUIDE.md +17 -5
- data/lib/starscope/db.rb +18 -7
- data/lib/starscope/exportable.rb +4 -3
- data/lib/starscope/langs/erb.rb +4 -4
- data/lib/starscope/langs/go.rb +23 -23
- data/lib/starscope/langs/javascript.rb +114 -0
- data/lib/starscope/langs/ruby.rb +16 -18
- data/lib/starscope/output.rb +3 -3
- data/lib/starscope/version.rb +1 -1
- data/starscope.gemspec +11 -8
- data/test/fixtures/sample_javascript.js +117 -0
- data/test/fixtures/sample_ruby.rb +4 -4
- data/test/functional/starscope_test.rb +1 -1
- data/test/test_helper.rb +2 -1
- data/test/unit/db_test.rb +3 -3
- data/test/unit/exportable_test.rb +3 -3
- data/test/unit/fragment_extractor_test.rb +8 -8
- data/test/unit/langs/erb_test.rb +13 -13
- data/test/unit/langs/golang_test.rb +1 -1
- data/test/unit/langs/javascript_test.rb +68 -0
- data/test/unit/langs/ruby_test.rb +1 -1
- data/test/unit/output_test.rb +1 -1
- data/test/unit/queryable_test.rb +13 -13
- metadata +58 -26
- data/Gemfile.lock +0 -41
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'rkelly'
|
2
|
+
require 'babel/transpiler'
|
3
|
+
require 'sourcemap'
|
4
|
+
|
5
|
+
module Starscope::Lang
|
6
|
+
module Javascript
|
7
|
+
VERSION = 0
|
8
|
+
|
9
|
+
def self.match_file(name)
|
10
|
+
name.end_with?('.js')
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.extract(path, contents, &block)
|
14
|
+
transform = Babel::Transpiler.transform(contents,
|
15
|
+
'stage' => 0,
|
16
|
+
'blacklist' => ['validation.react'],
|
17
|
+
'externalHelpers' => true,
|
18
|
+
'compact' => false,
|
19
|
+
'sourceMaps' => true)
|
20
|
+
map = SourceMap::Map.from_hash(transform['map'])
|
21
|
+
ast = RKelly::Parser.new.parse(transform['code'])
|
22
|
+
lines = contents.lines.to_a
|
23
|
+
|
24
|
+
return unless ast
|
25
|
+
|
26
|
+
found = extract_methods(ast, map, lines, &block)
|
27
|
+
|
28
|
+
found = extract_var_decls(ast, map, lines, found, &block)
|
29
|
+
|
30
|
+
extract_var_reads(ast, map, lines, found, &block)
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.extract_methods(ast, map, lines, &block)
|
34
|
+
found = {}
|
35
|
+
|
36
|
+
ast.each do |node|
|
37
|
+
case node
|
38
|
+
when RKelly::Nodes::FunctionExprNode, RKelly::Nodes::FunctionDeclNode
|
39
|
+
line = find_line(node.range.from, map, lines, node.value)
|
40
|
+
next unless line
|
41
|
+
|
42
|
+
type = :func
|
43
|
+
type = :class if lines[line - 1].include?("class #{node.value}")
|
44
|
+
|
45
|
+
yield :defs, node.value, line_no: line, type: type
|
46
|
+
found[node.value] ||= Set.new
|
47
|
+
found[node.value].add(line)
|
48
|
+
|
49
|
+
next if type == :class
|
50
|
+
|
51
|
+
mapping = map.bsearch(SourceMap::Offset.new(node.range.to.line, node.range.to.char))
|
52
|
+
yield :end, :'}', line_no: mapping.original.line, type: type
|
53
|
+
when RKelly::Nodes::FunctionCallNode
|
54
|
+
name = node_name(node.value)
|
55
|
+
next unless name
|
56
|
+
|
57
|
+
line = find_line(node.range.from, map, lines, name)
|
58
|
+
next unless line
|
59
|
+
|
60
|
+
yield :calls, name, line_no: line
|
61
|
+
found[name] ||= Set.new
|
62
|
+
found[name].add(line)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
found
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.extract_var_decls(ast, map, lines, found, &block)
|
70
|
+
ast.each do |node|
|
71
|
+
next unless node.is_a? RKelly::Nodes::VarDeclNode
|
72
|
+
|
73
|
+
line = find_line(node.range.from, map, lines, node.name)
|
74
|
+
next unless line
|
75
|
+
|
76
|
+
next if found[node.name] && found[node.name].include?(line)
|
77
|
+
yield :defs, node.name, line_no: line
|
78
|
+
found[node.name] ||= Set.new
|
79
|
+
found[node.name].add(line)
|
80
|
+
end
|
81
|
+
|
82
|
+
found
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.extract_var_reads(ast, map, lines, found, &block)
|
86
|
+
ast.each do |node|
|
87
|
+
name = node_name(node)
|
88
|
+
next unless name
|
89
|
+
|
90
|
+
line = find_line(node.range.from, map, lines, name)
|
91
|
+
next unless line
|
92
|
+
|
93
|
+
next if found[name] && found[name].include?(line)
|
94
|
+
yield :reads, name, line_no: line
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def self.node_name(node)
|
99
|
+
case node
|
100
|
+
when RKelly::Nodes::DotAccessorNode
|
101
|
+
node.accessor
|
102
|
+
when RKelly::Nodes::ResolveNode
|
103
|
+
node.value
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def self.find_line(from, map, lines, name)
|
108
|
+
mapping = map.bsearch(SourceMap::Offset.new(from.line, from.char))
|
109
|
+
return unless mapping
|
110
|
+
return unless lines[mapping.original.line - 1].include? name
|
111
|
+
mapping.original.line
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
data/lib/starscope/langs/ruby.rb
CHANGED
@@ -18,8 +18,6 @@ module Starscope::Lang
|
|
18
18
|
extract_tree(ast, [], &block) unless ast.nil?
|
19
19
|
end
|
20
20
|
|
21
|
-
private
|
22
|
-
|
23
21
|
def self.extract_tree(tree, scope, &block)
|
24
22
|
extract_node(tree, scope, &block)
|
25
23
|
|
@@ -40,45 +38,45 @@ module Starscope::Lang
|
|
40
38
|
case node.type
|
41
39
|
when :send
|
42
40
|
name = scoped_name(node, scope)
|
43
|
-
yield :calls, name, :
|
41
|
+
yield :calls, name, line_no: loc.line, col: loc.column
|
44
42
|
|
45
|
-
if name.last
|
43
|
+
if name.last =~ /\w+=$/
|
46
44
|
name[-1] = name.last.to_s.chop.to_sym
|
47
|
-
yield :assigns, name, :
|
45
|
+
yield :assigns, name, line_no: loc.line, col: loc.column
|
48
46
|
elsif node.children[0].nil? && node.children[1] == :require && node.children[2].type == :str
|
49
47
|
yield :requires, node.children[2].children[0].split('/'),
|
50
|
-
:
|
48
|
+
line_no: loc.line, col: loc.column
|
51
49
|
end
|
52
50
|
|
53
51
|
when :def
|
54
52
|
yield :defs, scope + [node.children[0]],
|
55
|
-
:
|
56
|
-
yield :end, :end, :
|
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
|
57
55
|
|
58
56
|
when :defs
|
59
57
|
yield :defs, scope + [node.children[1]],
|
60
|
-
:
|
61
|
-
yield :end, :end, :
|
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
|
62
60
|
|
63
61
|
when :module, :class
|
64
62
|
yield :defs, scope + scoped_name(node.children[0], scope),
|
65
|
-
:
|
66
|
-
yield :end, :end, :
|
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
|
67
65
|
|
68
66
|
when :casgn
|
69
67
|
name = scoped_name(node, scope)
|
70
|
-
yield :assigns, name, :
|
71
|
-
yield :defs, name, :
|
68
|
+
yield :assigns, name, line_no: loc.line, col: loc.name.column
|
69
|
+
yield :defs, name, line_no: loc.line, col: loc.name.column
|
72
70
|
|
73
71
|
when :lvasgn, :ivasgn, :cvasgn, :gvasgn
|
74
|
-
yield :assigns, scope + [node.children[0]], :
|
72
|
+
yield :assigns, scope + [node.children[0]], line_no: loc.line, col: loc.name.column
|
75
73
|
|
76
74
|
when :const
|
77
75
|
name = scoped_name(node, scope)
|
78
|
-
yield :reads, name, :
|
76
|
+
yield :reads, name, line_no: loc.line, col: loc.name.column
|
79
77
|
|
80
78
|
when :lvar, :ivar, :cvar, :gvar
|
81
|
-
yield :reads, scope + [node.children[0]], :
|
79
|
+
yield :reads, scope + [node.children[0]], line_no: loc.line, col: loc.name.column
|
82
80
|
|
83
81
|
when :sym
|
84
82
|
# handle `:foo` vs `foo: 1`
|
@@ -87,7 +85,7 @@ module Starscope::Lang
|
|
87
85
|
else
|
88
86
|
loc.expression.column
|
89
87
|
end
|
90
|
-
yield :sym, [node.children[0]], :
|
88
|
+
yield :sym, [node.children[0]], line_no: loc.line, col: col
|
91
89
|
end
|
92
90
|
end
|
93
91
|
|
data/lib/starscope/output.rb
CHANGED
@@ -11,9 +11,9 @@ class Starscope::Output
|
|
11
11
|
|
12
12
|
def new_pbar(title, num_items)
|
13
13
|
return if @level == :quiet
|
14
|
-
@pbar = ProgressBar.create(:
|
15
|
-
:
|
16
|
-
:
|
14
|
+
@pbar = ProgressBar.create(title: title, total: num_items,
|
15
|
+
format: PBAR_FORMAT, length: 80,
|
16
|
+
out: @out)
|
17
17
|
end
|
18
18
|
|
19
19
|
def inc_pbar
|
data/lib/starscope/version.rb
CHANGED
data/starscope.gemspec
CHANGED
@@ -5,7 +5,7 @@ Gem::Specification.new do |gem|
|
|
5
5
|
gem.version = Starscope::VERSION
|
6
6
|
gem.summary = 'Smart code search and indexing'
|
7
7
|
gem.description = <<-EOF
|
8
|
-
Starscope is a code indexer, search and navigation tool for Ruby and
|
8
|
+
Starscope is a code indexer, search and navigation tool for Ruby, Golang, and JavaScript.
|
9
9
|
Inspired by the extremely popular Ctags and Cscope utilities, Starscope can
|
10
10
|
answer a lot of questions about a lot of code.
|
11
11
|
EOF
|
@@ -17,15 +17,18 @@ Gem::Specification.new do |gem|
|
|
17
17
|
gem.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
18
18
|
gem.test_files = `git ls-files -- test/*`.split("\n")
|
19
19
|
gem.require_paths = ['lib']
|
20
|
-
gem.required_ruby_version = '>= 1.
|
20
|
+
gem.required_ruby_version = '>= 1.9.3'
|
21
21
|
|
22
22
|
gem.add_dependency 'oj', '~> 2.9'
|
23
23
|
gem.add_dependency 'parser', '~> 2.2.2'
|
24
24
|
gem.add_dependency 'ruby-progressbar', '~> 1.5'
|
25
|
-
gem.add_dependency '
|
26
|
-
gem.
|
27
|
-
gem.
|
28
|
-
|
29
|
-
gem.add_development_dependency '
|
30
|
-
gem.add_development_dependency '
|
25
|
+
gem.add_dependency 'rkelly-remix', '~> 0.0.7'
|
26
|
+
gem.add_dependency 'babel-transpiler', '~> 0.7'
|
27
|
+
gem.add_dependency 'sourcemap', '~> 0.1'
|
28
|
+
|
29
|
+
gem.add_development_dependency 'bundler', '~> 1.7'
|
30
|
+
gem.add_development_dependency 'rake', '~> 10.4'
|
31
|
+
gem.add_development_dependency 'pry', '~> 0.10.1'
|
32
|
+
gem.add_development_dependency 'minitest', '~> 5.8'
|
33
|
+
gem.add_development_dependency 'mocha', '~> 1.1'
|
31
34
|
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
/* @flow */
|
2
|
+
|
3
|
+
import React from 'react-native';
|
4
|
+
|
5
|
+
var {
|
6
|
+
Component,
|
7
|
+
StyleSheet,
|
8
|
+
} = React;
|
9
|
+
|
10
|
+
var {NavigationBar} = Navigator;
|
11
|
+
|
12
|
+
var styles = StyleSheet.create({
|
13
|
+
navigatorBar: {
|
14
|
+
height: NavigationBar.Styles.General.NavBarHeight,
|
15
|
+
justifyContent: 'center',
|
16
|
+
alignItems: 'center',
|
17
|
+
},
|
18
|
+
});
|
19
|
+
|
20
|
+
var func1 = () => {
|
21
|
+
return 1;
|
22
|
+
};
|
23
|
+
|
24
|
+
function foo() {
|
25
|
+
return bar;
|
26
|
+
}
|
27
|
+
|
28
|
+
StatusBarIOS.setStyle(1);
|
29
|
+
Router.routes = routes;
|
30
|
+
|
31
|
+
class MyStat {
|
32
|
+
static myStatFunc(
|
33
|
+
title
|
34
|
+
): void {
|
35
|
+
}
|
36
|
+
}
|
37
|
+
|
38
|
+
var NavigatorRouteMapper = {
|
39
|
+
LeftButton({route}, navigator, index) {
|
40
|
+
if (!index) { return null; } // Nothing below in stack.
|
41
|
+
|
42
|
+
return (
|
43
|
+
<TouchableOpacity onPress={() => navigator.pop()}>
|
44
|
+
<Text style={{color: 'white', fontSize: 12, marginLeft: 1}}>‹</Text>
|
45
|
+
</TouchableOpacity>
|
46
|
+
);
|
47
|
+
},
|
48
|
+
|
49
|
+
RightButton() {
|
50
|
+
return null;
|
51
|
+
},
|
52
|
+
};
|
53
|
+
|
54
|
+
class Navigation extends Component {
|
55
|
+
constructor(props) {
|
56
|
+
super(props);
|
57
|
+
this.state = {key: 'foo', selectedTab: 'foo'};
|
58
|
+
func1();
|
59
|
+
|
60
|
+
}
|
61
|
+
|
62
|
+
_tabItem(routeName: string, params: Object, badgeCount?: number) : PropTypes.element {
|
63
|
+
var route = routes[routeName];
|
64
|
+
|
65
|
+
var onTabPress = () => {
|
66
|
+
if (this.state.selectedTab === routeName) {
|
67
|
+
if (route === Router.currentRoute) {
|
68
|
+
Router.navigator._currentQueryFetcherRoot.fetchData();
|
69
|
+
} else {
|
70
|
+
Router.popToTop();
|
71
|
+
}
|
72
|
+
} else {
|
73
|
+
this.setState({selectedTab: routeName});
|
74
|
+
}
|
75
|
+
};
|
76
|
+
|
77
|
+
return (
|
78
|
+
<TabBarIOS.Item
|
79
|
+
badge={badgeCount}
|
80
|
+
selected={this.state.selectedTab === routeName}
|
81
|
+
onPress={onTabPress}
|
82
|
+
>
|
83
|
+
<Navigator
|
84
|
+
ref={::this._setCurrentNavigator}
|
85
|
+
navigationBar={
|
86
|
+
<NavigationBar routeMapper={NavigatorRouteMapper} style={{backgroundColor: Branding.pink}} />
|
87
|
+
}
|
88
|
+
/>
|
89
|
+
|
90
|
+
</TabBarIOS.Item>
|
91
|
+
);
|
92
|
+
}
|
93
|
+
|
94
|
+
_setCurrentNavigator(nav) {
|
95
|
+
Router.navigator = nav;
|
96
|
+
}
|
97
|
+
|
98
|
+
_renderTabScene({route, params}, nav) {
|
99
|
+
var setRef = (ref) => {
|
100
|
+
nav._currentQueryFetcherRoot = ref;
|
101
|
+
};
|
102
|
+
|
103
|
+
return <QueryFetcherRoot ref={setRef} component={route.component} route={route} params={params} />;
|
104
|
+
}
|
105
|
+
|
106
|
+
render() {
|
107
|
+
return (
|
108
|
+
<TabBarIOS tintColor={Branding.yellow} barTintColor={Branding.green}>
|
109
|
+
{this._tabItem('foo', {})}
|
110
|
+
{this._tabItem('bar', {})}
|
111
|
+
{this._tabItem('baz', {})}
|
112
|
+
</TabBarIOS>
|
113
|
+
);
|
114
|
+
}
|
115
|
+
}
|
116
|
+
|
117
|
+
export default Navigation;
|
@@ -26,7 +26,7 @@ class Starscope::DB
|
|
26
26
|
if format == DB_FORMAT
|
27
27
|
@paths = Oj.load(stream.gets)
|
28
28
|
@files = Oj.load(stream.gets)
|
29
|
-
@tables = Oj.load(stream.gets, :
|
29
|
+
@tables = Oj.load(stream.gets, symbol_keys: true)
|
30
30
|
elsif format <= 2
|
31
31
|
# Old format (pre-json), so read the directories segment then rebuild
|
32
32
|
len = stream.gets.to_i
|
@@ -59,7 +59,7 @@ class Starscope::DB
|
|
59
59
|
files = paths.map { |p| self.class.files_from_path(p) }.flatten
|
60
60
|
return if files.empty?
|
61
61
|
if @progress
|
62
|
-
pbar = ProgressBar.create(:
|
62
|
+
pbar = ProgressBar.create(title: 'Building', total: files.length, format: PBAR_FORMAT, length: 80)
|
63
63
|
end
|
64
64
|
files.each do |f|
|
65
65
|
add_file(f)
|
@@ -70,7 +70,7 @@ class Starscope::DB
|
|
70
70
|
def update
|
71
71
|
new_files = (@paths.map { |p| self.class.files_from_path(p) }.flatten) - @files.keys
|
72
72
|
if @progress
|
73
|
-
pbar = ProgressBar.create(:
|
73
|
+
pbar = ProgressBar.create(title: 'Updating', total: new_files.length + @files.length, format: PBAR_FORMAT, length: 80)
|
74
74
|
end
|
75
75
|
changed = @files.keys.map do |f|
|
76
76
|
changed = update_file(f)
|
@@ -114,7 +114,7 @@ class Starscope::DB
|
|
114
114
|
if entry[:line_no]
|
115
115
|
tmpdb[entry[:file]] ||= {}
|
116
116
|
tmpdb[entry[:file]][entry[:line_no]] ||= []
|
117
|
-
tmpdb[entry[:file]][entry[:line_no]] << { :
|
117
|
+
tmpdb[entry[:file]][entry[:line_no]] << { tbl: tbl, key: key, entry: entry }
|
118
118
|
end
|
119
119
|
end
|
120
120
|
end
|
data/test/test_helper.rb
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
require 'minitest/autorun'
|
2
2
|
require 'minitest/pride'
|
3
3
|
require 'mocha/mini_test'
|
4
|
-
|
4
|
+
require_relative '../lib/starscope'
|
5
5
|
|
6
6
|
FIXTURES = 'test/fixtures'
|
7
7
|
|
8
8
|
GOLANG_SAMPLE = "#{FIXTURES}/sample_golang.go"
|
9
|
+
JAVASCRIPT_EXAMPLE = "#{FIXTURES}/sample_javascript.js"
|
9
10
|
RUBY_SAMPLE = "#{FIXTURES}/sample_ruby.rb"
|
10
11
|
ERB_SAMPLE = "#{FIXTURES}/sample_erb.erb"
|
11
12
|
EMPTY_FILE = "#{FIXTURES}/empty"
|
data/test/unit/db_test.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
require_relative '../test_helper'
|
2
2
|
require 'tempfile'
|
3
3
|
|
4
4
|
describe Starscope::DB do
|
@@ -144,7 +144,7 @@ describe Starscope::DB do
|
|
144
144
|
it 'must run queries on multiple tables' do
|
145
145
|
@db.add_paths([FIXTURES])
|
146
146
|
ret = @db.query([:calls, :defs], 'foo')
|
147
|
-
ret.length.must_equal
|
147
|
+
ret.length.must_equal 4
|
148
148
|
ret.first[:name].last.must_equal :foo
|
149
149
|
end
|
150
150
|
|
@@ -161,7 +161,7 @@ describe Starscope::DB do
|
|
161
161
|
it 'must store extractor metadata returned from the `extract` call' do
|
162
162
|
extractor = mock('extractor')
|
163
163
|
extractor.expects(:match_file).with(GOLANG_SAMPLE).returns(true)
|
164
|
-
extractor.expects(:extract).with(GOLANG_SAMPLE, File.read(GOLANG_SAMPLE)).returns(:
|
164
|
+
extractor.expects(:extract).with(GOLANG_SAMPLE, File.read(GOLANG_SAMPLE)).returns(a: 1)
|
165
165
|
extractor.expects(:name).returns('Foo')
|
166
166
|
EXTRACTORS.stubs(:each).yields(extractor)
|
167
167
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
require_relative '../test_helper'
|
2
2
|
|
3
3
|
describe Starscope::Exportable do
|
4
4
|
before do
|
@@ -10,14 +10,14 @@ describe Starscope::Exportable do
|
|
10
10
|
it 'must export to ctags' do
|
11
11
|
@db.export_to(:ctags, @buf)
|
12
12
|
@buf.rewind
|
13
|
-
lines = @buf.
|
13
|
+
lines = @buf.each_line.to_a
|
14
14
|
lines.must_include "NoTableError\t#{FIXTURES}/sample_ruby.rb\t/^ class NoTableError < StandardError; end$/;\"\tkind:c\tlanguage:Ruby\n"
|
15
15
|
end
|
16
16
|
|
17
17
|
it 'must export to cscope' do
|
18
18
|
@db.export_to(:cscope, @buf)
|
19
19
|
@buf.rewind
|
20
|
-
lines = @buf.
|
20
|
+
lines = @buf.each_line.to_a
|
21
21
|
|
22
22
|
lines.must_include "\t@#{FIXTURES}/sample_golang.go\n"
|
23
23
|
lines.must_include "\tgSunday\n"
|