open_api_2_json_schema 0.1.2 → 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: 8f25b393383b6694b23d0306c5a48f91762ba658afbd488c15fa16c40cbfa246
4
- data.tar.gz: 5bc71e2ab8ff4019428686c39b17cc46f8ea5445d4d181af6fca65aa41b8cdd1
3
+ metadata.gz: b098b4e80aac6152b1a1623aa380b89b54e8c4a0c1e9c00c7e94f1f3063da1f8
4
+ data.tar.gz: bed62b780a77c06f4aa3d1576f57bff01926fd913b353b8a5c33cd41a3a971ff
5
5
  SHA512:
6
- metadata.gz: 3263c6c3f5372ff6e6cc93a812ce429ce1ab03d64b1d7eb5cfb23e9291f48b162accca973247dfca2fbc1da1b851089d5a4b21d663cfd0a300fe4fb368f69c1c
7
- data.tar.gz: 828d603767e21eab7b4197d4e3c8217b0cd816464e1726916c9e42571b09c0bcfdff8e1e3622f0f07928f74b67f6d54c87c752ec890dc0902119343181518ce8
6
+ metadata.gz: '03495227e0657a9d7fbb15827fd8cf6089f0d00ba6b3693de0544af09ce053239fe77c98712a34b5713511ce67fdeee580c96bb325c2ff7f53c4b55c98f79f31'
7
+ data.tar.gz: 3c8bcf6d521c462e49d6911f6a374e097140af0f6b6e969a4ceca1a5eae37df6fc20ce2806cac0da2e44fe331e7505a3730ff99fb73e2f960493defa41d41d51
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## [0.2.0] - 2022-12-21
2
+
3
+ - Parsing & deferencing ref using `oas_parser`
4
+
1
5
  ## [0.1.2] - 2022-10-19
2
6
 
3
7
  - Support `discriminator`
data/README.md CHANGED
@@ -34,46 +34,6 @@ schema = {
34
34
  OpenApi2JsonSchema.convert(schema)
35
35
  ```
36
36
 
37
- ### Discriminator
38
-
39
- ```yaml
40
- # Sample YAML file
41
- schema:
42
- discriminator:
43
- propertyName: key
44
- mapping:
45
- value1: 'path-to-file-2.yml'
46
- value2: 'path-to-file-2.yml'
47
- properties:
48
- key:
49
- type: string
50
- enum:
51
- - value1
52
- - value2
53
- ```
54
-
55
- ```json
56
- "schema": {
57
- "properties": {
58
- "key": {
59
- "type": "string",
60
- "enum": ["value1", "value2"]
61
- }
62
- },
63
- "discriminator": {
64
- "propertyName": "name",
65
- "mapping": {
66
- "value1": {
67
- "type": "object"
68
- },
69
- "value2": {
70
- "type": "array"
71
- }
72
- }
73
- }
74
- }
75
- ```
76
-
77
37
  ## Development
78
38
 
79
39
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -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.2"
4
+ VERSION = "0.2.0"
5
5
  end
@@ -2,32 +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
- require_relative 'attribute_handlers/discriminator'
8
8
 
9
9
  module OpenApi2JsonSchema
10
10
  module_function
11
11
 
12
- STRUCTS = ['allOf', 'anyOf', 'oneOf', 'not', 'items', 'additionalProperties', 'schema', 'discriminator']
13
- NOT_SUPPORTED = [
14
- 'nullable', 'readOnly',
15
- 'writeOnly', 'xml', 'externalDocs',
16
- 'example', 'deprecated'
17
- ]
18
- VALID_TYPES = ['integer', 'number', 'string', 'boolean', 'object', 'array', 'null']
19
- VALID_FORMATS = ['date-time', 'email', 'hostname', 'ipv4', 'ipv6', 'uri', 'uri-reference']
20
-
21
- MIN_INT_32 = 0 - 2 ** 31
22
- MAX_INT_32 = 2 ** 31 - 1
23
- MIN_INT_64 = 0 - 2 ** 63
24
- MAX_INT_64 = 2 ** 63 - 1
25
- MIN_FLOAT = 0 - 2 ** 128
26
- MAX_FLOAT = 2 ** 128 - 1
27
- MAX_DOUBLE = 1.7976931348623157e+308
28
- MIN_DOUBLE = 0 - MAX_DOUBLE
29
- BYTE_PATTERN = '^[\\w\\d+\\/=]*$'
30
-
31
12
  class Error < StandardError; end
32
13
  class InvalidTypeError < Error
33
14
  def self.build(type)
@@ -36,125 +17,10 @@ module OpenApi2JsonSchema
36
17
  end
37
18
 
38
19
  def convert_from_file(path)
39
- data = File.read(path)
40
- convert(YAML.load(data))
20
+ convert(OasParser::Definition.resolve(path).raw)
41
21
  end
42
22
 
43
23
  def convert(schema)
44
- convert_schema(schema).tap do |json_schema|
45
- json_schema['$schema'] = 'http://json-schema.org/draft-04/schema#'
46
- end.to_json
47
- end
48
-
49
- def convert_schema(schema)
50
- json_schema = schema.except(*NOT_SUPPORTED)
51
-
52
- schema.slice(*STRUCTS).each do |struct, data|
53
- case data
54
- when Array
55
- if struct == 'allOf'
56
- json_schema[struct] = AttributeHandlers::AllOf.new.call(data)
57
- else
58
- json_schema[struct] = data.map do |item|
59
- convert_schema(item)
60
- end
61
- end
62
- when Hash
63
- if struct == 'discriminator'
64
- json_schema[struct] = AttributeHandlers::Discriminator.new.call(data)
65
- else
66
- json_schema[struct] = convert_schema(data)
67
- end
68
- else
69
- # ignore
70
- end
71
- end
72
-
73
- if schema.key?('properties')
74
- new_properties = convert_properties(schema['properties'])
75
-
76
- if schema['required'].is_a?(Array)
77
- new_required = clean_required(schema['required'], schema['properties'])
78
- json_schema['required'] = new_required if new_required.any?
79
- end
80
-
81
- json_schema['properties'] = new_properties if new_properties.any?
82
- end
83
-
84
- validate_type(schema['type'])
85
-
86
- json_schema.merge!(convert_types(schema))
87
- json_schema.merge!(convert_format(schema))
88
-
89
- json_schema
90
- end
91
-
92
- def validate_type(type)
93
- unless type.nil? || VALID_TYPES.include?(type)
94
- raise InvalidTypeError.build(type)
95
- end
96
- end
97
-
98
- def convert_properties(properties)
99
- return {} unless properties.is_a?(Hash)
100
-
101
- properties.reduce({}) do |result, (key, property)|
102
- next result unless property.is_a?(Hash)
103
-
104
- result.merge(key => convert_schema(property))
105
- end
106
- end
107
-
108
- def convert_types(schema)
109
- if schema['type'] && schema['nullable'] == true
110
- type = [schema['type'], 'null']
111
-
112
- if schema['enum'].is_a?(Array)
113
- {
114
- 'type' => type,
115
- 'enum' => schema['enum'].append(nil)
116
- }
117
- else
118
- { 'type' => type }
119
- end
120
- else
121
- {}
122
- end
123
- end
124
-
125
- def convert_format(schema)
126
- case schema['format']
127
- when 'int32'
128
- {
129
- 'minimum' => [MIN_INT_32, schema['minimum'] || MIN_INT_32].max,
130
- 'maximum' => [MAX_INT_32, schema['maximum'] || MAX_INT_32].min
131
- }
132
- when 'int64'
133
- {
134
- 'minimum' => [MIN_INT_64, schema['minimum'] || MIN_INT_64].max,
135
- 'maximum' => [MAX_INT_64, schema['maximum'] || MAX_INT_64].min
136
- }
137
- when 'float'
138
- {
139
- 'minimum' => [MIN_FLOAT, schema['minimum'] || MIN_FLOAT].max,
140
- 'maximum' => [MAX_FLOAT, schema['maximum'] || MAX_FLOAT].min
141
- }
142
- when 'double'
143
- {
144
- 'minimum' => [MIN_DOUBLE, schema['minimum'] || MIN_DOUBLE].max,
145
- 'maximum' => [MAX_DOUBLE, schema['maximum'] || MAX_DOUBLE].min
146
- }
147
- when 'byte'
148
- { 'pattern' => BYTE_PATTERN }
149
- else
150
- {}
151
- end
152
- end
153
-
154
- def clean_required(required, properties)
155
- required ||= []
156
- properties ||= {}
157
-
158
- properties.slice(*required).keys
24
+ Converter.new.convert(schema)
159
25
  end
160
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.2
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-10-19 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,11 +41,9 @@ files:
27
41
  - Rakefile
28
42
  - bin/console
29
43
  - bin/setup
30
- - lib/attribute_handlers/all_of.rb
31
- - lib/attribute_handlers/discriminator.rb
32
44
  - lib/open_api_2_json_schema.rb
45
+ - lib/open_api_2_json_schema/converter.rb
33
46
  - lib/open_api_2_json_schema/version.rb
34
- - lib/ref_schema_parser.rb
35
47
  homepage: https://github.com/hieuk09/open_api_2_json_schema
36
48
  licenses:
37
49
  - MIT
@@ -46,14 +58,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
46
58
  requirements:
47
59
  - - ">="
48
60
  - !ruby/object:Gem::Version
49
- version: 2.6.0
61
+ version: 2.7.0
50
62
  required_rubygems_version: !ruby/object:Gem::Requirement
51
63
  requirements:
52
64
  - - ">="
53
65
  - !ruby/object:Gem::Version
54
66
  version: '0'
55
67
  requirements: []
56
- rubygems_version: 3.0.8
68
+ rubygems_version: 3.3.7
57
69
  signing_key:
58
70
  specification_version: 4
59
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,18 +0,0 @@
1
- require_relative "../ref_schema_parser"
2
-
3
- module OpenApi2JsonSchema
4
- module AttributeHandlers
5
- class Discriminator
6
- def call(discriminator_schema)
7
- raise "discriminator schema must be a Hash" unless discriminator_schema.is_a?(Hash)
8
-
9
- mapping = discriminator_schema.fetch("mapping")
10
- mapping.each do |key, file_path|
11
- mapping[key] = OpenApi2JsonSchema::RefSchemaParser.new.call(file_path)
12
- end
13
-
14
- discriminator_schema
15
- end
16
- end
17
- end
18
- 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