starscope 1.4.1 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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"
|