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.
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.0
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-27 00:00:00.000000000 Z
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.11'
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.11'
41
- description: Generate JSON schemas for IDE integration with Rubocop
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/cache.rb
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/lockfile_inspector.rb
69
- - lib/rubocop/schema/scraper.rb
70
- - lib/rubocop/schema/templates.rb
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: 3.0.0
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 Rubocop
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
@@ -1,8 +0,0 @@
1
- module RuboCop
2
- module Schema
3
- def self.template(name)
4
- @templates ||= {}
5
- (@templates[name] ||= YAML.load_file(ROOT.join('assets', 'templates', "#{name}.yml")).freeze).dup
6
- end
7
- end
8
- end