tomograph 2.5.2 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -51,7 +51,7 @@ module Tomograph
51
51
  end
52
52
  @responses = @responses.map do |response|
53
53
  {
54
- 'status' => response['attributes']['statusCode']['content'],
54
+ 'status' => response['attributes']['statusCode']['content'].to_s,
55
55
  'body' => json_schema(response['content']),
56
56
  'content-type' => response['attributes'].has_key?('headers') ?
57
57
  response['attributes']['headers']['content'][0]['content']['value']['content'] : nil
@@ -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
@@ -51,7 +51,7 @@ module Tomograph
51
51
  end
52
52
  @responses = @responses.map do |response|
53
53
  {
54
- 'status' => response['attributes']['statusCode']['content'],
54
+ 'status' => response['attributes']['statusCode']['content'].to_s,
55
55
  'body' => json_schema(response['content']),
56
56
  'content-type' => response['attributes'].has_key?('headers') ?
57
57
  response['attributes']['headers']['content'][0]['content']['value']['content'] : nil
@@ -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:)