rubocop-schema-gen 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/rubocop/schema/cached_http_client.rb +6 -4
- data/lib/rubocop/schema/cli.rb +52 -14
- data/lib/rubocop/schema/diff.rb +67 -0
- data/lib/rubocop/schema/document_loader.rb +17 -4
- data/lib/rubocop/schema/extension_spec.rb +17 -9
- data/lib/rubocop/schema/generator.rb +1 -3
- data/lib/rubocop/schema/helpers.rb +10 -0
- data/lib/rubocop/schema/repo.rb +79 -0
- data/lib/rubocop/schema/value_objects.rb +8 -2
- data/lib/rubocop/schema/version.rb +1 -1
- metadata +5 -16
- data/.gitignore +0 -19
- data/.rspec +0 -3
- data/.rubocop.yml +0 -74
- data/.ruby-version +0 -1
- data/.travis.yml +0 -10
- data/CODE_OF_CONDUCT.md +0 -74
- data/Gemfile +0 -15
- data/LICENSE.txt +0 -21
- data/Rakefile +0 -6
- data/bin/console +0 -15
- data/bin/setup +0 -8
- data/rubocop-schema.gemspec +0 -32
- data/rubocop-schema.json +0 -22198
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ad2887f7e9c6ed387de3ea9c44a785c2c846c351681226752d334bad5e42ac42
|
4
|
+
data.tar.gz: dd3787e2db023d2dfc5a391bbc628e9796dc63d4578e604d2bd0eb2f9fb86ca6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0cb67d04acc4d37ba1c8d4e05fb269b6f22be79b0928666c5e1639cb0d7840caacc3140c0320cead6fe311fe9aae3fd6cf9ff6474854f65ff3f07d28849204ab
|
7
|
+
data.tar.gz: 9f663797d40199ab878106996f4d6272c57c67f698ab9bb55fb222330c047330f49985eedd66cbcbd15acc0330e8da47dba38463f6039332d12d6fae2bc8514c
|
@@ -2,9 +2,13 @@ require 'pathname'
|
|
2
2
|
require 'uri'
|
3
3
|
require 'net/http'
|
4
4
|
|
5
|
+
require 'rubocop/schema/helpers'
|
6
|
+
|
5
7
|
module RuboCop
|
6
8
|
module Schema
|
7
9
|
class CachedHTTPClient
|
10
|
+
include Helpers
|
11
|
+
|
8
12
|
def initialize(cache_dir, &event_handler)
|
9
13
|
@cache_dir = Pathname(cache_dir)
|
10
14
|
@event_handler = event_handler
|
@@ -18,11 +22,9 @@ module RuboCop
|
|
18
22
|
return path.read if path.readable?
|
19
23
|
|
20
24
|
path.parent.mkpath
|
21
|
-
|
25
|
+
Event.dispatch type: :request, &@event_handler
|
22
26
|
|
23
|
-
|
24
|
-
res.body = '' unless res.is_a? Net::HTTPOK
|
25
|
-
res.body.force_encoding(Encoding::UTF_8).tap(&path.method(:write))
|
27
|
+
http_get(url).tap(&path.method(:write))
|
26
28
|
end
|
27
29
|
|
28
30
|
private
|
data/lib/rubocop/schema/cli.rb
CHANGED
@@ -5,6 +5,7 @@ require 'rubocop/schema/document_loader'
|
|
5
5
|
require 'rubocop/schema/cached_http_client'
|
6
6
|
require 'rubocop/schema/generator'
|
7
7
|
require 'rubocop/schema/extension_spec'
|
8
|
+
require 'rubocop/schema/repo'
|
8
9
|
|
9
10
|
module RuboCop
|
10
11
|
module Schema
|
@@ -22,19 +23,14 @@ module RuboCop
|
|
22
23
|
@args = args
|
23
24
|
@out_file = out_file
|
24
25
|
@log_file = log_file
|
25
|
-
@out_path = args.first
|
26
26
|
|
27
|
-
raise ArgumentError, 'Cannot accept an out_file and an argument' if @out_file &&
|
27
|
+
raise ArgumentError, 'Cannot accept an out_file and an argument' if @out_file && args.first
|
28
28
|
end
|
29
29
|
|
30
30
|
def run
|
31
|
-
|
32
|
-
|
31
|
+
read_flag while @args.first&.start_with?('--')
|
32
|
+
assign_outfile
|
33
33
|
|
34
|
-
spec = ExtensionSpec.from_lockfile(lockfile_path)
|
35
|
-
fail 'RuboCop is not part of this project' if spec.empty?
|
36
|
-
|
37
|
-
assign_outfile(spec)
|
38
34
|
print "Generating #{@out_path} … " if @out_path
|
39
35
|
|
40
36
|
schema = report_duration(lowercase: @out_path) { Generator.new(spec.specs, document_loader).schema }
|
@@ -43,18 +39,55 @@ module RuboCop
|
|
43
39
|
|
44
40
|
private
|
45
41
|
|
46
|
-
def
|
42
|
+
def read_flag
|
43
|
+
case @args.shift
|
44
|
+
when '--version'
|
45
|
+
info VERSION
|
46
|
+
when '--spec'
|
47
|
+
info spec
|
48
|
+
when /\A--spec=(\S+)/
|
49
|
+
@spec = ExtensionSpec.from_string($1)
|
50
|
+
when /\A--build-repo=(.+)/
|
51
|
+
build_repo $1
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def build_repo(dir)
|
56
|
+
Repo.new(dir, document_loader, &method(:handle_event)).build
|
57
|
+
exit
|
58
|
+
end
|
59
|
+
|
60
|
+
def spec
|
61
|
+
@spec ||=
|
62
|
+
begin
|
63
|
+
lockfile_path = @working_dir + 'Gemfile.lock'
|
64
|
+
fail "Cannot read #{lockfile_path}" unless lockfile_path.readable?
|
65
|
+
|
66
|
+
spec = ExtensionSpec.from_lockfile(lockfile_path)
|
67
|
+
fail 'RuboCop is not part of this project' if spec.empty?
|
68
|
+
|
69
|
+
spec
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def assign_outfile
|
47
74
|
return if @out_file
|
48
75
|
|
49
|
-
|
76
|
+
@out_path = path_from_arg(@args.first)
|
77
|
+
|
78
|
+
@out_file ||= File.open(@out_path, 'w') # rubocop:disable Naming/MemoizedInstanceVariableName
|
79
|
+
end
|
80
|
+
|
81
|
+
def path_from_arg(arg)
|
82
|
+
case arg
|
50
83
|
when '-'
|
51
84
|
@out_file = $stdout
|
52
|
-
|
85
|
+
nil
|
53
86
|
when nil
|
54
|
-
|
87
|
+
"#{spec}-config-schema.json"
|
88
|
+
else
|
89
|
+
arg
|
55
90
|
end
|
56
|
-
|
57
|
-
@out_file ||= File.open(@out_path, 'w') # rubocop:disable Naming/MemoizedInstanceVariableName
|
58
91
|
end
|
59
92
|
|
60
93
|
def report_duration(lowercase: false)
|
@@ -79,6 +112,11 @@ module RuboCop
|
|
79
112
|
end
|
80
113
|
end
|
81
114
|
|
115
|
+
def info(msg)
|
116
|
+
$stdout.puts msg
|
117
|
+
exit
|
118
|
+
end
|
119
|
+
|
82
120
|
def fail(msg)
|
83
121
|
@log_file.puts msg.to_s
|
84
122
|
exit 1
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'rubocop/schema/helpers'
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Schema
|
5
|
+
class Diff
|
6
|
+
include Helpers
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def instance
|
10
|
+
@instance ||= new
|
11
|
+
end
|
12
|
+
|
13
|
+
def diff(old, new)
|
14
|
+
instance.diff old, new
|
15
|
+
end
|
16
|
+
|
17
|
+
def apply(old, diff)
|
18
|
+
instance.apply old, diff
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def diff(old, new)
|
23
|
+
return diff_hashes old, new if old.is_a?(Hash) && new.is_a?(Hash)
|
24
|
+
|
25
|
+
new
|
26
|
+
end
|
27
|
+
|
28
|
+
def apply(old, diff)
|
29
|
+
return apply_hash(old, diff) if old.is_a?(Hash) && diff.is_a?(Hash)
|
30
|
+
|
31
|
+
diff
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def diff_hashes(old, new)
|
37
|
+
(old.keys - new.keys).map { |k| [k, nil] }.to_h.tap do |result|
|
38
|
+
new.each do |k, v|
|
39
|
+
if old.key? k
|
40
|
+
result[k] = diff(old[k], v) unless old[k] == v
|
41
|
+
else
|
42
|
+
result[k] = v
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def apply_hash(old, diff)
|
49
|
+
deep_dup(old).tap do |result|
|
50
|
+
diff.each do |k, v|
|
51
|
+
apply_hash_pair result, k, v
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def apply_hash_pair(hash, key, value)
|
57
|
+
if value.nil?
|
58
|
+
hash.delete key
|
59
|
+
elsif hash.key? key
|
60
|
+
hash[key] = apply(hash[key], value)
|
61
|
+
else
|
62
|
+
hash[key] = value
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -1,10 +1,19 @@
|
|
1
|
+
require 'asciidoctor'
|
2
|
+
|
1
3
|
module RuboCop
|
2
4
|
module Schema
|
3
5
|
class DocumentLoader
|
4
6
|
DOCS_URL_TEMPLATE =
|
5
|
-
-'https://raw.githubusercontent.com/rubocop/%s
|
7
|
+
-'https://raw.githubusercontent.com/rubocop/%s/%s/docs/modules/ROOT/pages/cops%s.adoc'
|
6
8
|
DEFAULTS_URL_TEMPLATE =
|
7
|
-
-'https://raw.githubusercontent.com/rubocop/%s
|
9
|
+
-'https://raw.githubusercontent.com/rubocop/%s/%s/config/default.yml'
|
10
|
+
|
11
|
+
CORRECTIONS = {
|
12
|
+
'rubocop' => {
|
13
|
+
# Fixes a typo that causes Asciidoctor to crash
|
14
|
+
'1.10.0' => '174bda389c2c23cffb17e9d6128f5e6bdbc0e8a0'
|
15
|
+
}
|
16
|
+
}.freeze
|
8
17
|
|
9
18
|
# @param [CachedHTTPClient] http_client
|
10
19
|
def initialize(http_client)
|
@@ -30,11 +39,15 @@ module RuboCop
|
|
30
39
|
private
|
31
40
|
|
32
41
|
def url_for_doc(spec, department)
|
33
|
-
format DOCS_URL_TEMPLATE, spec.name, spec
|
42
|
+
format DOCS_URL_TEMPLATE, spec.name, correct_version(spec), department && "_#{department.to_s.downcase}"
|
34
43
|
end
|
35
44
|
|
36
45
|
def url_for_defaults(spec)
|
37
|
-
format DEFAULTS_URL_TEMPLATE, spec.name, spec
|
46
|
+
format DEFAULTS_URL_TEMPLATE, spec.name, correct_version(spec)
|
47
|
+
end
|
48
|
+
|
49
|
+
def correct_version(spec)
|
50
|
+
CORRECTIONS.dig(spec.name, spec.version) || "v#{spec.version}"
|
38
51
|
end
|
39
52
|
end
|
40
53
|
end
|
@@ -28,16 +28,24 @@ module RuboCop
|
|
28
28
|
end.compact)
|
29
29
|
end
|
30
30
|
|
31
|
+
# @param [Pathname] lockfile
|
31
32
|
def self.from_lockfile(lockfile)
|
32
|
-
new(
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
33
|
+
new(lockfile.readlines.map do |line|
|
34
|
+
next unless line =~ /\A\s+(rubocop(?:-\w+)?) \((\d+(?:\.\d+)+)\)\s*\z/
|
35
|
+
next unless KNOWN_GEMS.include? $1
|
36
|
+
|
37
|
+
Spec.new(name: $1, version: $2)
|
38
|
+
end.compact)
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.from_string(string)
|
42
|
+
new(string.split('-').each_slice(2).map do |(name, version)|
|
43
|
+
name = "rubocop-#{name}" unless name == 'rubocop'
|
44
|
+
|
45
|
+
raise ArgumentError, "Unknown gem '#{name}'" unless KNOWN_GEMS.include? name
|
46
|
+
raise ArgumentError, "Invalid version '#{version}'" unless version&.match? /\A\d+(?:\.\d+)+\z/
|
47
|
+
|
48
|
+
Spec.new(name: name, version: version)
|
41
49
|
end)
|
42
50
|
end
|
43
51
|
|
@@ -1,6 +1,3 @@
|
|
1
|
-
require 'asciidoctor'
|
2
|
-
require 'nokogiri'
|
3
|
-
|
4
1
|
require 'rubocop/schema/value_objects'
|
5
2
|
require 'rubocop/schema/cop_schema'
|
6
3
|
require 'rubocop/schema/helpers'
|
@@ -32,6 +29,7 @@ module RuboCop
|
|
32
29
|
|
33
30
|
def generate
|
34
31
|
@specs.each &method(:generate_spec)
|
32
|
+
@props.delete 'AllCops' unless @specs.any? { |s| s.name == 'rubocop' }
|
35
33
|
end
|
36
34
|
|
37
35
|
def generate_spec(spec)
|
@@ -1,3 +1,6 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
require 'uri'
|
3
|
+
|
1
4
|
module RuboCop
|
2
5
|
module Schema
|
3
6
|
module Helpers
|
@@ -46,6 +49,13 @@ module RuboCop
|
|
46
49
|
def strip_html(str)
|
47
50
|
Nokogiri::HTML(str).text
|
48
51
|
end
|
52
|
+
|
53
|
+
def http_get(url)
|
54
|
+
url = URI(url)
|
55
|
+
res = Net::HTTP.get_response(url)
|
56
|
+
res.body = '' unless res.is_a? Net::HTTPOK
|
57
|
+
res.body.force_encoding Encoding::UTF_8
|
58
|
+
end
|
49
59
|
end
|
50
60
|
end
|
51
61
|
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
require 'rubocop/schema/helpers'
|
4
|
+
require 'rubocop/schema/diff'
|
5
|
+
|
6
|
+
module RuboCop
|
7
|
+
module Schema
|
8
|
+
class Repo
|
9
|
+
include Helpers
|
10
|
+
|
11
|
+
TAGS_URL_TEMPLATE = -'https://api.github.com/repos/rubocop/%s/tags'
|
12
|
+
|
13
|
+
def initialize(dir, loader, &event_handler)
|
14
|
+
@dir = Pathname(dir)
|
15
|
+
@loader = loader
|
16
|
+
@event_handler = event_handler
|
17
|
+
@dir.mkpath
|
18
|
+
end
|
19
|
+
|
20
|
+
def build
|
21
|
+
ExtensionSpec::KNOWN_GEMS.each &method(:build_for_gem)
|
22
|
+
Event.dispatch message: "Repo updated: #{@dir}", &@event_handler
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def build_for_gem(name)
|
28
|
+
existing = read(name).map { |h| [h['version'], h['diff']] }.to_h
|
29
|
+
previous = nil
|
30
|
+
body = versions_of(name).map do |version|
|
31
|
+
previous, diff = fetch_for_spec(Spec.new(name: name, version: version), existing, previous)
|
32
|
+
{
|
33
|
+
'version' => version,
|
34
|
+
'diff' => diff
|
35
|
+
}
|
36
|
+
end
|
37
|
+
write name, body.compact
|
38
|
+
end
|
39
|
+
|
40
|
+
def fetch_for_spec(spec, existing, previous)
|
41
|
+
if existing.key? spec.version
|
42
|
+
diff = existing[spec.version]
|
43
|
+
schema = Diff.apply(previous, diff)
|
44
|
+
else
|
45
|
+
schema = build_for_spec(spec)
|
46
|
+
diff = Diff.diff(previous, schema)
|
47
|
+
end
|
48
|
+
[schema, diff]
|
49
|
+
end
|
50
|
+
|
51
|
+
def build_for_spec(spec)
|
52
|
+
Event.dispatch message: "Generating: #{spec}", &@event_handler
|
53
|
+
Generator.new([spec], @loader).schema
|
54
|
+
end
|
55
|
+
|
56
|
+
def write(name, body)
|
57
|
+
path_for(name).binwrite JSON.pretty_generate body
|
58
|
+
end
|
59
|
+
|
60
|
+
def read(name)
|
61
|
+
path = path_for(name)
|
62
|
+
return [] unless path.exist?
|
63
|
+
|
64
|
+
JSON.parse path.read
|
65
|
+
end
|
66
|
+
|
67
|
+
def path_for(name)
|
68
|
+
@dir.join("#{name}.json")
|
69
|
+
end
|
70
|
+
|
71
|
+
def versions_of(name)
|
72
|
+
json = http_get(format(TAGS_URL_TEMPLATE, name))
|
73
|
+
raise "No tags available for #{name}" if json == ''
|
74
|
+
|
75
|
+
JSON.parse(json).reverse.map { |obj| obj['name'].to_s[/(?<=\Av)\d.+/] }.compact
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -2,8 +2,14 @@ module RuboCop
|
|
2
2
|
module Schema
|
3
3
|
CopInfo = Struct.new(:name, :description, :attributes, :supports_autocorrect, :enabled_by_default)
|
4
4
|
Attribute = Struct.new(:name, :type, :default)
|
5
|
-
|
6
|
-
|
5
|
+
|
6
|
+
Event = Struct.new(:type, :message) do
|
7
|
+
def self.dispatch(**kwargs)
|
8
|
+
yield new(**kwargs) if block_given?
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
Spec = Struct.new(:name, :version) do
|
7
13
|
def short_name
|
8
14
|
return nil if name == 'rubocop'
|
9
15
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubocop-schema-gen
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Neil E. Pearson
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-05-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: asciidoctor
|
@@ -60,21 +60,10 @@ executables:
|
|
60
60
|
extensions: []
|
61
61
|
extra_rdoc_files: []
|
62
62
|
files:
|
63
|
-
- ".gitignore"
|
64
|
-
- ".rspec"
|
65
|
-
- ".rubocop.yml"
|
66
|
-
- ".ruby-version"
|
67
|
-
- ".travis.yml"
|
68
|
-
- CODE_OF_CONDUCT.md
|
69
|
-
- Gemfile
|
70
63
|
- LICENSE
|
71
|
-
- LICENSE.txt
|
72
64
|
- README.md
|
73
|
-
- Rakefile
|
74
65
|
- assets/templates/cop_schema.yml
|
75
66
|
- assets/templates/schema.yml
|
76
|
-
- bin/console
|
77
|
-
- bin/setup
|
78
67
|
- exe/rubocop-schema-gen
|
79
68
|
- lib/rubocop/schema.rb
|
80
69
|
- lib/rubocop/schema/ascii_doc/base.rb
|
@@ -87,14 +76,14 @@ files:
|
|
87
76
|
- lib/rubocop/schema/cop_info_merger.rb
|
88
77
|
- lib/rubocop/schema/cop_schema.rb
|
89
78
|
- lib/rubocop/schema/defaults_ripper.rb
|
79
|
+
- lib/rubocop/schema/diff.rb
|
90
80
|
- lib/rubocop/schema/document_loader.rb
|
91
81
|
- lib/rubocop/schema/extension_spec.rb
|
92
82
|
- lib/rubocop/schema/generator.rb
|
93
83
|
- lib/rubocop/schema/helpers.rb
|
84
|
+
- lib/rubocop/schema/repo.rb
|
94
85
|
- lib/rubocop/schema/value_objects.rb
|
95
86
|
- lib/rubocop/schema/version.rb
|
96
|
-
- rubocop-schema.gemspec
|
97
|
-
- rubocop-schema.json
|
98
87
|
homepage: https://github.com/hx/rubocop-schema
|
99
88
|
licenses:
|
100
89
|
- MIT
|
@@ -117,7 +106,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
117
106
|
- !ruby/object:Gem::Version
|
118
107
|
version: '0'
|
119
108
|
requirements: []
|
120
|
-
rubygems_version: 3.
|
109
|
+
rubygems_version: 3.0.8
|
121
110
|
signing_key:
|
122
111
|
specification_version: 4
|
123
112
|
summary: Generate JSON schemas for IDE integration with RuboCop
|