deep-cover 0.1.1

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.
Files changed (99) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +13 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +10 -0
  5. data/CODE_OF_CONDUCT.md +74 -0
  6. data/Gemfile +8 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +127 -0
  9. data/Rakefile +6 -0
  10. data/bin/console +14 -0
  11. data/bin/cov +43 -0
  12. data/bin/gemcov +8 -0
  13. data/bin/selfcov +21 -0
  14. data/bin/setup +8 -0
  15. data/bin/testall +88 -0
  16. data/deep_cover.gemspec +44 -0
  17. data/exe/deep-cover +6 -0
  18. data/future_read_me.md +108 -0
  19. data/lib/deep-cover.rb +1 -0
  20. data/lib/deep_cover.rb +11 -0
  21. data/lib/deep_cover/analyser.rb +24 -0
  22. data/lib/deep_cover/analyser/base.rb +51 -0
  23. data/lib/deep_cover/analyser/branch.rb +20 -0
  24. data/lib/deep_cover/analyser/covered_code_source.rb +31 -0
  25. data/lib/deep_cover/analyser/function.rb +12 -0
  26. data/lib/deep_cover/analyser/ignore_uncovered.rb +19 -0
  27. data/lib/deep_cover/analyser/node.rb +11 -0
  28. data/lib/deep_cover/analyser/per_char.rb +20 -0
  29. data/lib/deep_cover/analyser/per_line.rb +23 -0
  30. data/lib/deep_cover/analyser/statement.rb +31 -0
  31. data/lib/deep_cover/analyser/subset.rb +24 -0
  32. data/lib/deep_cover/auto_run.rb +49 -0
  33. data/lib/deep_cover/autoload_tracker.rb +75 -0
  34. data/lib/deep_cover/backports.rb +9 -0
  35. data/lib/deep_cover/base.rb +55 -0
  36. data/lib/deep_cover/builtin_takeover.rb +2 -0
  37. data/lib/deep_cover/cli/debugger.rb +93 -0
  38. data/lib/deep_cover/cli/deep_cover.rb +49 -0
  39. data/lib/deep_cover/cli/instrumented_clone_reporter.rb +105 -0
  40. data/lib/deep_cover/config.rb +52 -0
  41. data/lib/deep_cover/core_ext/autoload_overrides.rb +40 -0
  42. data/lib/deep_cover/core_ext/coverage_replacement.rb +26 -0
  43. data/lib/deep_cover/core_ext/load_overrides.rb +24 -0
  44. data/lib/deep_cover/core_ext/require_overrides.rb +36 -0
  45. data/lib/deep_cover/coverage.rb +198 -0
  46. data/lib/deep_cover/covered_code.rb +138 -0
  47. data/lib/deep_cover/custom_requirer.rb +93 -0
  48. data/lib/deep_cover/node.rb +8 -0
  49. data/lib/deep_cover/node/arguments.rb +50 -0
  50. data/lib/deep_cover/node/assignments.rb +250 -0
  51. data/lib/deep_cover/node/base.rb +99 -0
  52. data/lib/deep_cover/node/begin.rb +25 -0
  53. data/lib/deep_cover/node/block.rb +53 -0
  54. data/lib/deep_cover/node/boolean.rb +22 -0
  55. data/lib/deep_cover/node/branch.rb +28 -0
  56. data/lib/deep_cover/node/case.rb +94 -0
  57. data/lib/deep_cover/node/collections.rb +21 -0
  58. data/lib/deep_cover/node/const.rb +10 -0
  59. data/lib/deep_cover/node/def.rb +38 -0
  60. data/lib/deep_cover/node/empty_body.rb +21 -0
  61. data/lib/deep_cover/node/exceptions.rb +74 -0
  62. data/lib/deep_cover/node/if.rb +36 -0
  63. data/lib/deep_cover/node/keywords.rb +84 -0
  64. data/lib/deep_cover/node/literals.rb +77 -0
  65. data/lib/deep_cover/node/loops.rb +72 -0
  66. data/lib/deep_cover/node/mixin/can_augment_children.rb +65 -0
  67. data/lib/deep_cover/node/mixin/check_completion.rb +16 -0
  68. data/lib/deep_cover/node/mixin/child_can_be_empty.rb +25 -0
  69. data/lib/deep_cover/node/mixin/executed_after_children.rb +13 -0
  70. data/lib/deep_cover/node/mixin/execution_location.rb +56 -0
  71. data/lib/deep_cover/node/mixin/flow_accounting.rb +63 -0
  72. data/lib/deep_cover/node/mixin/has_child.rb +138 -0
  73. data/lib/deep_cover/node/mixin/has_child_handler.rb +73 -0
  74. data/lib/deep_cover/node/mixin/has_tracker.rb +44 -0
  75. data/lib/deep_cover/node/mixin/is_statement.rb +18 -0
  76. data/lib/deep_cover/node/mixin/rewriting.rb +32 -0
  77. data/lib/deep_cover/node/mixin/wrapper.rb +13 -0
  78. data/lib/deep_cover/node/module.rb +64 -0
  79. data/lib/deep_cover/node/root.rb +18 -0
  80. data/lib/deep_cover/node/send.rb +83 -0
  81. data/lib/deep_cover/node/splat.rb +13 -0
  82. data/lib/deep_cover/node/variables.rb +14 -0
  83. data/lib/deep_cover/parser_ext/range.rb +40 -0
  84. data/lib/deep_cover/reporter.rb +6 -0
  85. data/lib/deep_cover/reporter/istanbul.rb +151 -0
  86. data/lib/deep_cover/tools.rb +18 -0
  87. data/lib/deep_cover/tools/builtin_coverage.rb +50 -0
  88. data/lib/deep_cover/tools/camelize.rb +8 -0
  89. data/lib/deep_cover/tools/dump_covered_code.rb +32 -0
  90. data/lib/deep_cover/tools/execute_sample.rb +23 -0
  91. data/lib/deep_cover/tools/format.rb +16 -0
  92. data/lib/deep_cover/tools/format_char_cover.rb +18 -0
  93. data/lib/deep_cover/tools/format_generated_code.rb +25 -0
  94. data/lib/deep_cover/tools/number_lines.rb +18 -0
  95. data/lib/deep_cover/tools/our_coverage.rb +9 -0
  96. data/lib/deep_cover/tools/require_relative_dir.rb +10 -0
  97. data/lib/deep_cover/tools/silence_warnings.rb +15 -0
  98. data/lib/deep_cover/version.rb +3 -0
  99. metadata +326 -0
@@ -0,0 +1,73 @@
1
+ module DeepCover
2
+ module Node::Mixin
3
+ module HasChildHandler
4
+ def self.included(base)
5
+ base.extend ClassMethods
6
+ end
7
+
8
+ def call_child_handler template, child, child_name = nil
9
+ child_name ||= self.class.child_index_to_name(child.index, children.size) rescue binding.pry
10
+ method_name = template % {name: child_name}
11
+ if respond_to?(method_name)
12
+ args = [child, child_name]
13
+ arity = method(method_name).arity
14
+ if arity >= 0
15
+ args = args[0...arity]
16
+ end
17
+ answer = send(method_name, *args)
18
+ end
19
+ answer
20
+ end
21
+ private :call_child_handler
22
+
23
+ module ClassMethods
24
+ def has_child_handler(template)
25
+ child_method_name = template % {name: 'child'}
26
+ action = template.gsub(/_%{name}/, '').gsub(/%{name}_/, '')
27
+ const_name = "#{Tools.camelize(action)}Handler"
28
+ class_eval <<-end_eval, __FILE__, __LINE__
29
+ module #{const_name} # module RewriteHandler
30
+ module ClassMethods # module ClassMethods
31
+ def has_child(#{action}: nil, **h) # def has_child(rewrite: nil, **h)
32
+ name, _types = h.first # name, _types = h.first
33
+ define_child_handler(#{template.inspect}, # define_child_handler('rewrite_%{child}',
34
+ name, #{action}) # name, rewrite)
35
+ super(**h) # super(**h)
36
+ end # end
37
+ end # end
38
+
39
+ def #{child_method_name}(child, name = nil) # def rewrite_child(child, name = nil)
40
+ call_child_handler(#{template.inspect}, child, # call_child_handler('rewrite_%{child}', child,
41
+ name) || super # name) || super
42
+ end # end
43
+ end # end
44
+ include #{const_name} # include RewriteHandler
45
+ singleton_class.prepend #{const_name}::ClassMethods # singleton_class.prepend RewriteHandler::ClassMethods
46
+ end_eval
47
+ end
48
+
49
+ def define_child_handler(template, name, action)
50
+ method_name = template % {name: name}
51
+ case action
52
+ when nil
53
+ # Nothing to do
54
+ when Symbol
55
+ define_method(method_name) do |*args|
56
+ arity = method(action).arity
57
+ if arity < 0
58
+ send(action, *args)
59
+ else
60
+ send(action, *args[0...arity])
61
+ end
62
+ end
63
+ when Proc
64
+ define_method(method_name, &action)
65
+ else
66
+ define_method(method_name) {|*| action }
67
+ end
68
+ end
69
+ private :define_child_handler
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,44 @@
1
+ module DeepCover
2
+ module Node::Mixin
3
+ module HasTracker
4
+ def self.included(base)
5
+ base.extend ClassMethods
6
+ setup_constants(base)
7
+ end
8
+
9
+ def self.setup_constants(base)
10
+ base.const_set :TRACKERS, {}
11
+ end
12
+
13
+ def initialize(*)
14
+ @tracker_offset = covered_code.allocate_trackers(self.class::TRACKERS.size).begin
15
+ super
16
+ end
17
+
18
+ def tracker_sources
19
+ self.class::TRACKERS.map do |name, _|
20
+ [:"#{name}_tracker", send(:"#{name}_tracker_source")]
21
+ end.to_h
22
+ end
23
+
24
+ module ClassMethods
25
+ def inherited(base)
26
+ super
27
+ HasTracker.setup_constants(base)
28
+ end
29
+
30
+ def has_tracker(name)
31
+ i = self::TRACKERS[name] = self::TRACKERS.size
32
+ class_eval <<-end_eval, __FILE__, __LINE__ + 1
33
+ def #{name}_tracker_source
34
+ covered_code.tracker_source(@tracker_offset + #{i})
35
+ end
36
+ def #{name}_tracker_hits
37
+ covered_code.tracker_hits(@tracker_offset + #{i})
38
+ end
39
+ end_eval
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,18 @@
1
+ module DeepCover
2
+ module Node::Mixin
3
+ module IsStatement
4
+ def self.included(base)
5
+ base.has_child_handler('is_%{name}_statement')
6
+ end
7
+
8
+ def is_statement
9
+ parent.is_child_statement(self)
10
+ end
11
+
12
+ # Default child rewriting rule
13
+ def is_child_statement(child, name=nil)
14
+ :if_incompatible
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,32 @@
1
+ module DeepCover
2
+ module Node::Mixin
3
+ module Rewriting
4
+ def self.included(base)
5
+ base.has_child_handler('rewrite_%{name}')
6
+ end
7
+
8
+ # Code to add before and after the node for covering purposes
9
+ def rewrite
10
+ end
11
+
12
+ # Default child rewriting rule
13
+ def rewrite_child(child, name=nil)
14
+ end
15
+
16
+ def resolve_rewrite(rule, context)
17
+ rule ||= '%{node}'
18
+ sources = context.tracker_sources
19
+ rule.split('%{node}').map{|s| s % {local: covered_code.local_var, **sources} }
20
+ end
21
+
22
+ def rewrite_prefix_suffix
23
+ parent_prefix, parent_suffix = resolve_rewrite(parent.rewrite_child(self), parent)
24
+ prefix, suffix = resolve_rewrite(rewrite, self)
25
+ [
26
+ "#{parent_prefix}#{prefix}",
27
+ "#{suffix}#{parent_suffix}"
28
+ ]
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,13 @@
1
+ module DeepCover
2
+ module Node::Mixin
3
+ module Wrapper
4
+ def initialize(base_node, **kwargs)
5
+ super(base_node, base_children: [base_node], **kwargs)
6
+ end
7
+
8
+ def executed_loc_keys
9
+ []
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,64 @@
1
+ require_relative 'const'
2
+
3
+ module DeepCover
4
+ class Node
5
+ class ModuleName < Node
6
+ has_child scope: [Node, nil]
7
+ has_child const_name: Symbol
8
+
9
+ def flow_completion_count
10
+ parent.execution_count
11
+ end
12
+
13
+ def execution_count
14
+ if scope
15
+ scope.flow_completion_count
16
+ else
17
+ super
18
+ end
19
+ end
20
+ end
21
+
22
+ class Module < Node
23
+ check_completion
24
+ has_tracker :body_entry
25
+ has_child const: {const: ModuleName}
26
+ has_child body: Node,
27
+ can_be_empty: -> { base_node.loc.end.begin },
28
+ rewrite: '%{body_entry_tracker};%{local}=nil;%{node}',
29
+ is_statement: true,
30
+ flow_entry_count: :body_entry_tracker_hits
31
+ executed_loc_keys :keyword
32
+
33
+ def execution_count
34
+ body_entry_tracker_hits
35
+ end
36
+ end
37
+
38
+ class Class < Node
39
+ check_completion
40
+ has_tracker :body_entry
41
+ has_child const: {const: ModuleName}
42
+ has_child inherit: [Node, nil] # TODO
43
+ has_child body: Node,
44
+ can_be_empty: -> { base_node.loc.end.begin },
45
+ rewrite: '%{body_entry_tracker};%{node}',
46
+ is_statement: true,
47
+ flow_entry_count: :body_entry_tracker_hits
48
+ executed_loc_keys :keyword
49
+
50
+ def execution_count
51
+ body_entry_tracker_hits
52
+ end
53
+ end
54
+
55
+ # class << foo
56
+ class Sclass < Node
57
+ has_child object: Node
58
+ has_child body: Node,
59
+ can_be_empty: -> { base_node.loc.end.begin },
60
+ is_statement: true
61
+ # TODO
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,18 @@
1
+ module DeepCover
2
+ class Node::Root < Node
3
+ has_tracker :root
4
+ has_child main: Node,
5
+ can_be_empty: -> { ::Parser::Source::Range.new(covered_code.buffer, 0, 0) },
6
+ is_statement: true,
7
+ rewrite: -> {
8
+ "#{covered_code.trackers_setup_source};%{root_tracker};%{local}=nil;%{node}"
9
+ }
10
+ attr_reader :covered_code
11
+ alias_method :flow_entry_count, :root_tracker_hits
12
+
13
+ def initialize(child_ast, covered_code)
14
+ @covered_code = covered_code
15
+ super(nil, parent: nil, base_children: [child_ast])
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,83 @@
1
+ require_relative 'literals'
2
+
3
+ module DeepCover
4
+ class Node
5
+ class MethodName < Node
6
+ has_child name: Symbol
7
+
8
+ def initialize(name, parent: raise, **kwargs)
9
+ super(parent, **kwargs, parent: parent, base_children: [name])
10
+ end
11
+
12
+ def loc_hash
13
+ # Expression is used in the rewriting
14
+ # if selector_end is present, then this won't be needed
15
+ {expression: parent.loc_hash[:selector_begin]}
16
+ end
17
+
18
+ def executable?
19
+ false
20
+ end
21
+ end
22
+
23
+ class Send < Node
24
+ check_completion
25
+ has_child receiver: [Node, nil]
26
+ has_child method_name_wrapper: {Symbol => MethodName}, rewrite: :add_opening_parentheses
27
+ has_extra_children arguments: Node, rewrite: :add_closing_parentheses
28
+ executed_loc_keys :dot, :selector_begin, :selector_end, :operator
29
+
30
+ def method_name
31
+ method_name_wrapper.name
32
+ end
33
+
34
+ def loc_hash
35
+ base = super
36
+ hash = { expression: base[:expression], begin: base[:begin], end: base[:end], dot: base[:dot]}
37
+ selector = base[:selector]
38
+
39
+ if [:[], :[]=].include?(method_name)
40
+ hash[:selector_begin] = selector.resize(1)
41
+ hash[:selector_end] = Parser::Source::Range.new(selector.source_buffer, selector.end_pos - 1, selector.end_pos)
42
+ else
43
+ hash[:selector_begin] = base[:selector]
44
+ end
45
+
46
+ hash
47
+ end
48
+
49
+ # Only need to add them to deal with ambiguous cases where a method is hidden by a local. Ex:
50
+ # raise TypeError, 'hello' #=> Works
51
+ # raise (TypeError), 'hello' #=> Simplification of what DeepCover generates, still works
52
+ # raise = 1; raise TypeError, 'hello' #=> works
53
+ # raise = 1; raise (TypeError), 'hello' #=> syntax error.
54
+ # raise = 1; raise((TypeError), 'hello'0 #=> works
55
+ def add_parentheses?
56
+ return if arguments.empty?
57
+ # No ambiguity if there is a receiver
58
+ return if receiver
59
+ # Already has parentheses
60
+ return if self.loc_hash[:begin]
61
+ true
62
+ end
63
+
64
+ def add_opening_parentheses
65
+ return unless add_parentheses?
66
+ "%{node}("
67
+ end
68
+
69
+ def add_closing_parentheses(child)
70
+ return unless add_parentheses?
71
+ return unless child.index == children.size - 1
72
+ "%{node})"
73
+ end
74
+ end
75
+
76
+ class MatchWithLvasgn < Node
77
+ check_completion
78
+ has_child receiver: Regexp
79
+ has_child compare_to: Node
80
+ # TODO: test
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,13 @@
1
+ module DeepCover
2
+ class Node
3
+ class Splat < Node
4
+ check_completion inner: '[%{node}]', outer: '*%{node}'
5
+ has_child receiver: Node
6
+ end
7
+
8
+ class Kwsplat < Node
9
+ check_completion inner: '{%{node}}', outer: '**%{node}'
10
+ has_child receiver: Node
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,14 @@
1
+ module DeepCover
2
+ class Node
3
+ class Variable < Node
4
+ has_child var_name: Symbol
5
+ end
6
+ Ivar = Lvar = Cvar = Gvar = BackRef = Variable
7
+
8
+ # $1
9
+ class NthRef < Node
10
+ has_child n: Integer
11
+ # TODO
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,40 @@
1
+ class Parser::Source::Range
2
+ def with(begin_pos: @begin_pos, end_pos: @end_pos)
3
+ Parser::Source::Range.new(@source_buffer, begin_pos, end_pos)
4
+ end
5
+
6
+ # Similar to `end`, but is just after the current Range
7
+ def succ
8
+ with begin_pos: @end_pos+1, end_pos: @end_pos+1
9
+ end
10
+
11
+ # (1...10).split(2...3, 6...8) => [1...2, 3...6, 7...10]
12
+ # Assumes inner_ranges are exclusive, and included in self
13
+ def split(*inner_ranges)
14
+ inner_ranges.sort_by!(&:begin_pos)
15
+ [self.begin, *inner_ranges, self.end]
16
+ .each_cons(2)
17
+ .map{|i, j| with(begin_pos: i.end_pos, end_pos: j.begin_pos)}
18
+ .reject(&:empty?)
19
+ end
20
+
21
+ def lstrip(pattern = /\s*/)
22
+ if (match = /^#{pattern}/.match(source))
23
+ with(begin_pos: @begin_pos + match[0].length)
24
+ else
25
+ self
26
+ end
27
+ end
28
+
29
+ def rstrip(pattern = /\s*/)
30
+ if (match = /#{pattern}$/.match(source))
31
+ with(end_pos: @end_pos - match[0].length)
32
+ else
33
+ self
34
+ end
35
+ end
36
+
37
+ def strip(pattern = /\s*/)
38
+ lstrip(pattern).rstrip(pattern)
39
+ end
40
+ end
@@ -0,0 +1,6 @@
1
+ module DeepCover
2
+ module Reporter
3
+ end
4
+ require_relative 'node'
5
+ require_relative_dir 'reporter'
6
+ end
@@ -0,0 +1,151 @@
1
+ require 'json'
2
+
3
+ module DeepCover
4
+ module Reporter
5
+ class Istanbul < Struct.new(:covered_code, :options)
6
+ # Converters has no dependency on the including class.
7
+ module Converters
8
+ def convert_range(range)
9
+ { start: {
10
+ line: range.line,
11
+ column: range.column,
12
+ },
13
+ end: {
14
+ line: range.last_line,
15
+ column: range.last_column-1, # Our ranges are exclusive, Istanbul's are inclusive
16
+ },
17
+ }
18
+ end
19
+
20
+ # [:a, :b, :c] => {'1': :a, '2': :b, '3': :c}
21
+ def convert_list(list)
22
+ list.map.with_index{ |val, i| [i.succ.to_s, val] }.to_h
23
+ end
24
+
25
+ def convert_def(node)
26
+ ends_at = node.signature.loc_hash[:end] || node.loc_hash[:name]
27
+ decl = node.loc_hash[:keyword].with(end_pos: ends_at.end_pos)
28
+ _convert_function(node, node.method_name, decl)
29
+ end
30
+
31
+ def convert_block(node)
32
+ decl = node.loc_hash[:begin]
33
+ if (args = node.args.expression)
34
+ decl = decl.join(args) rescue binding.pry
35
+ end
36
+ _convert_function(node, '(block)', decl)
37
+ end
38
+
39
+ def convert_function(node)
40
+ if node.is_a?(Node::Block)
41
+ convert_block(node)
42
+ else
43
+ convert_def(node)
44
+ end
45
+ end
46
+
47
+ def convert_branch(node, branches = node.branches)
48
+ # Currently, nyc seems to outputs the same location over and over...
49
+ loc = convert_range(node.expression)
50
+ {
51
+ loc: loc,
52
+ type: node.type,
53
+ line: node.expression.line,
54
+ locations: branches.map{|n| loc}
55
+ }
56
+ end
57
+
58
+ private
59
+ def _convert_function(node, name, decl)
60
+ loc = node.body ? node.body.expression : decl.end
61
+ {
62
+ name: name,
63
+ line: node.expression.line,
64
+ decl: convert_range(decl),
65
+ loc: convert_range(loc),
66
+ }
67
+ end
68
+ end
69
+ include Converters
70
+
71
+ def node_analyser
72
+ @node_analyser ||= Analyser::Node.new(covered_code, **options)
73
+ end
74
+
75
+ def node_runs
76
+ @node_runs ||= node_analyser.results
77
+ end
78
+
79
+ def functions
80
+ @functions ||= Analyser::Function.new(node_analyser, **options).results
81
+ end
82
+
83
+ def statements
84
+ @statements ||= Analyser::Statement.new(node_analyser, **options).results
85
+ end
86
+
87
+ def branches
88
+ @branches ||= Analyser::Branch.new(node_analyser, **options).results
89
+ end
90
+
91
+ def branch_map
92
+ branches.map do |node, branches_runs|
93
+ convert_branch(node, branches_runs.keys)
94
+ end
95
+ end
96
+
97
+ # Istanbul doesn't understand how to ignore a branch...
98
+ def zero_to_something(values)
99
+ values.map{|v| v || 1}
100
+ end
101
+
102
+ def branch_runs
103
+ branches.values.map{|r| zero_to_something(r.values) }
104
+ end
105
+
106
+ def statement_map
107
+ statements.keys.map{ |range| convert_range(range) }
108
+ end
109
+
110
+ def statement_runs
111
+ statements.values
112
+ end
113
+
114
+ def function_map
115
+ functions.keys.map{|n| convert_function(n) }
116
+ end
117
+
118
+ def function_runs
119
+ functions.values
120
+ end
121
+
122
+ def data
123
+ {
124
+ statementMap: statement_map ,
125
+ s: statement_runs,
126
+ fnMap: function_map ,
127
+ f: function_runs ,
128
+ branchMap: branch_map ,
129
+ b: branch_runs ,
130
+ }
131
+ end
132
+
133
+ def convert
134
+ { covered_code.name => {
135
+ path: covered_code.path,
136
+ **data.transform_values{|l| convert_list(l)},
137
+ } }
138
+ end
139
+
140
+ def report
141
+ convert.to_json
142
+ end
143
+
144
+ class << self
145
+ def available?
146
+ `nyc --version` >= '11.' rescue false
147
+ end
148
+ end
149
+ end
150
+ end
151
+ end