spoom 1.1.11 → 1.1.12
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/Gemfile +1 -0
- data/README.md +6 -0
- data/Rakefile +1 -0
- data/lib/spoom/cli/bump.rb +11 -7
- data/lib/spoom/cli/coverage.rb +11 -7
- data/lib/spoom/cli/helper.rb +5 -4
- data/lib/spoom/cli/lsp.rb +2 -1
- data/lib/spoom/cli/run.rb +16 -6
- data/lib/spoom/cli.rb +6 -4
- data/lib/spoom/context.rb +219 -0
- data/lib/spoom/coverage/d3/base.rb +12 -8
- data/lib/spoom/coverage/d3/circle_map.rb +40 -37
- data/lib/spoom/coverage/d3/pie.rb +30 -26
- data/lib/spoom/coverage/d3/timeline.rb +86 -82
- data/lib/spoom/coverage/d3.rb +72 -70
- data/lib/spoom/coverage/report.rb +6 -6
- data/lib/spoom/coverage/snapshot.rb +40 -33
- data/lib/spoom/coverage.rb +84 -81
- data/lib/spoom/file_tree.rb +2 -0
- data/lib/spoom/git.rb +107 -97
- data/lib/spoom/printer.rb +4 -0
- data/lib/spoom/sorbet/errors.rb +29 -11
- data/lib/spoom/sorbet/lsp/base.rb +1 -1
- data/lib/spoom/sorbet/lsp/errors.rb +23 -17
- data/lib/spoom/sorbet/lsp/structures.rb +85 -54
- data/lib/spoom/sorbet/lsp.rb +71 -63
- data/lib/spoom/sorbet/metrics.rb +18 -16
- data/lib/spoom/sorbet/sigils.rb +59 -54
- data/lib/spoom/sorbet.rb +11 -8
- data/lib/spoom/timeline.rb +1 -0
- data/lib/spoom/version.rb +1 -1
- data/lib/spoom.rb +43 -25
- metadata +20 -20
- data/lib/spoom/test_helpers/project.rb +0 -138
data/lib/spoom/coverage.rb
CHANGED
@@ -9,94 +9,97 @@ require "date"
|
|
9
9
|
|
10
10
|
module Spoom
|
11
11
|
module Coverage
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
12
|
+
class << self
|
13
|
+
extend T::Sig
|
14
|
+
|
15
|
+
sig { params(path: String, rbi: T::Boolean, sorbet_bin: T.nilable(String)).returns(Snapshot) }
|
16
|
+
def snapshot(path: ".", rbi: true, sorbet_bin: nil)
|
17
|
+
config = sorbet_config(path: path)
|
18
|
+
config.allowed_extensions.push(".rb", ".rbi") if config.allowed_extensions.empty?
|
19
|
+
|
20
|
+
new_config = config.copy
|
21
|
+
new_config.allowed_extensions.reject! { |ext| !rbi && ext == ".rbi" }
|
22
|
+
|
23
|
+
metrics = Spoom::Sorbet.srb_metrics(
|
24
|
+
"--no-config",
|
25
|
+
"--no-error-sections",
|
26
|
+
"--no-error-count",
|
27
|
+
"--isolate-error-code=0",
|
28
|
+
new_config.options_string,
|
29
|
+
path: path,
|
30
|
+
capture_err: true,
|
31
|
+
sorbet_bin: sorbet_bin
|
32
|
+
)
|
33
|
+
|
34
|
+
snapshot = Snapshot.new
|
35
|
+
return snapshot unless metrics
|
36
|
+
|
37
|
+
sha = Spoom::Git.last_commit(path: path)
|
38
|
+
snapshot.commit_sha = sha
|
39
|
+
snapshot.commit_timestamp = Spoom::Git.commit_timestamp(sha, path: path).to_i if sha
|
40
|
+
|
41
|
+
snapshot.files = metrics.fetch("types.input.files", 0)
|
42
|
+
snapshot.modules = metrics.fetch("types.input.modules.total", 0)
|
43
|
+
snapshot.classes = metrics.fetch("types.input.classes.total", 0)
|
44
|
+
snapshot.singleton_classes = metrics.fetch("types.input.singleton_classes.total", 0)
|
45
|
+
snapshot.methods_with_sig = metrics.fetch("types.sig.count", 0)
|
46
|
+
snapshot.methods_without_sig = metrics.fetch("types.input.methods.total", 0) - snapshot.methods_with_sig
|
47
|
+
snapshot.calls_typed = metrics.fetch("types.input.sends.typed", 0)
|
48
|
+
snapshot.calls_untyped = metrics.fetch("types.input.sends.total", 0) - snapshot.calls_typed
|
49
|
+
|
50
|
+
snapshot.duration += metrics.fetch("run.utilization.system_time.us", 0)
|
51
|
+
snapshot.duration += metrics.fetch("run.utilization.user_time.us", 0)
|
52
|
+
|
53
|
+
Snapshot::STRICTNESSES.each do |strictness|
|
54
|
+
next unless metrics.key?("types.input.files.sigil.#{strictness}")
|
55
|
+
|
56
|
+
snapshot.sigils[strictness] = T.must(metrics["types.input.files.sigil.#{strictness}"])
|
57
|
+
end
|
58
|
+
|
59
|
+
snapshot.version_static = Spoom::Sorbet.version_from_gemfile_lock(gem: "sorbet-static", path: path)
|
60
|
+
snapshot.version_runtime = Spoom::Sorbet.version_from_gemfile_lock(gem: "sorbet-runtime", path: path)
|
61
|
+
|
62
|
+
files = Spoom::Sorbet.srb_files(new_config, path: path)
|
63
|
+
snapshot.rbi_files = files.count { |file| file.end_with?(".rbi") }
|
64
|
+
|
65
|
+
snapshot
|
55
66
|
end
|
56
67
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
Report.new(
|
72
|
-
project_name: File.basename(File.expand_path(path)),
|
73
|
-
palette: palette,
|
74
|
-
snapshots: snapshots,
|
75
|
-
sigils_tree: sigils_tree(path: path),
|
76
|
-
sorbet_intro_commit: intro_commit,
|
77
|
-
sorbet_intro_date: intro_date,
|
78
|
-
)
|
79
|
-
end
|
68
|
+
sig { params(snapshots: T::Array[Snapshot], palette: D3::ColorPalette, path: String).returns(Report) }
|
69
|
+
def report(snapshots, palette:, path: ".")
|
70
|
+
intro_commit = Git.sorbet_intro_commit(path: path)
|
71
|
+
intro_date = intro_commit ? Git.commit_time(intro_commit, path: path) : nil
|
72
|
+
|
73
|
+
Report.new(
|
74
|
+
project_name: File.basename(File.expand_path(path)),
|
75
|
+
palette: palette,
|
76
|
+
snapshots: snapshots,
|
77
|
+
sigils_tree: sigils_tree(path: path),
|
78
|
+
sorbet_intro_commit: intro_commit,
|
79
|
+
sorbet_intro_date: intro_date,
|
80
|
+
)
|
81
|
+
end
|
80
82
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
83
|
+
sig { params(path: String).returns(Sorbet::Config) }
|
84
|
+
def sorbet_config(path: ".")
|
85
|
+
Sorbet::Config.parse_file("#{path}/#{Spoom::Sorbet::CONFIG_PATH}")
|
86
|
+
end
|
85
87
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
88
|
+
sig { params(path: String).returns(FileTree) }
|
89
|
+
def sigils_tree(path: ".")
|
90
|
+
config = sorbet_config(path: path)
|
91
|
+
files = Sorbet.srb_files(config, path: path)
|
90
92
|
|
91
|
-
|
92
|
-
|
93
|
-
|
93
|
+
extensions = config.allowed_extensions
|
94
|
+
extensions = [".rb"] if extensions.empty?
|
95
|
+
extensions -= [".rbi"]
|
94
96
|
|
95
|
-
|
96
|
-
|
97
|
-
|
97
|
+
pattern = /\.(#{Regexp.union(extensions.map { |ext| ext[1..-1] })})$/
|
98
|
+
files.select! { |file| file =~ pattern }
|
99
|
+
files.reject! { |file| file =~ %r{/test/} }
|
98
100
|
|
99
|
-
|
101
|
+
FileTree.new(files, strip_prefix: path)
|
102
|
+
end
|
100
103
|
end
|
101
104
|
end
|
102
105
|
end
|
data/lib/spoom/file_tree.rb
CHANGED
@@ -33,6 +33,7 @@ module Spoom
|
|
33
33
|
if path.empty? || parts.size == 1
|
34
34
|
return @roots[path] ||= Node.new(parent: nil, name: path)
|
35
35
|
end
|
36
|
+
|
36
37
|
parent_path = T.must(parts[0...-1]).join("/")
|
37
38
|
parent = add_path(parent_path)
|
38
39
|
name = T.must(parts.last)
|
@@ -105,6 +106,7 @@ module Spoom
|
|
105
106
|
def path
|
106
107
|
parent = self.parent
|
107
108
|
return name unless parent
|
109
|
+
|
108
110
|
"#{parent.path}/#{name}"
|
109
111
|
end
|
110
112
|
end
|
data/lib/spoom/git.rb
CHANGED
@@ -6,119 +6,129 @@ require "time"
|
|
6
6
|
module Spoom
|
7
7
|
# Execute git commands
|
8
8
|
module Git
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
9
|
+
class << self
|
10
|
+
extend T::Sig
|
11
|
+
|
12
|
+
# Execute a `command`
|
13
|
+
sig { params(command: String, arg: String, path: String).returns(ExecResult) }
|
14
|
+
def exec(command, *arg, path: ".")
|
15
|
+
return ExecResult.new(
|
16
|
+
out: "",
|
17
|
+
err: "Error: `#{path}` is not a directory.",
|
18
|
+
status: false,
|
19
|
+
exit_code: 1
|
20
|
+
) unless File.directory?(path)
|
21
|
+
|
22
|
+
T.unsafe(Open3).popen3(command, *arg, chdir: path) do |_, stdout, stderr, thread|
|
23
|
+
status = T.cast(thread.value, Process::Status)
|
24
|
+
ExecResult.new(
|
25
|
+
out: stdout.read,
|
26
|
+
err: stderr.read,
|
27
|
+
status: T.must(status.success?),
|
28
|
+
exit_code: T.must(status.exitstatus)
|
29
|
+
)
|
30
|
+
end
|
29
31
|
end
|
30
|
-
end
|
31
32
|
|
32
|
-
|
33
|
+
# Git commands
|
33
34
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
35
|
+
sig { params(arg: String, path: String).returns(ExecResult) }
|
36
|
+
def checkout(*arg, path: ".")
|
37
|
+
exec("git checkout -q #{arg.join(" ")}", path: path)
|
38
|
+
end
|
38
39
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
40
|
+
sig { params(arg: String, path: String).returns(ExecResult) }
|
41
|
+
def diff(*arg, path: ".")
|
42
|
+
exec("git diff #{arg.join(" ")}", path: path)
|
43
|
+
end
|
43
44
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
45
|
+
sig { params(arg: String, path: String).returns(ExecResult) }
|
46
|
+
def log(*arg, path: ".")
|
47
|
+
exec("git log #{arg.join(" ")}", path: path)
|
48
|
+
end
|
48
49
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
50
|
+
sig { params(arg: String, path: String).returns(ExecResult) }
|
51
|
+
def rev_parse(*arg, path: ".")
|
52
|
+
exec("git rev-parse --short #{arg.join(" ")}", path: path)
|
53
|
+
end
|
53
54
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
55
|
+
sig { params(arg: String, path: String).returns(ExecResult) }
|
56
|
+
def show(*arg, path: ".")
|
57
|
+
exec("git show #{arg.join(" ")}", path: path)
|
58
|
+
end
|
58
59
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
result.out.strip
|
64
|
-
end
|
60
|
+
sig { params(path: String).returns(T.nilable(String)) }
|
61
|
+
def current_branch(path: ".")
|
62
|
+
result = exec("git branch --show-current", path: path)
|
63
|
+
return nil unless result.status
|
65
64
|
|
66
|
-
|
65
|
+
result.out.strip
|
66
|
+
end
|
67
67
|
|
68
|
-
|
69
|
-
sig { params(sha: String, path: String).returns(T.nilable(Integer)) }
|
70
|
-
def self.commit_timestamp(sha, path: ".")
|
71
|
-
result = show("--no-notes --no-patch --pretty=%at #{sha}", path: path)
|
72
|
-
return nil unless result.status
|
73
|
-
result.out.strip.to_i
|
74
|
-
end
|
68
|
+
# Utils
|
75
69
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
epoch_to_time(timestamp.to_s)
|
82
|
-
end
|
70
|
+
# Get the commit epoch timestamp for a `sha`
|
71
|
+
sig { params(sha: String, path: String).returns(T.nilable(Integer)) }
|
72
|
+
def commit_timestamp(sha, path: ".")
|
73
|
+
result = show("--no-notes --no-patch --pretty=%at #{sha}", path: path)
|
74
|
+
return nil unless result.status
|
83
75
|
|
84
|
-
|
85
|
-
|
86
|
-
def self.last_commit(path: ".")
|
87
|
-
result = rev_parse("HEAD", path: path)
|
88
|
-
return nil unless result.status
|
89
|
-
result.out.strip
|
90
|
-
end
|
76
|
+
result.out.strip.to_i
|
77
|
+
end
|
91
78
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
79
|
+
# Get the commit Time for a `sha`
|
80
|
+
sig { params(sha: String, path: String).returns(T.nilable(Time)) }
|
81
|
+
def commit_time(sha, path: ".")
|
82
|
+
timestamp = commit_timestamp(sha, path: path)
|
83
|
+
return nil unless timestamp
|
97
84
|
|
98
|
-
|
99
|
-
|
100
|
-
def self.workdir_clean?(path: ".")
|
101
|
-
diff("HEAD", path: path).out.empty?
|
102
|
-
end
|
85
|
+
epoch_to_time(timestamp.to_s)
|
86
|
+
end
|
103
87
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
out = result.out.strip
|
110
|
-
return nil if out.empty?
|
111
|
-
out
|
112
|
-
end
|
88
|
+
# Get the last commit sha
|
89
|
+
sig { params(path: String).returns(T.nilable(String)) }
|
90
|
+
def last_commit(path: ".")
|
91
|
+
result = rev_parse("HEAD", path: path)
|
92
|
+
return nil unless result.status
|
113
93
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
94
|
+
result.out.strip
|
95
|
+
end
|
96
|
+
|
97
|
+
# Translate a git epoch timestamp into a Time
|
98
|
+
sig { params(timestamp: String).returns(Time) }
|
99
|
+
def epoch_to_time(timestamp)
|
100
|
+
Time.strptime(timestamp, "%s")
|
101
|
+
end
|
102
|
+
|
103
|
+
# Is there uncommited changes in `path`?
|
104
|
+
sig { params(path: String).returns(T::Boolean) }
|
105
|
+
def workdir_clean?(path: ".")
|
106
|
+
diff("HEAD", path: path).out.empty?
|
107
|
+
end
|
108
|
+
|
109
|
+
# Get the hash of the commit introducing the `sorbet/config` file
|
110
|
+
sig { params(path: String).returns(T.nilable(String)) }
|
111
|
+
def sorbet_intro_commit(path: ".")
|
112
|
+
result = Spoom::Git.log("--diff-filter=A --format='%h' -1 -- sorbet/config", path: path)
|
113
|
+
return nil unless result.status
|
114
|
+
|
115
|
+
out = result.out.strip
|
116
|
+
return nil if out.empty?
|
117
|
+
|
118
|
+
out
|
119
|
+
end
|
120
|
+
|
121
|
+
# Get the hash of the commit removing the `sorbet/config` file
|
122
|
+
sig { params(path: String).returns(T.nilable(String)) }
|
123
|
+
def sorbet_removal_commit(path: ".")
|
124
|
+
result = Spoom::Git.log("--diff-filter=D --format='%h' -1 -- sorbet/config", path: path)
|
125
|
+
return nil unless result.status
|
126
|
+
|
127
|
+
out = result.out.strip
|
128
|
+
return nil if out.empty?
|
129
|
+
|
130
|
+
out
|
131
|
+
end
|
122
132
|
end
|
123
133
|
end
|
124
134
|
end
|
data/lib/spoom/printer.rb
CHANGED
@@ -38,6 +38,7 @@ module Spoom
|
|
38
38
|
sig { params(string: T.nilable(String)).void }
|
39
39
|
def print(string)
|
40
40
|
return unless string
|
41
|
+
|
41
42
|
@out.print(string)
|
42
43
|
end
|
43
44
|
|
@@ -47,6 +48,7 @@ module Spoom
|
|
47
48
|
sig { params(string: T.nilable(String), color: Color).void }
|
48
49
|
def print_colored(string, *color)
|
49
50
|
return unless string
|
51
|
+
|
50
52
|
string = T.unsafe(self).colorize(string, *color)
|
51
53
|
@out.print(string)
|
52
54
|
end
|
@@ -61,6 +63,7 @@ module Spoom
|
|
61
63
|
sig { params(string: T.nilable(String)).void }
|
62
64
|
def printl(string)
|
63
65
|
return unless string
|
66
|
+
|
64
67
|
printt
|
65
68
|
print(string)
|
66
69
|
printn
|
@@ -76,6 +79,7 @@ module Spoom
|
|
76
79
|
sig { params(string: String, color: Spoom::Color).returns(String) }
|
77
80
|
def colorize(string, *color)
|
78
81
|
return string unless @colors
|
82
|
+
|
79
83
|
T.unsafe(self).set_color(string, *color)
|
80
84
|
end
|
81
85
|
end
|
data/lib/spoom/sorbet/errors.rb
CHANGED
@@ -4,10 +4,16 @@
|
|
4
4
|
module Spoom
|
5
5
|
module Sorbet
|
6
6
|
module Errors
|
7
|
-
extend T::Sig
|
8
|
-
|
9
7
|
DEFAULT_ERROR_URL_BASE = "https://srb.help/"
|
10
8
|
|
9
|
+
class << self
|
10
|
+
extend T::Sig
|
11
|
+
|
12
|
+
sig { params(errors: T::Array[Error]).returns(T::Array[Error]) }
|
13
|
+
def sort_errors_by_code(errors)
|
14
|
+
errors.sort_by { |e| [e.code, e.file, e.line, e.message] }
|
15
|
+
end
|
16
|
+
end
|
11
17
|
# Parse errors from Sorbet output
|
12
18
|
class Parser
|
13
19
|
extend T::Sig
|
@@ -20,10 +26,14 @@ module Spoom
|
|
20
26
|
"or set SORBET_SILENCE_DEV_MESSAGE=1 in your shell environment.",
|
21
27
|
], T::Array[String])
|
22
28
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
29
|
+
class << self
|
30
|
+
extend T::Sig
|
31
|
+
|
32
|
+
sig { params(output: String, error_url_base: String).returns(T::Array[Error]) }
|
33
|
+
def parse_string(output, error_url_base: DEFAULT_ERROR_URL_BASE)
|
34
|
+
parser = Spoom::Sorbet::Errors::Parser.new(error_url_base: error_url_base)
|
35
|
+
parser.parse(output)
|
36
|
+
end
|
27
37
|
end
|
28
38
|
|
29
39
|
sig { params(error_url_base: String).void }
|
@@ -85,12 +95,14 @@ module Spoom
|
|
85
95
|
sig { params(error: Error).void }
|
86
96
|
def open_error(error)
|
87
97
|
raise "Error: Already parsing an error!" if @current_error
|
98
|
+
|
88
99
|
@current_error = error
|
89
100
|
end
|
90
101
|
|
91
102
|
sig { void }
|
92
103
|
def close_error
|
93
104
|
raise "Error: Not already parsing an error!" unless @current_error
|
105
|
+
|
94
106
|
@errors << @current_error
|
95
107
|
@current_error = nil
|
96
108
|
end
|
@@ -98,6 +110,11 @@ module Spoom
|
|
98
110
|
sig { params(line: String).void }
|
99
111
|
def append_error(line)
|
100
112
|
raise "Error: Not already parsing an error!" unless @current_error
|
113
|
+
|
114
|
+
filepath_match = line.match(/^ (.*?):\d+/)
|
115
|
+
if filepath_match && filepath_match[1]
|
116
|
+
@current_error.files_from_error_sections << T.must(filepath_match[1])
|
117
|
+
end
|
101
118
|
@current_error.more << line
|
102
119
|
end
|
103
120
|
end
|
@@ -115,6 +132,10 @@ module Spoom
|
|
115
132
|
sig { returns(T::Array[String]) }
|
116
133
|
attr_reader :more
|
117
134
|
|
135
|
+
# Other files associated with the error
|
136
|
+
sig { returns(T::Set[String]) }
|
137
|
+
attr_reader :files_from_error_sections
|
138
|
+
|
118
139
|
sig do
|
119
140
|
params(
|
120
141
|
file: T.nilable(String),
|
@@ -130,12 +151,14 @@ module Spoom
|
|
130
151
|
@message = message
|
131
152
|
@code = code
|
132
153
|
@more = more
|
154
|
+
@files_from_error_sections = T.let(Set.new, T::Set[String])
|
133
155
|
end
|
134
156
|
|
135
157
|
# By default errors are sorted by location
|
136
158
|
sig { params(other: T.untyped).returns(Integer) }
|
137
159
|
def <=>(other)
|
138
160
|
return 0 unless other.is_a?(Error)
|
161
|
+
|
139
162
|
[file, line, code, message] <=> [other.file, other.line, other.code, other.message]
|
140
163
|
end
|
141
164
|
|
@@ -144,11 +167,6 @@ module Spoom
|
|
144
167
|
"#{file}:#{line}: #{message} (#{code})"
|
145
168
|
end
|
146
169
|
end
|
147
|
-
|
148
|
-
sig { params(errors: T::Array[Error]).returns(T::Array[Error]) }
|
149
|
-
def self.sort_errors_by_code(errors)
|
150
|
-
errors.sort_by { |e| [e.code, e.file, e.line, e.message] }
|
151
|
-
end
|
152
170
|
end
|
153
171
|
end
|
154
172
|
end
|
@@ -16,18 +16,23 @@ module Spoom
|
|
16
16
|
sig { returns(T::Array[Diagnostic]) }
|
17
17
|
attr_reader :diagnostics
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
19
|
+
class << self
|
20
|
+
extend T::Sig
|
21
|
+
|
22
|
+
sig { params(json: T::Hash[T.untyped, T.untyped]).returns(Diagnostics) }
|
23
|
+
def from_json(json)
|
24
|
+
Diagnostics.new(
|
25
|
+
json["uri"],
|
26
|
+
json["diagnostics"].map { |d| Diagnostic.from_json(d) }
|
27
|
+
)
|
28
|
+
end
|
25
29
|
end
|
26
30
|
|
27
31
|
sig { params(uri: String, diagnostics: T::Array[Diagnostic]).void }
|
28
32
|
def initialize(uri, diagnostics)
|
29
33
|
@uri = uri
|
30
34
|
@diagnostics = diagnostics
|
35
|
+
super()
|
31
36
|
end
|
32
37
|
end
|
33
38
|
end
|
@@ -38,25 +43,26 @@ module Spoom
|
|
38
43
|
sig { returns(Integer) }
|
39
44
|
attr_reader :code
|
40
45
|
|
41
|
-
sig { returns(String) }
|
42
|
-
attr_reader :message
|
43
|
-
|
44
46
|
sig { returns(T::Hash[T.untyped, T.untyped]) }
|
45
47
|
attr_reader :data
|
46
48
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
49
|
+
class << self
|
50
|
+
extend T::Sig
|
51
|
+
|
52
|
+
sig { params(json: T::Hash[T.untyped, T.untyped]).returns(ResponseError) }
|
53
|
+
def from_json(json)
|
54
|
+
ResponseError.new(
|
55
|
+
json["code"],
|
56
|
+
json["message"],
|
57
|
+
json["data"]
|
58
|
+
)
|
59
|
+
end
|
54
60
|
end
|
55
61
|
|
56
62
|
sig { params(code: Integer, message: String, data: T::Hash[T.untyped, T.untyped]).void }
|
57
63
|
def initialize(code, message, data)
|
64
|
+
super(message)
|
58
65
|
@code = code
|
59
|
-
@message = message
|
60
66
|
@data = data
|
61
67
|
end
|
62
68
|
end
|