rubocop-schema-gen 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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