rubocop-schema-gen 0.1.0 → 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.
- checksums.yaml +4 -4
- data/.rspec +1 -1
- data/.rubocop.yml +37 -1
- data/.ruby-version +1 -1
- data/.travis.yml +5 -1
- data/Gemfile +6 -1
- data/LICENSE +13 -0
- data/README.md +20 -25
- data/assets/templates/cop_schema.yml +1 -3
- data/assets/templates/schema.yml +4 -0
- data/bin/console +1 -0
- data/exe/rubocop-schema-gen +4 -2
- data/lib/rubocop/schema.rb +0 -3
- data/lib/rubocop/schema/ascii_doc/base.rb +53 -0
- data/lib/rubocop/schema/ascii_doc/cop.rb +93 -0
- data/lib/rubocop/schema/ascii_doc/department.rb +21 -0
- data/lib/rubocop/schema/ascii_doc/index.rb +20 -0
- data/lib/rubocop/schema/ascii_doc/stringifier.rb +49 -0
- data/lib/rubocop/schema/{cache.rb → cached_http_client.rb} +7 -11
- data/lib/rubocop/schema/cli.rb +55 -25
- data/lib/rubocop/schema/cop_info_merger.rb +54 -0
- data/lib/rubocop/schema/cop_schema.rb +69 -26
- data/lib/rubocop/schema/defaults_ripper.rb +46 -0
- data/lib/rubocop/schema/document_loader.rb +41 -0
- data/lib/rubocop/schema/extension_spec.rb +59 -0
- data/lib/rubocop/schema/generator.rb +93 -0
- data/lib/rubocop/schema/helpers.rb +51 -0
- data/lib/rubocop/schema/value_objects.rb +23 -3
- data/lib/rubocop/schema/version.rb +1 -1
- data/rubocop-schema.gemspec +4 -3
- data/rubocop-schema.json +4174 -3086
- metadata +34 -11
- data/lib/rubocop/schema/lockfile_inspector.rb +0 -51
- data/lib/rubocop/schema/scraper.rb +0 -183
- data/lib/rubocop/schema/templates.rb +0 -8
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.1
|
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-04-
|
11
|
+
date: 2021-04-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: asciidoctor
|
@@ -24,21 +24,35 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 2.0.14
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.17'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.17'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: nokogiri
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
30
44
|
requirements:
|
31
45
|
- - "~>"
|
32
46
|
- !ruby/object:Gem::Version
|
33
|
-
version: '1
|
47
|
+
version: '1'
|
34
48
|
type: :runtime
|
35
49
|
prerelease: false
|
36
50
|
version_requirements: !ruby/object:Gem::Requirement
|
37
51
|
requirements:
|
38
52
|
- - "~>"
|
39
53
|
- !ruby/object:Gem::Version
|
40
|
-
version: '1
|
41
|
-
description: Generate JSON schemas for IDE integration with
|
54
|
+
version: '1'
|
55
|
+
description: Generate JSON schemas for IDE integration with RuboCop
|
42
56
|
email:
|
43
57
|
- neil@helium.net.au
|
44
58
|
executables:
|
@@ -53,6 +67,7 @@ files:
|
|
53
67
|
- ".travis.yml"
|
54
68
|
- CODE_OF_CONDUCT.md
|
55
69
|
- Gemfile
|
70
|
+
- LICENSE
|
56
71
|
- LICENSE.txt
|
57
72
|
- README.md
|
58
73
|
- Rakefile
|
@@ -62,12 +77,20 @@ files:
|
|
62
77
|
- bin/setup
|
63
78
|
- exe/rubocop-schema-gen
|
64
79
|
- lib/rubocop/schema.rb
|
65
|
-
- lib/rubocop/schema/
|
80
|
+
- lib/rubocop/schema/ascii_doc/base.rb
|
81
|
+
- lib/rubocop/schema/ascii_doc/cop.rb
|
82
|
+
- lib/rubocop/schema/ascii_doc/department.rb
|
83
|
+
- lib/rubocop/schema/ascii_doc/index.rb
|
84
|
+
- lib/rubocop/schema/ascii_doc/stringifier.rb
|
85
|
+
- lib/rubocop/schema/cached_http_client.rb
|
66
86
|
- lib/rubocop/schema/cli.rb
|
87
|
+
- lib/rubocop/schema/cop_info_merger.rb
|
67
88
|
- lib/rubocop/schema/cop_schema.rb
|
68
|
-
- lib/rubocop/schema/
|
69
|
-
- lib/rubocop/schema/
|
70
|
-
- lib/rubocop/schema/
|
89
|
+
- lib/rubocop/schema/defaults_ripper.rb
|
90
|
+
- lib/rubocop/schema/document_loader.rb
|
91
|
+
- lib/rubocop/schema/extension_spec.rb
|
92
|
+
- lib/rubocop/schema/generator.rb
|
93
|
+
- lib/rubocop/schema/helpers.rb
|
71
94
|
- lib/rubocop/schema/value_objects.rb
|
72
95
|
- lib/rubocop/schema/version.rb
|
73
96
|
- rubocop-schema.gemspec
|
@@ -87,7 +110,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
87
110
|
requirements:
|
88
111
|
- - ">="
|
89
112
|
- !ruby/object:Gem::Version
|
90
|
-
version:
|
113
|
+
version: 2.4.0
|
91
114
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
92
115
|
requirements:
|
93
116
|
- - ">="
|
@@ -97,5 +120,5 @@ requirements: []
|
|
97
120
|
rubygems_version: 3.2.3
|
98
121
|
signing_key:
|
99
122
|
specification_version: 4
|
100
|
-
summary: Generate JSON schemas for IDE integration with
|
123
|
+
summary: Generate JSON schemas for IDE integration with RuboCop
|
101
124
|
test_files: []
|
@@ -1,51 +0,0 @@
|
|
1
|
-
require 'bundler'
|
2
|
-
require 'pathname'
|
3
|
-
|
4
|
-
module RuboCop
|
5
|
-
module Schema
|
6
|
-
class LockfileInspector
|
7
|
-
Spec = Struct.new(:name, :version, keyword_init: true) do
|
8
|
-
def short_name
|
9
|
-
return nil if name == 'rubocop'
|
10
|
-
|
11
|
-
name[8..]
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
KNOWN_GEMS = Set.new(
|
16
|
-
%w[
|
17
|
-
rubocop
|
18
|
-
rubocop-performance
|
19
|
-
rubocop-rails
|
20
|
-
rubocop-rspec
|
21
|
-
rubocop-minitest
|
22
|
-
rubocop-rake
|
23
|
-
rubocop-sequel
|
24
|
-
]
|
25
|
-
)
|
26
|
-
|
27
|
-
# @return [Pathname]
|
28
|
-
attr_reader :lockfile_path
|
29
|
-
|
30
|
-
def initialize(lockfile_path)
|
31
|
-
@lockfile_path = Pathname(lockfile_path)
|
32
|
-
end
|
33
|
-
|
34
|
-
# @return [Array<Spec>]
|
35
|
-
def specs
|
36
|
-
return [] unless @lockfile_path.readable?
|
37
|
-
|
38
|
-
@specs ||= Bundler::LockfileParser.new(@lockfile_path.to_s).sources.flat_map do |source|
|
39
|
-
source.specs.map do |stub|
|
40
|
-
next unless KNOWN_GEMS.include? stub.name
|
41
|
-
|
42
|
-
Spec.new(
|
43
|
-
name: stub.name,
|
44
|
-
version: stub.version.to_s
|
45
|
-
)
|
46
|
-
end.compact
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
@@ -1,183 +0,0 @@
|
|
1
|
-
require 'asciidoctor'
|
2
|
-
require 'nokogiri'
|
3
|
-
|
4
|
-
require 'rubocop/schema/cache'
|
5
|
-
require 'rubocop/schema/lockfile_inspector'
|
6
|
-
require 'rubocop/schema/templates'
|
7
|
-
require 'rubocop/schema/value_objects'
|
8
|
-
|
9
|
-
module RuboCop
|
10
|
-
module Schema
|
11
|
-
class Scraper
|
12
|
-
DEFAULT_VERSION = -'master'
|
13
|
-
URL_TEMPLATE =
|
14
|
-
-'https://raw.githubusercontent.com/rubocop/rubocop%s/%s/docs/modules/ROOT/pages/cops%s.adoc'
|
15
|
-
|
16
|
-
# @param [LockfileInspector] lockfile
|
17
|
-
# @param [Object] cache
|
18
|
-
def initialize(lockfile, cache)
|
19
|
-
raise ArgumentError unless cache.is_a? Cache
|
20
|
-
raise ArgumentError unless lockfile.is_a? LockfileInspector
|
21
|
-
|
22
|
-
@cache = cache
|
23
|
-
@lockfile = lockfile
|
24
|
-
end
|
25
|
-
|
26
|
-
def schema
|
27
|
-
Schema.template('schema').tap do |json|
|
28
|
-
properties = json.fetch('properties')
|
29
|
-
|
30
|
-
lockfile.specs.each do |spec|
|
31
|
-
index(spec).each do |department_name|
|
32
|
-
dept_info = CopInfo.new(
|
33
|
-
name: department_name,
|
34
|
-
description: "Department #{department_name}"
|
35
|
-
)
|
36
|
-
dept_info.description << " (#{spec.short_name} extension)" if spec.short_name
|
37
|
-
properties[department_name] = cop_schema(dept_info)
|
38
|
-
|
39
|
-
info_for(spec, department_name).each do |cop_info|
|
40
|
-
properties[cop_info.name] = cop_schema(cop_info)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
private
|
48
|
-
|
49
|
-
# @return [LockfileInspector]
|
50
|
-
attr_reader :lockfile
|
51
|
-
|
52
|
-
# @return [Cache]
|
53
|
-
attr_reader :cache
|
54
|
-
|
55
|
-
def info_for(spec, department)
|
56
|
-
doc = load_doc(extension: spec.short_name, version: spec.version, department: department)
|
57
|
-
cop_blocks = doc.query(context: :section) { |s| s.title.start_with? "#{department}/" }
|
58
|
-
cop_blocks.map do |section|
|
59
|
-
info = CopInfo.new(name: section.title)
|
60
|
-
|
61
|
-
description = []
|
62
|
-
# Stats table
|
63
|
-
stats_table_block =
|
64
|
-
section
|
65
|
-
.query(context: :table) { |t| t.rows.head.first.first.text == 'Enabled by default' }
|
66
|
-
.first
|
67
|
-
|
68
|
-
if stats_table_block
|
69
|
-
stats_table = table_to_hash(stats_table_block).first
|
70
|
-
description << "Default: #{stats_table['Enabled by default']}"
|
71
|
-
info.supports_autocorrect = stats_table['Supports autocorrection'] == 'Yes'
|
72
|
-
end
|
73
|
-
|
74
|
-
# Description
|
75
|
-
top = section.blocks.index(stats_table_block) || -1
|
76
|
-
top += 1
|
77
|
-
bottom = section.blocks.index(section.sections.first) || 0
|
78
|
-
bottom -= 1
|
79
|
-
description = section.blocks[top..bottom].map do |s|
|
80
|
-
case s.context
|
81
|
-
when :paragraph, :admonition, :listing
|
82
|
-
s.lines.join(' ')
|
83
|
-
when :literal
|
84
|
-
s.lines.map { |l| " #{l}" }.join("\n")
|
85
|
-
when :ulist
|
86
|
-
s.blocks.map { |b| " - #{reverse_html b.text}" }
|
87
|
-
when :olist
|
88
|
-
s.blocks.map.with_index { |b, i| " #{i + 1}. #{reverse_html b.text}" }
|
89
|
-
when :dlist
|
90
|
-
reverse_html s.convert # Too hard, just go HTML for now
|
91
|
-
else
|
92
|
-
raise "Don't know what to do with #{s.context}"
|
93
|
-
end
|
94
|
-
end + description
|
95
|
-
|
96
|
-
info.description = description.join("\n\n") unless description.empty?
|
97
|
-
|
98
|
-
# Configurable attributes
|
99
|
-
|
100
|
-
attr_table_block = section
|
101
|
-
.query(context: :section) { |s| s.title == 'Configurable attributes' }&.first
|
102
|
-
&.query(context: :table)&.first
|
103
|
-
|
104
|
-
if attr_table_block
|
105
|
-
info.attributes = table_to_hash(attr_table_block).map do |row|
|
106
|
-
type = row['Configurable values']
|
107
|
-
type = type.scan(/\w+/) if type.start_with? '`'
|
108
|
-
Attribute.new(
|
109
|
-
name: row['Name'],
|
110
|
-
default: row['Default value'],
|
111
|
-
type: type
|
112
|
-
)
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
info
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
# @param [LockFileInspector::Spec] spec
|
121
|
-
def index(spec)
|
122
|
-
doc = load_doc(extension: spec.short_name, version: spec.version)
|
123
|
-
dept_blocks = doc.query(context: :section) { |s| s.title.start_with? 'Department ' }
|
124
|
-
dept_blocks.map { |section| link_text section.title }
|
125
|
-
end
|
126
|
-
|
127
|
-
def load_doc(...)
|
128
|
-
# noinspection RubyResolve
|
129
|
-
Asciidoctor.load cache.get url_for(...)
|
130
|
-
end
|
131
|
-
|
132
|
-
def url_for(department: nil, version: DEFAULT_VERSION, extension: nil)
|
133
|
-
version = "v#{version}" if version =~ /\A\d+\./
|
134
|
-
format(URL_TEMPLATE, extension && "-#{extension}", version, department && "_#{department.to_s.downcase}")
|
135
|
-
end
|
136
|
-
|
137
|
-
def link_text(str)
|
138
|
-
# The Asciidoctor API doesn't provide access to the raw title, or parts of it.
|
139
|
-
# If performance becomes an issue, this could become a regexp or similarly crude solution.
|
140
|
-
Nokogiri::HTML(str).at_css('a')&.text
|
141
|
-
end
|
142
|
-
|
143
|
-
def reverse_html(str)
|
144
|
-
str = str.gsub(%r{</?code>}, '`')
|
145
|
-
Nokogiri::HTML(str).text
|
146
|
-
end
|
147
|
-
|
148
|
-
# @param [Asciidoctor::Table] table
|
149
|
-
def table_to_hash(table)
|
150
|
-
headings = table.rows.head.first.map(&:text)
|
151
|
-
table.rows.body.map do |row|
|
152
|
-
headings.each_with_index.to_h do |heading, i|
|
153
|
-
[heading, reverse_html(row[i].text)]
|
154
|
-
end
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
|
-
KNOWN_TYPES = Set.new(%w[boolean integer array string]).freeze
|
159
|
-
|
160
|
-
# @param [CopInfo] info
|
161
|
-
def cop_schema(info)
|
162
|
-
Schema.template('cop_schema').tap do |json|
|
163
|
-
json['description'] = info.description
|
164
|
-
json['properties'] = props = json.fetch('properties').dup
|
165
|
-
|
166
|
-
props['AutoCorrect'] = { 'type' => 'boolean' } if info.supports_autocorrect
|
167
|
-
|
168
|
-
info.attributes&.each do |attr|
|
169
|
-
props[attr.name] = prop = {}
|
170
|
-
prop['description'] = "Default: #{attr.default}" unless attr.default.blank?
|
171
|
-
case attr.type
|
172
|
-
when Array
|
173
|
-
prop['enum'] = attr.type
|
174
|
-
when String
|
175
|
-
type = attr.type.downcase
|
176
|
-
prop['type'] = type if KNOWN_TYPES.include? type
|
177
|
-
end
|
178
|
-
end
|
179
|
-
end
|
180
|
-
end
|
181
|
-
end
|
182
|
-
end
|
183
|
-
end
|