open_api_2_json_schema 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3b7f9dc1848c8bc1810adba623e3a909937e781a8d916530f008791d9fafbb03
4
- data.tar.gz: 17847b2a3ae5114c7a331e811c59dc062d018aa8646b109c099fb35260d497db
3
+ metadata.gz: b098b4e80aac6152b1a1623aa380b89b54e8c4a0c1e9c00c7e94f1f3063da1f8
4
+ data.tar.gz: bed62b780a77c06f4aa3d1576f57bff01926fd913b353b8a5c33cd41a3a971ff
5
5
  SHA512:
6
- metadata.gz: 81d9359bc0f47a7ce8f7660af70bb44190b0c241f33b1031b1eeb04d51358dae4962f7259f83dbed511caa8a62bdac137db5050932b0d3f891d245d963d0b9b7
7
- data.tar.gz: 8019ae57689e5386956cd2222c1f4a457ba37e9dd03942095486fec12d60297bddcb8fb935db709ab32041e09530af2a3dbb790195565eed3e76db1720c62e66
6
+ metadata.gz: '03495227e0657a9d7fbb15827fd8cf6089f0d00ba6b3693de0544af09ce053239fe77c98712a34b5713511ce67fdeee580c96bb325c2ff7f53c4b55c98f79f31'
7
+ data.tar.gz: 3c8bcf6d521c462e49d6911f6a374e097140af0f6b6e969a4ceca1a5eae37df6fc20ce2806cac0da2e44fe331e7505a3730ff99fb73e2f960493defa41d41d51
data/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ ## [0.2.0] - 2022-12-21
2
+
3
+ - Parsing & deferencing ref using `oas_parser`
4
+
5
+ ## [0.1.2] - 2022-10-19
6
+
7
+ - Support `discriminator`
8
+
1
9
  ## [0.1.1] - 2022-09-23
2
10
 
3
11
  - Support `$ref` and `allOf`
@@ -0,0 +1,121 @@
1
+ module OpenApi2JsonSchema
2
+ class Converter
3
+ NOT_SUPPORTED = [
4
+ 'nullable', 'readOnly',
5
+ 'writeOnly', 'xml', 'externalDocs',
6
+ 'example', 'deprecated'
7
+ ]
8
+ STRUCTS = ['allOf', 'anyOf', 'oneOf', 'not', 'items', 'additionalProperties', 'schema', 'discriminator']
9
+ VALID_TYPES = ['integer', 'number', 'string', 'boolean', 'object', 'array', 'null']
10
+ VALID_FORMATS = ['date-time', 'email', 'hostname', 'ipv4', 'ipv6', 'uri', 'uri-reference']
11
+
12
+ MIN_INT_32 = 0 - 2 ** 31
13
+ MAX_INT_32 = 2 ** 31 - 1
14
+ MIN_INT_64 = 0 - 2 ** 63
15
+ MAX_INT_64 = 2 ** 63 - 1
16
+ MIN_FLOAT = 0 - 2 ** 128
17
+ MAX_FLOAT = 2 ** 128 - 1
18
+ MAX_DOUBLE = 1.7976931348623157e+308
19
+ MIN_DOUBLE = 0 - MAX_DOUBLE
20
+ BYTE_PATTERN = '^[\\w\\d+\\/=]*$'
21
+
22
+ def convert(schema)
23
+ convert_schema(schema).tap do |json_schema|
24
+ json_schema['$schema'] = 'http://json-schema.org/draft-04/schema#'
25
+ end.to_json
26
+ end
27
+
28
+ private
29
+
30
+ def convert_schema(schema)
31
+ json_schema = schema.except(*NOT_SUPPORTED)
32
+
33
+ if schema.key?('properties')
34
+ new_properties = convert_properties(schema['properties'])
35
+
36
+ if schema['required'].is_a?(Array)
37
+ new_required = clean_required(schema['required'], schema['properties'])
38
+ json_schema['required'] = new_required if new_required.any?
39
+ end
40
+
41
+ json_schema['properties'] = new_properties if new_properties.any?
42
+ end
43
+
44
+ validate_type(schema['type'])
45
+
46
+ json_schema.merge!(convert_types(schema))
47
+ json_schema.merge!(convert_format(schema))
48
+
49
+ json_schema
50
+ end
51
+
52
+ def validate_type(type)
53
+ unless type.nil? || VALID_TYPES.include?(type)
54
+ raise InvalidTypeError.build(type)
55
+ end
56
+ end
57
+
58
+ def convert_properties(properties)
59
+ return {} unless properties.is_a?(Hash)
60
+
61
+ properties.reduce({}) do |result, (key, property)|
62
+ next result unless property.is_a?(Hash)
63
+
64
+ result.merge(key => convert_schema(property))
65
+ end
66
+ end
67
+
68
+ def convert_types(schema)
69
+ if schema['type'] && schema['nullable'] == true
70
+ type = [schema['type'], 'null']
71
+
72
+ if schema['enum'].is_a?(Array)
73
+ {
74
+ 'type' => type,
75
+ 'enum' => schema['enum'].append(nil)
76
+ }
77
+ else
78
+ { 'type' => type }
79
+ end
80
+ else
81
+ {}
82
+ end
83
+ end
84
+
85
+ def convert_format(schema)
86
+ case schema['format']
87
+ when 'int32'
88
+ {
89
+ 'minimum' => [MIN_INT_32, schema['minimum'] || MIN_INT_32].max,
90
+ 'maximum' => [MAX_INT_32, schema['maximum'] || MAX_INT_32].min
91
+ }
92
+ when 'int64'
93
+ {
94
+ 'minimum' => [MIN_INT_64, schema['minimum'] || MIN_INT_64].max,
95
+ 'maximum' => [MAX_INT_64, schema['maximum'] || MAX_INT_64].min
96
+ }
97
+ when 'float'
98
+ {
99
+ 'minimum' => [MIN_FLOAT, schema['minimum'] || MIN_FLOAT].max,
100
+ 'maximum' => [MAX_FLOAT, schema['maximum'] || MAX_FLOAT].min
101
+ }
102
+ when 'double'
103
+ {
104
+ 'minimum' => [MIN_DOUBLE, schema['minimum'] || MIN_DOUBLE].max,
105
+ 'maximum' => [MAX_DOUBLE, schema['maximum'] || MAX_DOUBLE].min
106
+ }
107
+ when 'byte'
108
+ { 'pattern' => BYTE_PATTERN }
109
+ else
110
+ {}
111
+ end
112
+ end
113
+
114
+ def clean_required(required, properties)
115
+ required ||= []
116
+ properties ||= {}
117
+
118
+ properties.slice(*required).keys
119
+ end
120
+ end
121
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OpenApi2JsonSchema
4
- VERSION = "0.1.1"
4
+ VERSION = "0.2.0"
5
5
  end
@@ -2,31 +2,13 @@
2
2
 
3
3
  require 'json'
4
4
  require 'yaml'
5
+ require 'oas_parser'
6
+ require_relative "open_api_2_json_schema/converter"
5
7
  require_relative "open_api_2_json_schema/version"
6
- require_relative 'attribute_handlers/all_of'
7
8
 
8
9
  module OpenApi2JsonSchema
9
10
  module_function
10
11
 
11
- STRUCTS = ['allOf', 'anyOf', 'oneOf', 'not', 'items', 'additionalProperties', 'schema']
12
- NOT_SUPPORTED = [
13
- 'nullable', 'discriminator', 'readOnly',
14
- 'writeOnly', 'xml', 'externalDocs',
15
- 'example', 'deprecated'
16
- ]
17
- VALID_TYPES = ['integer', 'number', 'string', 'boolean', 'object', 'array', 'null']
18
- VALID_FORMATS = ['date-time', 'email', 'hostname', 'ipv4', 'ipv6', 'uri', 'uri-reference']
19
-
20
- MIN_INT_32 = 0 - 2 ** 31
21
- MAX_INT_32 = 2 ** 31 - 1
22
- MIN_INT_64 = 0 - 2 ** 63
23
- MAX_INT_64 = 2 ** 63 - 1
24
- MIN_FLOAT = 0 - 2 ** 128
25
- MAX_FLOAT = 2 ** 128 - 1
26
- MAX_DOUBLE = 1.7976931348623157e+308
27
- MIN_DOUBLE = 0 - MAX_DOUBLE
28
- BYTE_PATTERN = '^[\\w\\d+\\/=]*$'
29
-
30
12
  class Error < StandardError; end
31
13
  class InvalidTypeError < Error
32
14
  def self.build(type)
@@ -35,121 +17,10 @@ module OpenApi2JsonSchema
35
17
  end
36
18
 
37
19
  def convert_from_file(path)
38
- data = File.read(path)
39
- convert(YAML.load(data))
20
+ convert(OasParser::Definition.resolve(path).raw)
40
21
  end
41
22
 
42
23
  def convert(schema)
43
- convert_schema(schema).tap do |json_schema|
44
- json_schema['$schema'] = 'http://json-schema.org/draft-04/schema#'
45
- end.to_json
46
- end
47
-
48
- def convert_schema(schema)
49
- json_schema = schema.except(*NOT_SUPPORTED)
50
-
51
- schema.slice(*STRUCTS).each do |struct, data|
52
- case data
53
- when Array
54
- if struct == 'allOf'
55
- json_schema[struct] = AttributeHandlers::AllOf.new.call(data)
56
- else
57
- json_schema[struct] = data.map do |item|
58
- convert_schema(item)
59
- end
60
- end
61
- when Hash
62
- json_schema[struct] = convert_schema(data)
63
- else
64
- # ignore
65
- end
66
- end
67
-
68
- if schema.key?('properties')
69
- new_properties = convert_properties(schema['properties'])
70
-
71
- if schema['required'].is_a?(Array)
72
- new_required = clean_required(schema['required'], schema['properties'])
73
- json_schema['required'] = new_required if new_required.any?
74
- end
75
-
76
- json_schema['properties'] = new_properties if new_properties.any?
77
- end
78
-
79
- validate_type(schema['type'])
80
-
81
- json_schema.merge!(convert_types(schema))
82
- json_schema.merge!(convert_format(schema))
83
-
84
- json_schema
85
- end
86
-
87
- def validate_type(type)
88
- unless type.nil? || VALID_TYPES.include?(type)
89
- raise InvalidTypeError.build(type)
90
- end
91
- end
92
-
93
- def convert_properties(properties)
94
- return {} unless properties.is_a?(Hash)
95
-
96
- properties.reduce({}) do |result, (key, property)|
97
- next result unless property.is_a?(Hash)
98
-
99
- result.merge(key => convert_schema(property))
100
- end
101
- end
102
-
103
- def convert_types(schema)
104
- if schema['type'] && schema['nullable'] == true
105
- type = [schema['type'], 'null']
106
-
107
- if schema['enum'].is_a?(Array)
108
- {
109
- 'type' => type,
110
- 'enum' => schema['enum'].append(nil)
111
- }
112
- else
113
- { 'type' => type }
114
- end
115
- else
116
- {}
117
- end
118
- end
119
-
120
- def convert_format(schema)
121
- case schema['format']
122
- when 'int32'
123
- {
124
- 'minimum' => [MIN_INT_32, schema['minimum'] || MIN_INT_32].max,
125
- 'maximum' => [MAX_INT_32, schema['maximum'] || MAX_INT_32].min
126
- }
127
- when 'int64'
128
- {
129
- 'minimum' => [MIN_INT_64, schema['minimum'] || MIN_INT_64].max,
130
- 'maximum' => [MAX_INT_64, schema['maximum'] || MAX_INT_64].min
131
- }
132
- when 'float'
133
- {
134
- 'minimum' => [MIN_FLOAT, schema['minimum'] || MIN_FLOAT].max,
135
- 'maximum' => [MAX_FLOAT, schema['maximum'] || MAX_FLOAT].min
136
- }
137
- when 'double'
138
- {
139
- 'minimum' => [MIN_DOUBLE, schema['minimum'] || MIN_DOUBLE].max,
140
- 'maximum' => [MAX_DOUBLE, schema['maximum'] || MAX_DOUBLE].min
141
- }
142
- when 'byte'
143
- { 'pattern' => BYTE_PATTERN }
144
- else
145
- {}
146
- end
147
- end
148
-
149
- def clean_required(required, properties)
150
- required ||= []
151
- properties ||= {}
152
-
153
- properties.slice(*required).keys
24
+ Converter.new.convert(schema)
154
25
  end
155
26
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: open_api_2_json_schema
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - hieuk09
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-09-23 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2022-12-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: oas_parser
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.25'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.25'
13
27
  description: 'Due to the OpenAPI v3.0 and JSON Schema discrepancy, you can use this
14
28
  JS library to convert OpenAPI Schema objects to proper JSON Schema. '
15
29
  email:
@@ -27,10 +41,9 @@ files:
27
41
  - Rakefile
28
42
  - bin/console
29
43
  - bin/setup
30
- - lib/attribute_handlers/all_of.rb
31
44
  - lib/open_api_2_json_schema.rb
45
+ - lib/open_api_2_json_schema/converter.rb
32
46
  - lib/open_api_2_json_schema/version.rb
33
- - lib/ref_schema_parser.rb
34
47
  homepage: https://github.com/hieuk09/open_api_2_json_schema
35
48
  licenses:
36
49
  - MIT
@@ -45,14 +58,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
45
58
  requirements:
46
59
  - - ">="
47
60
  - !ruby/object:Gem::Version
48
- version: 2.6.0
61
+ version: 2.7.0
49
62
  required_rubygems_version: !ruby/object:Gem::Requirement
50
63
  requirements:
51
64
  - - ">="
52
65
  - !ruby/object:Gem::Version
53
66
  version: '0'
54
67
  requirements: []
55
- rubygems_version: 3.0.8
68
+ rubygems_version: 3.3.7
56
69
  signing_key:
57
70
  specification_version: 4
58
71
  summary: OpenAPI v3.0 schema to JSON Schema draft 4 converter
@@ -1,21 +0,0 @@
1
- require_relative '../ref_schema_parser'
2
-
3
- module OpenApi2JsonSchema
4
- module AttributeHandlers
5
- class AllOf
6
- def call(all_of_schemas)
7
- raise 'allOf schema must be an Array' unless all_of_schemas.is_a?(Array)
8
-
9
- all_of_schemas.each_with_index.map do |schema, index|
10
- raise "Invalid schema: allOf[#{index}]" unless schema.is_a?(Hash)
11
-
12
- if schema['$ref']
13
- OpenApi2JsonSchema::RefSchemaParser.new.call(schema['$ref'])
14
- else
15
- schema
16
- end
17
- end
18
- end
19
- end
20
- end
21
- end
@@ -1,35 +0,0 @@
1
- require 'yaml'
2
-
3
- module OpenApi2JsonSchema
4
- class RefSchemaParser
5
- def call(ref_path)
6
- file_path, fragments = normalize_path(ref_path)
7
- ref_schema = load_file(file_path)
8
- fragment_schema = ref_schema
9
-
10
- if fragments
11
- fragments.split('/').each do |fragment|
12
- if fragment && fragment != '' && fragment_schema[fragment]
13
- fragment_schema = fragment_schema[fragment]
14
- end
15
- end
16
- end
17
-
18
- fragment_schema
19
- end
20
-
21
- private
22
-
23
- def normalize_path(path)
24
- temp_path = path.split('#')
25
- raise 'Invalid reference path' if temp_path.size > 2
26
-
27
- temp_path
28
- end
29
-
30
- def load_file(path)
31
- data = File.read(path)
32
- YAML.safe_load(data)
33
- end
34
- end
35
- end