codeclimate-fede 0.85.23
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 +7 -0
- data/bin/check +18 -0
- data/bin/codeclimate +21 -0
- data/bin/prep-release +45 -0
- data/bin/release +41 -0
- data/bin/validate-release +18 -0
- data/config/engines.yml +322 -0
- data/lib/cc/analyzer.rb +50 -0
- data/lib/cc/analyzer/bridge.rb +106 -0
- data/lib/cc/analyzer/composite_container_listener.rb +21 -0
- data/lib/cc/analyzer/container.rb +208 -0
- data/lib/cc/analyzer/container/result.rb +74 -0
- data/lib/cc/analyzer/container_listener.rb +9 -0
- data/lib/cc/analyzer/engine.rb +125 -0
- data/lib/cc/analyzer/engine_output.rb +74 -0
- data/lib/cc/analyzer/engine_output_filter.rb +36 -0
- data/lib/cc/analyzer/engine_output_overrider.rb +31 -0
- data/lib/cc/analyzer/filesystem.rb +50 -0
- data/lib/cc/analyzer/formatters.rb +21 -0
- data/lib/cc/analyzer/formatters/formatter.rb +53 -0
- data/lib/cc/analyzer/formatters/html_formatter.rb +415 -0
- data/lib/cc/analyzer/formatters/json_formatter.rb +38 -0
- data/lib/cc/analyzer/formatters/plain_text_formatter.rb +101 -0
- data/lib/cc/analyzer/formatters/spinner.rb +35 -0
- data/lib/cc/analyzer/issue.rb +69 -0
- data/lib/cc/analyzer/issue_sorter.rb +30 -0
- data/lib/cc/analyzer/issue_validations.rb +26 -0
- data/lib/cc/analyzer/issue_validations/category_validation.rb +32 -0
- data/lib/cc/analyzer/issue_validations/check_name_presence_validation.rb +15 -0
- data/lib/cc/analyzer/issue_validations/content_validation.rb +21 -0
- data/lib/cc/analyzer/issue_validations/description_presence_validation.rb +15 -0
- data/lib/cc/analyzer/issue_validations/location_format_validation.rb +72 -0
- data/lib/cc/analyzer/issue_validations/other_locations_format_validation.rb +41 -0
- data/lib/cc/analyzer/issue_validations/path_existence_validation.rb +15 -0
- data/lib/cc/analyzer/issue_validations/path_is_file_validation.rb +15 -0
- data/lib/cc/analyzer/issue_validations/path_presence_validation.rb +15 -0
- data/lib/cc/analyzer/issue_validations/relative_path_validation.rb +32 -0
- data/lib/cc/analyzer/issue_validations/remediation_points_validation.rb +25 -0
- data/lib/cc/analyzer/issue_validations/severity_validation.rb +39 -0
- data/lib/cc/analyzer/issue_validations/type_validation.rb +15 -0
- data/lib/cc/analyzer/issue_validations/validation.rb +35 -0
- data/lib/cc/analyzer/issue_validator.rb +11 -0
- data/lib/cc/analyzer/location_description.rb +45 -0
- data/lib/cc/analyzer/logging_container_listener.rb +24 -0
- data/lib/cc/analyzer/measurement.rb +22 -0
- data/lib/cc/analyzer/measurement_validations.rb +16 -0
- data/lib/cc/analyzer/measurement_validations/name_validation.rb +23 -0
- data/lib/cc/analyzer/measurement_validations/type_validation.rb +15 -0
- data/lib/cc/analyzer/measurement_validations/validation.rb +27 -0
- data/lib/cc/analyzer/measurement_validations/value_validation.rb +21 -0
- data/lib/cc/analyzer/measurement_validator.rb +11 -0
- data/lib/cc/analyzer/mounted_path.rb +80 -0
- data/lib/cc/analyzer/raising_container_listener.rb +32 -0
- data/lib/cc/analyzer/source_buffer.rb +47 -0
- data/lib/cc/analyzer/source_extractor.rb +79 -0
- data/lib/cc/analyzer/source_fingerprint.rb +40 -0
- data/lib/cc/analyzer/statsd_container_listener.rb +51 -0
- data/lib/cc/analyzer/validator.rb +38 -0
- data/lib/cc/cli.rb +39 -0
- data/lib/cc/cli/analyze.rb +90 -0
- data/lib/cc/cli/analyze/engine_failure.rb +11 -0
- data/lib/cc/cli/command.rb +85 -0
- data/lib/cc/cli/console.rb +12 -0
- data/lib/cc/cli/engines.rb +5 -0
- data/lib/cc/cli/engines/engine_command.rb +15 -0
- data/lib/cc/cli/engines/install.rb +35 -0
- data/lib/cc/cli/engines/list.rb +18 -0
- data/lib/cc/cli/file_store.rb +42 -0
- data/lib/cc/cli/global_cache.rb +47 -0
- data/lib/cc/cli/global_config.rb +35 -0
- data/lib/cc/cli/help.rb +51 -0
- data/lib/cc/cli/output.rb +34 -0
- data/lib/cc/cli/prepare.rb +98 -0
- data/lib/cc/cli/runner.rb +75 -0
- data/lib/cc/cli/validate_config.rb +84 -0
- data/lib/cc/cli/version.rb +16 -0
- data/lib/cc/cli/version_checker.rb +107 -0
- data/lib/cc/config.rb +70 -0
- data/lib/cc/config/checks_adapter.rb +40 -0
- data/lib/cc/config/default_adapter.rb +54 -0
- data/lib/cc/config/engine.rb +41 -0
- data/lib/cc/config/engine_set.rb +47 -0
- data/lib/cc/config/json_adapter.rb +17 -0
- data/lib/cc/config/prepare.rb +92 -0
- data/lib/cc/config/validation/check_validator.rb +34 -0
- data/lib/cc/config/validation/engine_validator.rb +93 -0
- data/lib/cc/config/validation/fetch_validator.rb +78 -0
- data/lib/cc/config/validation/file_validator.rb +112 -0
- data/lib/cc/config/validation/hash_validations.rb +52 -0
- data/lib/cc/config/validation/json.rb +31 -0
- data/lib/cc/config/validation/prepare_validator.rb +40 -0
- data/lib/cc/config/validation/yaml.rb +66 -0
- data/lib/cc/config/yaml_adapter.rb +73 -0
- data/lib/cc/engine_registry.rb +74 -0
- data/lib/cc/resolv.rb +39 -0
- data/lib/cc/workspace.rb +39 -0
- data/lib/cc/workspace/exclusion.rb +34 -0
- data/lib/cc/workspace/path_tree.rb +49 -0
- data/lib/cc/workspace/path_tree/dir_node.rb +67 -0
- data/lib/cc/workspace/path_tree/file_node.rb +31 -0
- metadata +277 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
module CC
|
|
2
|
+
module Analyzer
|
|
3
|
+
module Formatters
|
|
4
|
+
class JSONFormatter < Formatter
|
|
5
|
+
def initialize(filesystem)
|
|
6
|
+
@filesystem = filesystem
|
|
7
|
+
@has_begun = false
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def started
|
|
11
|
+
print "["
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def finished
|
|
15
|
+
print "]\n"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def write(data)
|
|
19
|
+
document = JSON.parse(data)
|
|
20
|
+
document["engine_name"] = current_engine.name
|
|
21
|
+
|
|
22
|
+
if @has_begun
|
|
23
|
+
print ",\n"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
print document.to_json
|
|
27
|
+
@has_begun = true
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def failed(output)
|
|
31
|
+
$stderr.puts "\nAnalysis failed with the following output:"
|
|
32
|
+
$stderr.puts output
|
|
33
|
+
exit 1
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
require "rainbow"
|
|
2
|
+
require "tty/spinner"
|
|
3
|
+
require "active_support/number_helper"
|
|
4
|
+
|
|
5
|
+
module CC
|
|
6
|
+
module Analyzer
|
|
7
|
+
module Formatters
|
|
8
|
+
class PlainTextFormatter < Formatter
|
|
9
|
+
def started
|
|
10
|
+
puts colorize("Starting analysis", :green)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def finished
|
|
14
|
+
puts
|
|
15
|
+
|
|
16
|
+
issues_by_path.each do |path, file_issues|
|
|
17
|
+
puts colorize("== #{path} (#{pluralize(file_issues.size, "issue")}) ==", :yellow)
|
|
18
|
+
|
|
19
|
+
IssueSorter.new(file_issues).by_location.each do |issue|
|
|
20
|
+
if (location = issue["location"])
|
|
21
|
+
source_buffer = @filesystem.source_buffer_for(location["path"])
|
|
22
|
+
print(colorize(LocationDescription.new(source_buffer, location, ": "), :cyan))
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
print(issue["description"])
|
|
26
|
+
print(colorize(" [#{issue["engine_name"]}]", "#333333"))
|
|
27
|
+
puts
|
|
28
|
+
end
|
|
29
|
+
puts
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
print(colorize("Analysis complete! Found #{pluralize(issues.size, "issue")}", :green))
|
|
33
|
+
unless warnings.empty?
|
|
34
|
+
print(colorize(" and #{pluralize(warnings.size, "warning")}", :green))
|
|
35
|
+
end
|
|
36
|
+
puts(colorize(".", :green))
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def engine_running(engine, &block)
|
|
40
|
+
super(engine) do
|
|
41
|
+
result = with_spinner("Running #{current_engine.name}: ", &block)
|
|
42
|
+
if result.skipped?
|
|
43
|
+
puts(colorize("Skipped #{current_engine.name}: #{result.stderr}", :yellow))
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def failed(output)
|
|
49
|
+
spinner.stop("Failed")
|
|
50
|
+
puts colorize("\nAnalysis failed with the following output:", :red)
|
|
51
|
+
puts output
|
|
52
|
+
exit 1
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
private
|
|
56
|
+
|
|
57
|
+
def spinner(text = nil)
|
|
58
|
+
@spinner ||= Spinner.new(text)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def with_spinner(text)
|
|
62
|
+
spinner(text).start
|
|
63
|
+
yield
|
|
64
|
+
ensure
|
|
65
|
+
spinner.stop
|
|
66
|
+
@spinner = nil
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def colorize(string, *args)
|
|
70
|
+
rainbow.wrap(string).color(*args)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def rainbow
|
|
74
|
+
@rainbow ||= Rainbow.new.tap do |rainbow|
|
|
75
|
+
rainbow.enabled = false unless @output.tty?
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def issues
|
|
80
|
+
@issues ||= []
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def issues_by_path
|
|
84
|
+
issues.group_by { |i| i["location"]["path"] }.sort
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def warnings
|
|
88
|
+
@warnings ||= []
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def measurements
|
|
92
|
+
@measurements ||= []
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def pluralize(number, noun)
|
|
96
|
+
"#{ActiveSupport::NumberHelper.number_to_delimited(number)} #{noun.pluralize(number)}"
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
module CC
|
|
2
|
+
module Analyzer
|
|
3
|
+
module Formatters
|
|
4
|
+
class Spinner
|
|
5
|
+
def initialize(text)
|
|
6
|
+
@spinner = TTY::Spinner.new(text)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def start
|
|
10
|
+
return unless $stdout.tty? && !CLI.debug?
|
|
11
|
+
@thread = Thread.new do
|
|
12
|
+
loop do
|
|
13
|
+
@spinning = true
|
|
14
|
+
spinner.spin
|
|
15
|
+
sleep 0.075
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def stop(text = "Done!")
|
|
21
|
+
if @spinning
|
|
22
|
+
spinner.stop(text)
|
|
23
|
+
print("\n")
|
|
24
|
+
@thread.kill
|
|
25
|
+
end
|
|
26
|
+
@spinning = false
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
attr_reader :spinner
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
module CC
|
|
2
|
+
module Analyzer
|
|
3
|
+
class Issue
|
|
4
|
+
DEFAULT_SEVERITY = IssueValidations::SeverityValidation::MINOR
|
|
5
|
+
DEPRECATED_SEVERITY = IssueValidations::SeverityValidation::NORMAL
|
|
6
|
+
|
|
7
|
+
SPEC_ISSUE_ATTRIBUTES = %w[
|
|
8
|
+
categories
|
|
9
|
+
check_name
|
|
10
|
+
content
|
|
11
|
+
description
|
|
12
|
+
location
|
|
13
|
+
other_locations
|
|
14
|
+
remediation_points
|
|
15
|
+
severity
|
|
16
|
+
type
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
def initialize(engine_name, output)
|
|
20
|
+
@engine_name = engine_name
|
|
21
|
+
@output = output
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def as_json(*)
|
|
25
|
+
parsed_output.reverse_merge!(
|
|
26
|
+
"engine_name" => engine_name,
|
|
27
|
+
"fingerprint" => fingerprint,
|
|
28
|
+
).merge!("severity" => severity)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def fingerprint
|
|
32
|
+
parsed_output.fetch("fingerprint") { default_fingerprint }
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Allow access to hash keys as methods
|
|
36
|
+
SPEC_ISSUE_ATTRIBUTES.each do |key|
|
|
37
|
+
define_method(key) do
|
|
38
|
+
parsed_output[key]
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def path
|
|
43
|
+
parsed_output.fetch("location", {}).fetch("path", "")
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
private
|
|
47
|
+
|
|
48
|
+
attr_reader :engine_name, :output
|
|
49
|
+
|
|
50
|
+
def default_fingerprint
|
|
51
|
+
SourceFingerprint.new(self).compute
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def severity
|
|
55
|
+
severity = parsed_output.fetch("severity", DEFAULT_SEVERITY)
|
|
56
|
+
|
|
57
|
+
if severity == DEPRECATED_SEVERITY
|
|
58
|
+
DEFAULT_SEVERITY
|
|
59
|
+
else
|
|
60
|
+
severity
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def parsed_output
|
|
65
|
+
@parsed_output ||= JSON.parse(output)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module CC
|
|
2
|
+
module Analyzer
|
|
3
|
+
class IssueSorter
|
|
4
|
+
def initialize(issues)
|
|
5
|
+
@issues = issues
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def by_location
|
|
9
|
+
@issues.sort_by { |i| line_or_offset(i) }
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
def line_or_offset(issue)
|
|
15
|
+
location = issue["location"]
|
|
16
|
+
|
|
17
|
+
case
|
|
18
|
+
when location["lines"]
|
|
19
|
+
[location["lines"]["begin"].to_i]
|
|
20
|
+
when location["positions"] && location["positions"]["begin"]["line"]
|
|
21
|
+
[location["positions"]["begin"]["line"].to_i, location["positions"]["begin"]["column"].to_i]
|
|
22
|
+
when location["positions"] && location["positions"]["begin"]["offset"]
|
|
23
|
+
[1_000_000_000] # push offsets to end of list
|
|
24
|
+
else
|
|
25
|
+
[0] # whole-file issues are first
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module CC
|
|
2
|
+
module Analyzer
|
|
3
|
+
module IssueValidations
|
|
4
|
+
autoload :CategoryValidation, "cc/analyzer/issue_validations/category_validation"
|
|
5
|
+
autoload :CheckNamePresenceValidation, "cc/analyzer/issue_validations/check_name_presence_validation"
|
|
6
|
+
autoload :ContentValidation, "cc/analyzer/issue_validations/content_validation"
|
|
7
|
+
autoload :DescriptionPresenceValidation, "cc/analyzer/issue_validations/description_presence_validation"
|
|
8
|
+
autoload :LocationFormatValidation, "cc/analyzer/issue_validations/location_format_validation"
|
|
9
|
+
autoload :OtherLocationsFormatValidation, "cc/analyzer/issue_validations/other_locations_format_validation"
|
|
10
|
+
autoload :PathExistenceValidation, "cc/analyzer/issue_validations/path_existence_validation"
|
|
11
|
+
autoload :PathIsFileValidation, "cc/analyzer/issue_validations/path_is_file_validation"
|
|
12
|
+
autoload :PathPresenceValidation, "cc/analyzer/issue_validations/path_presence_validation"
|
|
13
|
+
autoload :RelativePathValidation, "cc/analyzer/issue_validations/relative_path_validation"
|
|
14
|
+
autoload :RemediationPointsValidation, "cc/analyzer/issue_validations/remediation_points_validation"
|
|
15
|
+
autoload :SeverityValidation, "cc/analyzer/issue_validations/severity_validation"
|
|
16
|
+
autoload :TypeValidation, "cc/analyzer/issue_validations/type_validation"
|
|
17
|
+
autoload :Validation, "cc/analyzer/issue_validations/validation"
|
|
18
|
+
|
|
19
|
+
def self.validations
|
|
20
|
+
constants.sort.map(&method(:const_get)).select do |klass|
|
|
21
|
+
klass.is_a?(Class) && klass.superclass == Validation
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
module CC
|
|
2
|
+
module Analyzer
|
|
3
|
+
module IssueValidations
|
|
4
|
+
class CategoryValidation < Validation
|
|
5
|
+
CATEGORIES = [
|
|
6
|
+
"Bug Risk".freeze,
|
|
7
|
+
"Clarity".freeze,
|
|
8
|
+
"Compatibility".freeze,
|
|
9
|
+
"Complexity".freeze,
|
|
10
|
+
"Duplication".freeze,
|
|
11
|
+
"Performance".freeze,
|
|
12
|
+
"Security".freeze,
|
|
13
|
+
"Style".freeze,
|
|
14
|
+
].freeze
|
|
15
|
+
|
|
16
|
+
def valid?
|
|
17
|
+
object["categories"].present? && no_invalid_categories?
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def message
|
|
21
|
+
"Category must be at least one of #{CATEGORIES.join(", ")}"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def no_invalid_categories?
|
|
27
|
+
(CATEGORIES | object["categories"]) == CATEGORIES
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module CC
|
|
2
|
+
module Analyzer
|
|
3
|
+
module IssueValidations
|
|
4
|
+
class ContentValidation < Validation
|
|
5
|
+
def valid?
|
|
6
|
+
!has_content? || (content.is_a?(Hash) && content["body"].is_a?(String))
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def message
|
|
10
|
+
"Content must be a hash containing a 'body' key with string contents"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
private
|
|
14
|
+
|
|
15
|
+
def has_content?
|
|
16
|
+
object.key?("content")
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
module CC
|
|
2
|
+
module Analyzer
|
|
3
|
+
module IssueValidations
|
|
4
|
+
class LocationFormatValidation < Validation
|
|
5
|
+
class Validator
|
|
6
|
+
def initialize(location)
|
|
7
|
+
@location = location
|
|
8
|
+
check_validity
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def valid?
|
|
12
|
+
error.nil?
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def message
|
|
16
|
+
if error
|
|
17
|
+
"Location is not formatted correctly: #{error}"
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
attr_accessor :error
|
|
24
|
+
|
|
25
|
+
attr_reader :location
|
|
26
|
+
|
|
27
|
+
def check_validity
|
|
28
|
+
if location["lines"]
|
|
29
|
+
self.error = "location.lines is not valid: #{JSON.dump(location["lines"])}" unless valid_lines?(location["lines"])
|
|
30
|
+
elsif location["positions"]
|
|
31
|
+
self.error = "location.positions is not valid: #{JSON.dump(location["positions"])}" unless valid_positions?(location["positions"])
|
|
32
|
+
else
|
|
33
|
+
self.error = "location.lines or location.positions must be present"
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def valid_positions?(positions)
|
|
38
|
+
positions.is_a?(Hash) &&
|
|
39
|
+
valid_position?(positions["begin"]) &&
|
|
40
|
+
valid_position?(positions["end"])
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def valid_position?(position)
|
|
44
|
+
position &&
|
|
45
|
+
(
|
|
46
|
+
[position["line"], position["column"]].all? { |value| value.is_a?(Integer) } ||
|
|
47
|
+
position["offset"].is_a?(Integer)
|
|
48
|
+
)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def valid_lines?(lines)
|
|
52
|
+
lines.is_a?(Hash) && [lines["begin"], lines["end"]].all? { |value| value.is_a?(Integer) }
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def valid?
|
|
57
|
+
validation.valid?
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def message
|
|
61
|
+
validation.message
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
private
|
|
65
|
+
|
|
66
|
+
def validation
|
|
67
|
+
@validation ||= Validator.new(object.fetch("location", {}))
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|