open_api_2_json_schema 0.1.1 → 0.2.0

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.
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