tomograph 2.5.3 → 3.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.
data/exe/tomograph CHANGED
@@ -12,11 +12,10 @@ include Methadone::CLILogging
12
12
 
13
13
  version Tomograph::VERSION
14
14
  description 'Converts API Blueprint to JSON Schema'
15
- on('-d DRAFTER_VERSION', '--drafter', 'Choose drafter version: crafter, 3 or 4. Default: use drafter v.3.')
16
- on('-f INPUT_FORMAT', '--format', 'Force input format: "apib" or "yaml". Default: detect by file extension.')
15
+ on('-d DRAFTER_VERSION', '--drafter', 'Choose drafter version: crafter or 4, or OpenAPI version: openapi2 or openapi3. Default: use drafter v.4.')
17
16
  on('--exclude-description', 'Exclude "description" keys.')
18
17
  on('--split', 'Split output into files by method.')
19
- arg :input, 'path/to/doc.apib (API Blueprint) or path/to/doc.yaml (API Elements)'
18
+ arg :input, 'path/to/doc.yaml (API Elements)'
20
19
  arg :output, 'path/to/doc.json or path/to/dir if --split is used.'
21
20
 
22
21
  def prune!(obj, unwanted_key)
@@ -28,36 +27,18 @@ def prune!(obj, unwanted_key)
28
27
  end
29
28
  end
30
29
 
31
- def guess_format(opt_format, input)
32
- case opt_format && opt_format.downcase
33
- when 'apib'
34
- :apib
35
- when 'yaml'
36
- :yaml
37
- when nil
38
- case File.extname(input).downcase
39
- when '.apib'
40
- :apib
41
- when '.yaml', '.yml'
42
- :yaml
43
- else
44
- fail 'Unsupported input file extension!'
45
- end
46
- else
47
- fail 'Unsupported input format!'
48
- end
49
- end
50
-
51
30
  def choose_drafter(opt_parser)
52
31
  case opt_parser
53
32
  when 'crafter'
54
33
  :crafter
55
- when '3'
56
- :drafter_3
57
34
  when '4'
58
35
  :drafter_4
36
+ when 'openapi2'
37
+ :openapi2
38
+ when 'openapi3'
39
+ :openapi3
59
40
  when nil
60
- :drafter_3
41
+ :drafter_4
61
42
  else
62
43
  raise 'Unsupported drafter version!'
63
44
  end
@@ -77,35 +58,21 @@ def write_split_json(actions, output)
77
58
  end
78
59
 
79
60
  def write_json(obj, path)
80
- json = MultiJson.dump(obj, pretty: true)
61
+ json = JSON.pretty_generate(obj)
81
62
  File.open(path, 'w') do |file|
82
63
  file.write(json)
83
64
  end
84
65
  end
85
66
 
86
67
  main do |input, output|
87
- format = guess_format(options['format'], input)
88
68
  version = choose_drafter(options['drafter'])
89
- format_key = case format
90
- when :apib
91
- if version == :drafter_3
92
- :apib_path
93
- elsif version == :crafter
94
- :crafter_apib_path
95
- else
96
- :drafter_4_apib_path
97
- end
98
- when :yaml
99
- if version == :drafter_3
100
- :drafter_yaml_path
101
- elsif version == :crafter
102
- :crafter_yaml_path
103
- else
104
- :drafter_4_yaml_path
105
- end
106
- else
107
- fail NotImplementedError
108
- end
69
+ format_key = {
70
+ crafter: :crafter_yaml_path,
71
+ drafter_4: :drafter_yaml_path,
72
+ openapi2: :openapi2_json_path,
73
+ openapi3: :openapi3_yaml_path
74
+ }[version]
75
+
109
76
  tomogram = Tomograph::Tomogram.new(format_key => input)
110
77
  actions = tomogram.to_a.map(&:to_hash)
111
78
 
@@ -6,13 +6,9 @@ module Tomograph
6
6
  module ApiBlueprint
7
7
  class Crafter
8
8
  class Yaml
9
- def initialize(prefix, apib_path, drafter_yaml_path)
9
+ def initialize(prefix, drafter_yaml_path)
10
10
  @prefix = prefix
11
- @documentation = if apib_path
12
- YAML.safe_load(`drafter #{apib_path}`)
13
- elsif drafter_yaml_path
14
- YAML.safe_load(File.read(drafter_yaml_path))
15
- end
11
+ @documentation = YAML.safe_load(File.read(drafter_yaml_path))
16
12
  end
17
13
 
18
14
  def groups
@@ -101,15 +97,15 @@ module Tomograph
101
97
  path: "#{@prefix}#{related_actions.first.path}",
102
98
  method: related_actions.first.method,
103
99
  content_type: related_actions.first.content_type,
104
- request: related_actions.first.request,
105
- responses: related_actions.map(&:responses).flatten,
100
+ requests: related_actions.map(&:request).flatten.uniq,
101
+ responses: related_actions.map(&:responses).flatten.uniq,
106
102
  resource: related_actions.first.resource
107
103
  }
108
104
  end
109
105
 
110
106
  def to_tomogram
111
107
  @tomogram ||= actions.inject([]) do |result, action|
112
- result.push(Tomograph::Tomogram::Action.new(action))
108
+ result.push(Tomograph::Tomogram::Action.new(**action))
113
109
  end
114
110
  end
115
111
 
@@ -37,8 +37,8 @@ module Tomograph
37
37
  end
38
38
  return {} unless schema_node
39
39
 
40
- MultiJson.load(schema_node['content'])
41
- rescue MultiJson::ParseError => e
40
+ JSON.parse(schema_node['content'])
41
+ rescue JSON::ParserError => e
42
42
  puts "[Tomograph] Error while parsing #{e}. skipping..."
43
43
  {}
44
44
  end
@@ -6,13 +6,9 @@ module Tomograph
6
6
  module ApiBlueprint
7
7
  class Drafter4
8
8
  class Yaml
9
- def initialize(prefix, apib_path, drafter_yaml_path)
9
+ def initialize(prefix, drafter_yaml_path)
10
10
  @prefix = prefix
11
- @documentation = if apib_path
12
- YAML.safe_load(`drafter #{apib_path}`)
13
- elsif drafter_yaml_path
14
- YAML.safe_load(File.read(drafter_yaml_path))
15
- end
11
+ @documentation = YAML.safe_load(File.read(drafter_yaml_path))
16
12
  end
17
13
 
18
14
  def groups
@@ -101,15 +97,15 @@ module Tomograph
101
97
  path: "#{@prefix}#{related_actions.first.path}",
102
98
  method: related_actions.first.method,
103
99
  content_type: related_actions.first.content_type,
104
- request: related_actions.first.request,
105
- responses: related_actions.map(&:responses).flatten,
100
+ requests: related_actions.map(&:request).flatten.uniq,
101
+ responses: related_actions.map(&:responses).flatten.uniq,
106
102
  resource: related_actions.first.resource
107
103
  }
108
104
  end
109
105
 
110
106
  def to_tomogram
111
107
  @tomogram ||= actions.inject([]) do |result, action|
112
- result.push(Tomograph::Tomogram::Action.new(action))
108
+ result.push(Tomograph::Tomogram::Action.new(**action))
113
109
  end
114
110
  end
115
111
 
@@ -37,8 +37,8 @@ module Tomograph
37
37
  end
38
38
  return {} unless schema_node
39
39
 
40
- MultiJson.load(schema_node['content'])
41
- rescue MultiJson::ParseError => e
40
+ JSON.parse(schema_node['content'])
41
+ rescue JSON::ParserError => e
42
42
  puts "[Tomograph] Error while parsing #{e}. skipping..."
43
43
  {}
44
44
  end
@@ -5,7 +5,7 @@ module Tomograph
5
5
  class JsonSchema
6
6
  def initialize(prefix, json_schema_path)
7
7
  @prefix = prefix
8
- @documentation = MultiJson.load(File.read(json_schema_path))
8
+ @documentation = JSON.parse(File.read(json_schema_path))
9
9
  end
10
10
 
11
11
  def to_tomogram
@@ -14,7 +14,7 @@ module Tomograph
14
14
  path: "#{@prefix}#{action['path']}",
15
15
  method: action['method'],
16
16
  content_type: action['content-type'],
17
- request: action['request'],
17
+ requests: action['requests'],
18
18
  responses: action['responses'],
19
19
  resource: action['resource']))
20
20
  end
@@ -0,0 +1,91 @@
1
+ require 'tomograph/tomogram/action'
2
+
3
+ module Tomograph
4
+ module OpenApi
5
+ class OpenApi2
6
+ def initialize(prefix, json_schema_path)
7
+ @prefix = prefix
8
+ @documentation = JSON.parse(File.read(json_schema_path))
9
+ end
10
+
11
+ def to_tomogram
12
+ @tomogram ||= @documentation['paths'].inject([]) do |result, action|
13
+ action[1].keys.each do |method|
14
+ result.push(Tomograph::Tomogram::Action.new(
15
+ path: "#{@prefix}#{action[0]}",
16
+ method: method.upcase,
17
+ content_type: '',
18
+ requests: [],
19
+ responses: responses(action[1][method]['responses'], @documentation['definitions']),
20
+ resource: ''))
21
+ end
22
+ result
23
+ end
24
+ end
25
+
26
+ def responses(resp, defi)
27
+ resp.inject([]) do |result, reponse|
28
+ if reponse[1]['schema']
29
+ result.push(
30
+ status: reponse[0],
31
+ body: schema(reponse[1]['schema'], defi),
32
+ 'content-type': ''
33
+ )
34
+ else
35
+ result.push(
36
+ status: reponse[0],
37
+ body: {},
38
+ 'content-type': ''
39
+ )
40
+ end
41
+ end
42
+ end
43
+
44
+ def schema(sche, defi)
45
+ if sche.keys.include?('$ref')
46
+ res = sche.merge('definitions' => {sche["$ref"][14..-1] => defi[sche["$ref"][14..-1]]})
47
+ if defi[sche["$ref"][14..-1]].to_s.include?('$ref')
48
+ keys = defi[sche["$ref"][14..-1]].to_s.split('"').find_all{|word| word.include?('definitions') }
49
+ keys.each do |key|
50
+ res["definitions"].merge!({key[14..-1] => defi[key[14..-1]]})
51
+ end
52
+ end
53
+ res
54
+ else
55
+ if sche.to_s.include?('$ref')
56
+ res = sche.merge('definitions' => {})
57
+ keys = sche.to_s.split('"').find_all{|word| word.include?('definitions') }
58
+ keys.each do |key|
59
+ res["definitions"].merge!({key[14..-1] => defi[key[14..-1]]})
60
+ end
61
+ res
62
+ else
63
+ sche
64
+ end
65
+ end
66
+ end
67
+
68
+ def search_hash(hash, key)
69
+ return hash[key] if hash.assoc(key)
70
+ hash.delete_if{|key, value| value.class != Hash}
71
+ new_hash = Hash.new
72
+ hash.each_value {|values| new_hash.merge!(values)}
73
+ unless new_hash.empty?
74
+ search_hash(new_hash, key)
75
+ end
76
+ end
77
+
78
+ def to_resources
79
+ return @to_resources if @to_resources
80
+
81
+ @to_resources = @documentation.group_by { |action| action['resource'] }
82
+ @to_resources = @to_resources.each_with_object({}) do |(resource, actions), resource_map|
83
+ requests = actions.map do |action|
84
+ "#{action['method']} #{@prefix}#{action['path']}"
85
+ end
86
+ resource_map[resource] = requests
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,118 @@
1
+ require 'tomograph/tomogram/action'
2
+
3
+ module Tomograph
4
+ module OpenApi
5
+ class OpenApi3
6
+ def initialize(prefix, openapi3_yaml_path)
7
+ @prefix = prefix
8
+ @documentation = YAML.load(File.read(openapi3_yaml_path))
9
+ end
10
+
11
+ def to_tomogram
12
+ @tomogram ||= @documentation['paths'].inject([]) do |result, action|
13
+ action[1].keys.each do |method|
14
+ result.push(Tomograph::Tomogram::Action.new(
15
+ path: "#{@prefix}#{action[0]}",
16
+ method: method.upcase,
17
+ content_type: '',
18
+ requests: [],
19
+ responses: responses(action[1][method]['responses'], @documentation['components']['schemas']),
20
+ resource: ''))
21
+ end
22
+ result
23
+ end
24
+ end
25
+
26
+ def responses(resp, defi)
27
+ resp.inject([]) do |result, response|
28
+ if response[1]['content'] == nil
29
+ #TODO 403Forbidden
30
+ result.push(
31
+ status: response[0],
32
+ body: {},
33
+ 'content-type': ''
34
+ )
35
+ elsif response[1]['content'].values[0]['schema']
36
+ result.push(
37
+ status: response[0],
38
+ body: schema(response[1]['content'].values[0]['schema'], defi),
39
+ 'content-type': ''
40
+ )
41
+ else
42
+ result.push(
43
+ status: response[0],
44
+ body: {},
45
+ 'content-type': ''
46
+ )
47
+ end
48
+ end
49
+ end
50
+
51
+ def schema(sche, defi)
52
+ if sche.keys.include?('$ref')
53
+ sche.merge!('components' => {})
54
+ sche['components'].merge!('schemas' => {})
55
+ sche['components']['schemas'].merge!({sche["$ref"][21..-1] => defi[sche["$ref"][21..-1]]})
56
+
57
+ if defi[sche["$ref"][21..-1]].to_s.include?('$ref')
58
+ keys = defi[sche["$ref"][21..-1]].to_s.split('"').find_all{|word| word.include?('#/components/schemas/') }
59
+ keys.each do |key|
60
+ sche['components']['schemas'].merge!({key[21..-1] => defi[key[21..-1]]})
61
+
62
+ if defi[key[21..-1]].to_s.include?('$ref')
63
+ keys2 = defi[key[21..-1]].to_s.split('"').find_all{|word| word.include?('#/components/schemas/') }
64
+ keys2.each do |key2|
65
+ sche['components']['schemas'].merge!({key2[21..-1] => defi[key2[21..-1]]})
66
+
67
+ if defi[key2[21..-1]].to_s.include?('$ref')
68
+ keys3 = defi[key2[21..-1]].to_s.split('"').find_all { |word| word.include?('#/components/schemas/') }.uniq
69
+ keys3.each do |key3|
70
+ sche['components']['schemas'].merge!({ key3[21..-1] => defi[key3[21..-1]] })
71
+ end
72
+ end
73
+
74
+ end
75
+ end
76
+
77
+ end
78
+ end
79
+ sche
80
+
81
+ else
82
+ if sche.to_s.include?('$ref')
83
+ res = sche.merge('definitions' => {})
84
+ keys = sche.to_s.split('"').find_all{|word| word.include?('definitions') }
85
+ keys.each do |key|
86
+ res["definitions"].merge!({key[21..-1] => defi[key[21..-1]]})
87
+ end
88
+ res
89
+ else
90
+ sche
91
+ end
92
+ end
93
+ end
94
+
95
+ def search_hash(hash, key)
96
+ return hash[key] if hash.assoc(key)
97
+ hash.delete_if{|key, value| value.class != Hash}
98
+ new_hash = Hash.new
99
+ hash.each_value {|values| new_hash.merge!(values)}
100
+ unless new_hash.empty?
101
+ search_hash(new_hash, key)
102
+ end
103
+ end
104
+
105
+ def to_resources
106
+ return @to_resources if @to_resources
107
+
108
+ @to_resources = @documentation.group_by { |action| action['resource'] }
109
+ @to_resources = @to_resources.each_with_object({}) do |(resource, actions), resource_map|
110
+ requests = actions.map do |action|
111
+ "#{action['method']} #{@prefix}#{action['path']}"
112
+ end
113
+ resource_map[resource] = requests
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
@@ -1,23 +1,26 @@
1
- require 'multi_json'
1
+ require 'json'
2
2
  require 'tomograph/path'
3
3
  require 'tomograph/api_blueprint/json_schema'
4
- require 'tomograph/api_blueprint/drafter_3/yaml'
5
4
  require 'tomograph/api_blueprint/drafter_4/yaml'
6
5
  require 'tomograph/api_blueprint/crafter/yaml'
6
+ require 'tomograph/openapi/openapi2'
7
+ require 'tomograph/openapi/openapi3'
7
8
 
8
9
  module Tomograph
9
10
  class Tomogram
10
11
  extend Gem::Deprecate
11
12
 
12
- def initialize(prefix: '', apib_path: nil, drafter_yaml_path: nil, tomogram_json_path: nil, drafter_4_apib_path: nil, drafter_4_yaml_path: nil, crafter_apib_path: nil, crafter_yaml_path: nil)
13
+ def initialize(prefix: '', drafter_yaml_path: nil, tomogram_json_path: nil, crafter_yaml_path: nil, openapi2_json_path: nil, openapi3_yaml_path: nil)
13
14
  @documentation = if tomogram_json_path
14
15
  Tomograph::ApiBlueprint::JsonSchema.new(prefix, tomogram_json_path)
15
- elsif drafter_4_yaml_path || drafter_4_apib_path
16
- Tomograph::ApiBlueprint::Drafter4::Yaml.new(prefix, drafter_4_apib_path, drafter_4_yaml_path)
17
- elsif crafter_yaml_path || crafter_apib_path
18
- Tomograph::ApiBlueprint::Crafter::Yaml.new(prefix, crafter_apib_path, crafter_yaml_path)
16
+ elsif crafter_yaml_path
17
+ Tomograph::ApiBlueprint::Crafter::Yaml.new(prefix, crafter_yaml_path)
18
+ elsif openapi2_json_path
19
+ Tomograph::OpenApi::OpenApi2.new(prefix, openapi2_json_path)
20
+ elsif openapi3_yaml_path
21
+ Tomograph::OpenApi::OpenApi3.new(prefix, openapi3_yaml_path)
19
22
  else
20
- Tomograph::ApiBlueprint::Drafter3::Yaml.new(prefix, apib_path, drafter_yaml_path)
23
+ Tomograph::ApiBlueprint::Drafter4::Yaml.new(prefix, drafter_yaml_path)
21
24
  end
22
25
  @prefix = prefix
23
26
  end
@@ -26,13 +29,8 @@ module Tomograph
26
29
  @actions ||= @documentation.to_tomogram
27
30
  end
28
31
 
29
- def to_hash
30
- to_a.map(&:to_hash)
31
- end
32
- deprecate :to_hash, 'to_a with method access', 2018, 8
33
-
34
32
  def to_json
35
- MultiJson.dump(to_a.map(&:to_hash), pretty: true)
33
+ JSON.pretty_generate(to_a.map(&:to_hash))
36
34
  end
37
35
 
38
36
  def find_request(method:, path:)