kwalify_to_json_schema 0.1.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 +7 -0
- data/bin/kwalify_to_json_schema +4 -0
- data/home/sylvain/kwalify_to_json_schema/lib/kwalify_to_json_schema.rb +11 -0
- data/home/sylvain/kwalify_to_json_schema/lib/kwalify_to_json_schema/cli.rb +108 -0
- data/home/sylvain/kwalify_to_json_schema/lib/kwalify_to_json_schema/converter.rb +178 -0
- data/home/sylvain/kwalify_to_json_schema/lib/kwalify_to_json_schema/custom_processing.rb +14 -0
- data/home/sylvain/kwalify_to_json_schema/lib/kwalify_to_json_schema/kwalify_to_json_schema.rb +51 -0
- data/home/sylvain/kwalify_to_json_schema/lib/kwalify_to_json_schema/limitations.rb +8 -0
- data/home/sylvain/kwalify_to_json_schema/lib/kwalify_to_json_schema/options.rb +74 -0
- data/home/sylvain/kwalify_to_json_schema/lib/kwalify_to_json_schema/serialization.rb +45 -0
- data/home/sylvain/kwalify_to_json_schema/test/custom_processing.rb +14 -0
- data/home/sylvain/kwalify_to_json_schema/test/test_kwalify_to_json_schema.rb +75 -0
- data/home/sylvain/kwalify_to_json_schema/tools/all.rb +4 -0
- data/home/sylvain/kwalify_to_json_schema/tools/doc_template.rb +13 -0
- data/home/sylvain/kwalify_to_json_schema/tools/limitations.rb +19 -0
- data/home/sylvain/kwalify_to_json_schema/tools/options.rb +96 -0
- metadata +128 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: dbf127bd97917313787d2e8627ab38a3ef403edbf32bf77af9b1be706525a71e
|
4
|
+
data.tar.gz: 2b055ce7452bd80faa88b40c33d11644779f2ada1a2b7b63a0c7a1470fe55a2c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 03533367dd66aed289370d6aa7bfe03578dab440c59498bc030e8e4179d53917577e7064f12bc5e2ca30f32fda464fabf22c47424a70741a209669fef170d357
|
7
|
+
data.tar.gz: 00a4daafa64abeebac771e70b8809ad3475a8e97ca4bc8d6dc26a92735e25b2cb9ab573b876d79127e87146b5efd48c60206b11b0ad25edeee71b00493b24c0a
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require "json"
|
2
|
+
require "yaml"
|
3
|
+
require "thor"
|
4
|
+
require "coderay"
|
5
|
+
require_relative "kwalify_to_json_schema/kwalify_to_json_schema"
|
6
|
+
require_relative "kwalify_to_json_schema/serialization"
|
7
|
+
require_relative "kwalify_to_json_schema/options"
|
8
|
+
require_relative "kwalify_to_json_schema/limitations"
|
9
|
+
require_relative "kwalify_to_json_schema/converter"
|
10
|
+
require_relative "kwalify_to_json_schema/custom_processing"
|
11
|
+
require_relative "kwalify_to_json_schema/cli"
|
@@ -0,0 +1,108 @@
|
|
1
|
+
module KwalifyToJsonSchema
|
2
|
+
class Cli < Thor
|
3
|
+
###############################################################################################################
|
4
|
+
CUSTOM_PROCESSING_CODE_DOC = <<~CODE
|
5
|
+
class CustomProcessing
|
6
|
+
# The method will be called before conversion allowing to customize the input Kwalify schema.
|
7
|
+
# The implementation have to return the modified schema.
|
8
|
+
# The default implemention don't modify the schema.
|
9
|
+
# @param kwalify_schema {Hash}
|
10
|
+
# @return modified schema
|
11
|
+
def preprocess(kwalify_schema)
|
12
|
+
# TODO return modified schema
|
13
|
+
end
|
14
|
+
|
15
|
+
# The method will be called after the conversion allowing to customize the output JSON schema.
|
16
|
+
# The implementation have to return the modified schema.
|
17
|
+
# The default implemention don't modify the schema.
|
18
|
+
# @param json_schema {Hash}
|
19
|
+
# @return modified schema
|
20
|
+
def postprocess(json_schema)
|
21
|
+
# TODO return modified schema
|
22
|
+
end
|
23
|
+
end
|
24
|
+
CODE
|
25
|
+
|
26
|
+
desc "convert KWALIFY_SCHEMA_FILE, RESULT_FILE",
|
27
|
+
"Convert a Kwalify schema file to a JSON schema file. The result file extension will decide the format: .json or .yaml"
|
28
|
+
option :issues_to_description,
|
29
|
+
:type => :boolean,
|
30
|
+
:default => false,
|
31
|
+
:desc => "Will append any conversion issue to the schema description"
|
32
|
+
option :custom_processing,
|
33
|
+
:type => :string,
|
34
|
+
:desc => <<~DESC
|
35
|
+
Allows to provide a pre/post processing file on handled schemas.
|
36
|
+
The given Ruby file have to provide the following class:
|
37
|
+
#{CodeRay.scan(CUSTOM_PROCESSING_CODE_DOC, :ruby).encode :terminal}
|
38
|
+
DESC
|
39
|
+
|
40
|
+
def convert(kwalify_schema_file, result_file)
|
41
|
+
opts = {
|
42
|
+
Options::ISSUES_TO_DESCRIPTION => options[:issues_to_description],
|
43
|
+
Options::CUSTOM_PROCESSING => custom_processing(options),
|
44
|
+
}
|
45
|
+
KwalifyToJsonSchema.convert_file(kwalify_schema_file, result_file, opts)
|
46
|
+
end
|
47
|
+
|
48
|
+
###############################################################################################################
|
49
|
+
|
50
|
+
desc "convert_dir KWALIFY_SCHEMA_DIR, RESULT_DIR",
|
51
|
+
"Convert all the Kwalify schema from a directory to a JSON schema"
|
52
|
+
option :issues_to_description,
|
53
|
+
:type => :boolean,
|
54
|
+
:default => false,
|
55
|
+
:desc => "Will append any conversion issue to the schema description"
|
56
|
+
option :format,
|
57
|
+
:type => :string,
|
58
|
+
:enum => ["json", "yaml"],
|
59
|
+
:default => "json",
|
60
|
+
:desc => "Select the output file format"
|
61
|
+
option :recursive,
|
62
|
+
:type => :boolean,
|
63
|
+
:default => false,
|
64
|
+
:desc => "Process files recursively",
|
65
|
+
:long_desc => ""
|
66
|
+
option :custom_processing,
|
67
|
+
:type => :string,
|
68
|
+
:desc => <<~DESC
|
69
|
+
Allows to provide a pre/post processing file on handled schemas.
|
70
|
+
The given Ruby file have to provide the following class:
|
71
|
+
#{CodeRay.scan(CUSTOM_PROCESSING_CODE_DOC, :ruby).encode :terminal}
|
72
|
+
DESC
|
73
|
+
|
74
|
+
def convert_dir(kwalify_schema_dir, result_dir)
|
75
|
+
opts = {
|
76
|
+
Options::ISSUES_TO_DESCRIPTION => options[:issues_to_description],
|
77
|
+
Options::CUSTOM_PROCESSING => custom_processing(options),
|
78
|
+
}
|
79
|
+
|
80
|
+
path = [kwalify_schema_dir, options["recursive"] ? "**" : nil, "*.yaml"].compact
|
81
|
+
Dir.glob(File.join(*path)).each { |kwalify_schema_file|
|
82
|
+
result_file = File.join(result_dir, File.basename(kwalify_schema_file, File.extname(kwalify_schema_file))) + ".#{options["format"]}"
|
83
|
+
KwalifyToJsonSchema.convert_file(kwalify_schema_file, result_file, opts)
|
84
|
+
}
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.exit_on_failure?
|
88
|
+
false
|
89
|
+
end
|
90
|
+
|
91
|
+
private
|
92
|
+
|
93
|
+
def custom_processing(options)
|
94
|
+
pf = options[:custom_processing]
|
95
|
+
custom_processing = nil
|
96
|
+
if pf
|
97
|
+
require File.expand_path(pf)
|
98
|
+
begin
|
99
|
+
processing_class = Object.const_get :CustomProcessing
|
100
|
+
custom_processing = processing_class.new
|
101
|
+
rescue NameError => e
|
102
|
+
raise "The 'CustomProcessing' module must be defined in #{pf}"
|
103
|
+
end
|
104
|
+
end
|
105
|
+
custom_processing
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,178 @@
|
|
1
|
+
module KwalifyToJsonSchema
|
2
|
+
|
3
|
+
# Heart of conversion implementation
|
4
|
+
#
|
5
|
+
# Example of use:
|
6
|
+
#
|
7
|
+
# kwalify_schema = YAML.load(File.read("kwalify_schema.yaml"))
|
8
|
+
#
|
9
|
+
# converter = KwalifyToJsonSchema::Converter.new(options)
|
10
|
+
# json_schema = converter.exec(kwalify_schema)
|
11
|
+
#
|
12
|
+
# File.write("json_schema.json", JSON.pretty_generate(json_schema))
|
13
|
+
class Converter
|
14
|
+
SCHEMA = "http://json-schema.org/draft-07/schema#"
|
15
|
+
|
16
|
+
# The options given used to initialized the converter
|
17
|
+
attr_reader :options
|
18
|
+
# Give the list of issues encontered while converting as array of strings.
|
19
|
+
attr_reader :issues
|
20
|
+
|
21
|
+
# Converter options:
|
22
|
+
# | Name | Type | Default value| Description |
|
23
|
+
# |-----------------------|--------|--------------|-----------------------------------------------------|
|
24
|
+
# | :id | String | nil | The JSON schema identifier |
|
25
|
+
# | :title | String | nil | The JSON schema title |
|
26
|
+
# | :description | String | nil | The JSON schema description |
|
27
|
+
# | :issues_to_description| Boolean| false | To append the issuses to the JSON schema description|
|
28
|
+
# | :custom_processing | Object | nil | To customize the conversion |
|
29
|
+
# --
|
30
|
+
def initialize(options_hash = {})
|
31
|
+
@options = Options.new(options_hash)
|
32
|
+
@issues = []
|
33
|
+
end
|
34
|
+
|
35
|
+
# Execute the conversion process
|
36
|
+
# @param kwalify_schema Kwalify schema as Hash or YAML string to be converted as Hash
|
37
|
+
# @return JSON schema as Hash
|
38
|
+
def exec(kwalify_schema)
|
39
|
+
kwalify_schema = YAML.load(kwalify_schema) if kwalify_schema.is_a? String
|
40
|
+
kwalify_schema = preprocess(kwalify_schema.dup)
|
41
|
+
|
42
|
+
json_schema = process(root, kwalify_schema)
|
43
|
+
if issues.any? && options.issues_to_description?
|
44
|
+
description = json_schema["description"] ||= ""
|
45
|
+
description << "Issues when converting from Kwalify:\n"
|
46
|
+
description << issues.map { |issue| "* #{issue}" }.join("\n")
|
47
|
+
end
|
48
|
+
|
49
|
+
postprocess(json_schema)
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def root
|
55
|
+
{
|
56
|
+
"$schema" => SCHEMA,
|
57
|
+
"$id" => options.id,
|
58
|
+
"title" => options.title,
|
59
|
+
"description" => options.description,
|
60
|
+
}.reject { |k, v| v.nil? }
|
61
|
+
end
|
62
|
+
|
63
|
+
# @param target Json schema target
|
64
|
+
# @param kelem Kwalify element
|
65
|
+
def process(target, kelem)
|
66
|
+
|
67
|
+
# Add description if available
|
68
|
+
target["description"] = kelem["desc"] if kelem["desc"]
|
69
|
+
|
70
|
+
case ktype = kelem["type"]
|
71
|
+
when "map"
|
72
|
+
target["type"] = "object"
|
73
|
+
target["additionalProperties"] = false
|
74
|
+
mapping = kelem["mapping"]
|
75
|
+
required = []
|
76
|
+
if mapping.is_a? Hash
|
77
|
+
properties = target["properties"] = {}
|
78
|
+
mapping.each_pair { |name, e|
|
79
|
+
process(properties[name] = {}, e)
|
80
|
+
required << name if e["required"] == true
|
81
|
+
}
|
82
|
+
target["required"] = required unless required.empty?
|
83
|
+
end
|
84
|
+
when "seq"
|
85
|
+
target["type"] = "array"
|
86
|
+
sequence = kelem["sequence"]
|
87
|
+
if sequence.is_a? Array
|
88
|
+
process(target["items"] = {}, sequence.first)
|
89
|
+
end
|
90
|
+
when "str"
|
91
|
+
target["type"] = "string"
|
92
|
+
when "int"
|
93
|
+
target["type"] = "integer"
|
94
|
+
when "float", "number"
|
95
|
+
target["type"] = "number"
|
96
|
+
when "text"
|
97
|
+
# Use one of
|
98
|
+
target["oneOf"] = [
|
99
|
+
{ "type" => "string" },
|
100
|
+
{ "type" => "number" },
|
101
|
+
]
|
102
|
+
when "bool"
|
103
|
+
target["type"] = "boolean"
|
104
|
+
when "date"
|
105
|
+
# TODO
|
106
|
+
new_issue Limitations::DATE_TYPE_NOT_IMPLEMENTED
|
107
|
+
when "time"
|
108
|
+
# TODO
|
109
|
+
new_issue Limitations::TIME_TYPE_NOT_IMPLEMENTED
|
110
|
+
when "timestamp"
|
111
|
+
# TODO
|
112
|
+
new_issue Limitations::TIMESTAMP_TYPE_NOT_IMPLEMENTED
|
113
|
+
when "scalar"
|
114
|
+
# Use one of
|
115
|
+
target["oneOf"] = [
|
116
|
+
{ "type" => "string" },
|
117
|
+
{ "type" => "number" },
|
118
|
+
{ "type" => "integer" },
|
119
|
+
{ "type" => "boolean" },
|
120
|
+
]
|
121
|
+
when "any"
|
122
|
+
# Don't put type
|
123
|
+
else
|
124
|
+
new_issue("Unknown Kwalify type #{ktype}")
|
125
|
+
end
|
126
|
+
|
127
|
+
target["enum"] = kelem["enum"] if kelem["enum"]
|
128
|
+
if range = kelem["range"]
|
129
|
+
target["minimum"] = range["min"] if range["min"]
|
130
|
+
target["maximum"] = range["max"] if range["max"]
|
131
|
+
if range["min-ex"]
|
132
|
+
target["minimum"] = range["min-ex"]
|
133
|
+
target["exclusiveMinimum"] = true
|
134
|
+
end
|
135
|
+
if range["max-ex"]
|
136
|
+
target["maximum"] = range["max-ex"]
|
137
|
+
target["exclusiveMaximum"] = true
|
138
|
+
end
|
139
|
+
end
|
140
|
+
if pa = kelem["pattern"]
|
141
|
+
# Remove leading and trailing slash
|
142
|
+
target["pattern"] = pa.sub(/^\//, "").sub(/\/$/, "")
|
143
|
+
end
|
144
|
+
|
145
|
+
if length = kelem["length"]
|
146
|
+
case ktype
|
147
|
+
when "str", "text"
|
148
|
+
target["minLength"] = length["min"] if length["min"]
|
149
|
+
target["maxLength"] = length["max"] if length["max"]
|
150
|
+
target["minLength"] = length["min-ex"] + 1 if length["min-ex"]
|
151
|
+
target["maxLength"] = length["max-ex"] + -1 if length["max-ex"]
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
new_issue "'unique' is not supported by JSON Schema" if kelem["unique"]
|
156
|
+
|
157
|
+
target
|
158
|
+
end
|
159
|
+
|
160
|
+
def preprocess(kwalify_schema)
|
161
|
+
ep = options.custom_processing
|
162
|
+
return kwalify_schema unless ep.respond_to? :preprocess
|
163
|
+
kwalify_schema = ep.preprocess(kwalify_schema.dup)
|
164
|
+
end
|
165
|
+
|
166
|
+
def postprocess(json_schema)
|
167
|
+
ep = options.custom_processing
|
168
|
+
return json_schema unless ep.respond_to? :postprocess
|
169
|
+
ep.postprocess(json_schema)
|
170
|
+
end
|
171
|
+
|
172
|
+
def new_issue(description)
|
173
|
+
@issues << description
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
|
178
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module KwalifyToJsonSchema
|
2
|
+
# Template class for custom processing
|
3
|
+
class CustomProcessing
|
4
|
+
# The method will be called before conversion allowing to customize the input Kwalify schema.
|
5
|
+
# The implementation have to return the modified schema.
|
6
|
+
# The default implemention don't modify the schema.
|
7
|
+
def preproces(kwalify_schema); kwalify_schema; end
|
8
|
+
|
9
|
+
# The method will be called after the conversion allowing to customize the output JSON schema.
|
10
|
+
# The implementation have to return the modified schema.
|
11
|
+
# The default implemention don't modify the schema.
|
12
|
+
def postprocess(json_schema); json_schema; end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module KwalifyToJsonSchema
|
2
|
+
|
3
|
+
# Convert a Kwalify schema file to JSON .schema.
|
4
|
+
# The destination file can be JSON or YAML.
|
5
|
+
# The file extension is used to select the format: .json or .yaml.
|
6
|
+
# Other extension will fallback to JSON.
|
7
|
+
# Converter options:
|
8
|
+
# | Name | Type | Default value| Description |
|
9
|
+
# |-----------------------|--------|--------------|-----------------------------------------------------|
|
10
|
+
# | :id | String | nil | The JSON schema identifier |
|
11
|
+
# | :title | String | nil | The JSON schema title |
|
12
|
+
# | :description | String | nil | The JSON schema description |
|
13
|
+
# | :issues_to_description| Boolean| false | To append the issuses to the JSON schema description|
|
14
|
+
# | :custom_processing | Object | nil | To customize the conversion |
|
15
|
+
# --
|
16
|
+
# @param source Path to Kwalify YAML schema
|
17
|
+
# @param dest Path to resulting JSON schema
|
18
|
+
def self.convert_file(source, dest, options = {})
|
19
|
+
# Get a converter
|
20
|
+
converter = Converter.new(options)
|
21
|
+
# Convert
|
22
|
+
converted = converter.exec(Serialization.deserialize_from_file(source))
|
23
|
+
# Serialize
|
24
|
+
Serialization.serialize_to_file(dest, converted)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Convert a Kwalify schema string to JSON .schema.
|
28
|
+
# The source and destination strings can be JSON or YAML.
|
29
|
+
# Other extension will fallback to JSON.
|
30
|
+
# Converter options:
|
31
|
+
# | Name | Type | Default value| Description |
|
32
|
+
# |-----------------------|--------|--------------|-----------------------------------------------------|
|
33
|
+
# | :id | String | nil | The JSON schema identifier |
|
34
|
+
# | :title | String | nil | The JSON schema title |
|
35
|
+
# | :description | String | nil | The JSON schema description |
|
36
|
+
# | :issues_to_description| Boolean| false | To append the issuses to the JSON schema description|
|
37
|
+
# | :custom_processing | Object | nil | To customize the conversion |
|
38
|
+
# --
|
39
|
+
# @param kwalify_schema Kwalify schema as YAML or JSON
|
40
|
+
# @param source_format format of the source schema
|
41
|
+
# @param dest_format format of the destination schema
|
42
|
+
# @param options
|
43
|
+
def self.convert_string(kwalify_schema, source_format = "yaml", dest_format = "json", options = {})
|
44
|
+
# Get a converter
|
45
|
+
converter = Converter.new(options)
|
46
|
+
# Convert
|
47
|
+
converted = converter.exec(Serialization.deserialize_from_string(kwalify_schema, source_format))
|
48
|
+
# Serialize
|
49
|
+
Serialization.serialize_to_string(converted, dest_format)
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
module KwalifyToJsonSchema
|
2
|
+
# Enumeration of known implementation limitation
|
3
|
+
module Limitations
|
4
|
+
DATE_TYPE_NOT_IMPLEMENTED = "Kwalify 'date' type is not supported and is ignored"
|
5
|
+
TIME_TYPE_NOT_IMPLEMENTED = "Kwalify 'time' type is not supported and is ignored"
|
6
|
+
TIMESTAMP_TYPE_NOT_IMPLEMENTED = "Kwalify 'timestamp' type is not supported and is ignored"
|
7
|
+
end
|
8
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module KwalifyToJsonSchema
|
2
|
+
# The possible options for the conversion and the associated accessors
|
3
|
+
class Options
|
4
|
+
# Converter options:
|
5
|
+
# | Name | Type | Default value| Description |
|
6
|
+
# |-----------------------|--------|--------------|-----------------------------------------------------|
|
7
|
+
# | :id | String | nil | The JSON schema identifier |
|
8
|
+
# | :title | String | nil | The JSON schema title |
|
9
|
+
# | :description | String | nil | The JSON schema description |
|
10
|
+
# | :issues_to_description| Boolean| false | To append the issuses to the JSON schema description|
|
11
|
+
# | :custom_processing | Object | nil | To customize the conversion |
|
12
|
+
# --
|
13
|
+
DECLARATION = %q(
|
14
|
+
ID # The JSON schema identifier [String] (nil)
|
15
|
+
TITLE # The JSON schema title [String] (nil)
|
16
|
+
DESCRIPTION # The JSON schema description [String] (nil)
|
17
|
+
ISSUES_TO_DESCRIPTION # To append the issuses to the JSON schema description [Boolean] (false)
|
18
|
+
CUSTOM_PROCESSING # To customize the conversion [Object] (nil)
|
19
|
+
)
|
20
|
+
|
21
|
+
# The options as Hash
|
22
|
+
attr_reader :options_hash
|
23
|
+
|
24
|
+
def initialize(options_hash)
|
25
|
+
@options_hash = options_hash
|
26
|
+
end
|
27
|
+
|
28
|
+
# Parse options declaration text and give an array of Hash
|
29
|
+
def self.parse
|
30
|
+
DECLARATION.lines.map { |l|
|
31
|
+
next nil if l.strip.empty?
|
32
|
+
|
33
|
+
# Parse line
|
34
|
+
const_name, comment = l.split("#", 2).map(&:strip)
|
35
|
+
name = const_name.downcase.to_s
|
36
|
+
description = comment.split("[").first.strip
|
37
|
+
# Get type and default value
|
38
|
+
m = comment.match(/\[(.+)\].*\((.+)\)/)
|
39
|
+
type, default_value = m.captures
|
40
|
+
default_value = eval(default_value)
|
41
|
+
|
42
|
+
# Create read accessor
|
43
|
+
attr_reader_name = "#{name}#{type == "Boolean" ? "?" : ""}"
|
44
|
+
|
45
|
+
# Array entry as Hash for the option
|
46
|
+
{
|
47
|
+
const_name: const_name,
|
48
|
+
const_name_full: "#{Options.name}::#{const_name}",
|
49
|
+
name: name,
|
50
|
+
description: description,
|
51
|
+
type: type,
|
52
|
+
default_value: default_value,
|
53
|
+
attr_reader_name: attr_reader_name,
|
54
|
+
}
|
55
|
+
}.compact
|
56
|
+
end
|
57
|
+
|
58
|
+
# Setup the constants and methods for the options
|
59
|
+
# Example: ID will lead to get ID constant and :id method
|
60
|
+
def self.setup
|
61
|
+
parse.each { |o|
|
62
|
+
# Create constant
|
63
|
+
const_set o[:const_name], o[:name]
|
64
|
+
|
65
|
+
# Create read accessor
|
66
|
+
define_method(o[:attr_reader_name]) {
|
67
|
+
options_hash[o[:name]] || o[:default_value]
|
68
|
+
}
|
69
|
+
}
|
70
|
+
end
|
71
|
+
|
72
|
+
setup
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module KwalifyToJsonSchema
|
2
|
+
|
3
|
+
# Abstract JSON/YAML serialization/deserialization
|
4
|
+
module Serialization
|
5
|
+
def self.deserialize_from_file(file)
|
6
|
+
serialization_for_file(file).deserialize(File.read(file))
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.serialize_to_file(file, object)
|
10
|
+
File.write(file, serialization_for_file(file).serialize(object))
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.deserialize_from_string(string, format = "yaml")
|
14
|
+
serialization_for_format(format).deserialize(string)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.serialize_to_string(object, format = "json")
|
18
|
+
serialization_for_format(format).serialize(object)
|
19
|
+
end
|
20
|
+
|
21
|
+
# @return a Hash giving serialization/deserialization module and methods for a given file extension (.json/.yaml)
|
22
|
+
def self.serialization_for_file(file)
|
23
|
+
serialization_for_format(File.extname(file)[1..-1])
|
24
|
+
end
|
25
|
+
|
26
|
+
# @return a Hash giving serialization/deserialization module and methods for a format (json/yaml)
|
27
|
+
def self.serialization_for_format(format)
|
28
|
+
serializer = { "json" => Json, "yaml" => Yaml }[format] || Json
|
29
|
+
end
|
30
|
+
|
31
|
+
class Language
|
32
|
+
def self.normalize(string); serialize(deserialize(string)); end
|
33
|
+
end
|
34
|
+
|
35
|
+
class Json < Language
|
36
|
+
def self.serialize(object); JSON.pretty_generate(object); end
|
37
|
+
def self.deserialize(string); JSON.parse(string); end
|
38
|
+
end
|
39
|
+
|
40
|
+
class Yaml < Language
|
41
|
+
def self.serialize(object); YAML.dump(object); end
|
42
|
+
def self.deserialize(string); YAML.load(string); end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# Customization of Kwalify to JSON schema
|
2
|
+
class CustomProcessing
|
3
|
+
def preprocess(kwalify_schema)
|
4
|
+
# Remove and keep the wrapping name
|
5
|
+
head = kwalify_schema.first
|
6
|
+
@name = head.first
|
7
|
+
head.last
|
8
|
+
end
|
9
|
+
|
10
|
+
def postprocess(json_schema)
|
11
|
+
# Restore the wrapping name
|
12
|
+
{ @name => json_schema }
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require "minitest/autorun"
|
2
|
+
require "json-schema"
|
3
|
+
require_relative "../lib/kwalify_to_json_schema"
|
4
|
+
|
5
|
+
module KwalifyToJsonSchema
|
6
|
+
class Test < Minitest::Test
|
7
|
+
@@debug = false
|
8
|
+
@@tmpdir = Dir.mktmpdir
|
9
|
+
|
10
|
+
[
|
11
|
+
{ test_group: "conversion", cli_options: [] },
|
12
|
+
{ test_group: "custom_processing", cli_options: ["--custom-processing", File.join(__dir__, "custom_processing.rb")] },
|
13
|
+
].each { |entry|
|
14
|
+
test_group = entry[:test_group]
|
15
|
+
cli_options = entry[:cli_options]
|
16
|
+
|
17
|
+
# Create a test method for every Kwalify schema
|
18
|
+
Dir.glob(File.join(__dir__, test_group, "kwalify", "*.yaml")).each { |source|
|
19
|
+
test_file_base = File.basename(source, File.extname(source))
|
20
|
+
test_name_base = test_file_base.gsub("#", "_")
|
21
|
+
expected_formats = %w(json yaml)
|
22
|
+
|
23
|
+
# Define a method for the test JSON output
|
24
|
+
define_method("test_#{test_group}_#{test_name_base}_output".to_sym) {
|
25
|
+
formats_done = 0
|
26
|
+
expected_formats.map { |expected_format|
|
27
|
+
output_file = test_file_base + ".#{expected_format}"
|
28
|
+
expected = File.join(File.join(__dir__, test_group, "json_schema", expected_format, output_file))
|
29
|
+
|
30
|
+
next unless File.exist?(expected)
|
31
|
+
formats_done += 1
|
32
|
+
|
33
|
+
ser = KwalifyToJsonSchema::Serialization::serialization_for_format(expected_format)
|
34
|
+
dest = File.join(@@tmpdir, output_file)
|
35
|
+
|
36
|
+
args = ["convert", source, dest]
|
37
|
+
# Add issues to description if filename include "#issues_to_description"
|
38
|
+
args << "--issues_to_description" if output_file.include?("#issues_to_description")
|
39
|
+
args.concat cli_options
|
40
|
+
|
41
|
+
# Convert
|
42
|
+
# KwalifyToJsonSchema.convert_file(source, dest, options)
|
43
|
+
KwalifyToJsonSchema::Cli.start(args)
|
44
|
+
|
45
|
+
# Validate schema
|
46
|
+
validate_json_schema_file(dest)
|
47
|
+
|
48
|
+
if @@debug
|
49
|
+
puts test_name_base
|
50
|
+
puts ser.normalize(File.read(dest))
|
51
|
+
end
|
52
|
+
# Compare to expected result
|
53
|
+
assert_equal(
|
54
|
+
ser.normalize(File.read(expected)),
|
55
|
+
ser.normalize(File.read(dest))
|
56
|
+
)
|
57
|
+
}
|
58
|
+
|
59
|
+
skip "None of the expected #{expected_formats.join(", ")} result for test #{test_name_base} was found" if formats_done == 0
|
60
|
+
}
|
61
|
+
}
|
62
|
+
}
|
63
|
+
|
64
|
+
def validate_json_schema_file(schema_file)
|
65
|
+
schema = KwalifyToJsonSchema::Serialization::deserialize_from_file(schema_file)
|
66
|
+
validate_json_schema(schema)
|
67
|
+
end
|
68
|
+
|
69
|
+
def validate_json_schema(schema)
|
70
|
+
# FIXME draft7 is not available in current json-schema gem
|
71
|
+
metaschema = JSON::Validator.validator_for_name("draft4").metaschema
|
72
|
+
JSON::Validator.validate!(metaschema, schema)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "erb"
|
2
|
+
|
3
|
+
module DocTemplate
|
4
|
+
def self.render(template_file, dest_file)
|
5
|
+
template = ERB.new(File.read(template_file), nil, "-")
|
6
|
+
File.write(dest_file, template.result(get_binding(template_file)))
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.get_binding(template_file)
|
10
|
+
template_dir = File.dirname template_file
|
11
|
+
binding
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require_relative "../lib/kwalify_to_json_schema/limitations"
|
2
|
+
|
3
|
+
# Gives implementation limitations
|
4
|
+
module Limitations
|
5
|
+
|
6
|
+
# @return list of limitation as array of strings
|
7
|
+
def self.list
|
8
|
+
KwalifyToJsonSchema::Limitations.constants.map { |cst|
|
9
|
+
KwalifyToJsonSchema::Limitations.const_get(cst)
|
10
|
+
}
|
11
|
+
end
|
12
|
+
|
13
|
+
# @return limitation as markdown text
|
14
|
+
def self.markdown
|
15
|
+
list.map { |l|
|
16
|
+
"* #{l}"
|
17
|
+
}.join("\n")
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require "yaml"
|
2
|
+
require_relative "../lib/kwalify_to_json_schema/options"
|
3
|
+
|
4
|
+
# Gives implementation limitations
|
5
|
+
module Options
|
6
|
+
|
7
|
+
# @return list of limitation as array of strings
|
8
|
+
def self.list
|
9
|
+
KwalifyToJsonSchema::Options.parse
|
10
|
+
end
|
11
|
+
|
12
|
+
# @return limitation as markdown text
|
13
|
+
def self.ascii_table(formatting = ["%s"] * 4)
|
14
|
+
header = ["Name", "Type", "Default value", "Description"]
|
15
|
+
|
16
|
+
nb_cols = header.length
|
17
|
+
|
18
|
+
table = [header] +
|
19
|
+
[[""] * nb_cols] +
|
20
|
+
list.map { |o|
|
21
|
+
[
|
22
|
+
formatting[0] % o[:name].to_sym.inspect,
|
23
|
+
formatting[1] % o[:type],
|
24
|
+
formatting[2] % o[:default_value].inspect,
|
25
|
+
formatting[3] % o[:description],
|
26
|
+
]
|
27
|
+
}
|
28
|
+
nb_rows = table.length
|
29
|
+
|
30
|
+
cols_max_length = (0..nb_cols - 1).map { |c|
|
31
|
+
(0..nb_rows - 1).map { |r|
|
32
|
+
cell = table[r][c]
|
33
|
+
cell.length
|
34
|
+
}.max
|
35
|
+
}
|
36
|
+
|
37
|
+
table.map.each_with_index { |row, r|
|
38
|
+
row.map.each_with_index { |cell, c|
|
39
|
+
max_length = cols_max_length[c]
|
40
|
+
if r == 1
|
41
|
+
"|-" + cell + ("-" * (max_length - cell.length))
|
42
|
+
else
|
43
|
+
"| " + cell + (" " * (max_length - cell.length))
|
44
|
+
end
|
45
|
+
}.join + "|"
|
46
|
+
}.join "\n"
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.markdown
|
50
|
+
ascii_table [
|
51
|
+
"`%s`",
|
52
|
+
"`%s`",
|
53
|
+
"`%s`",
|
54
|
+
"_%s_",
|
55
|
+
]
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.inject_as_code_comment(file)
|
59
|
+
new_lines = []
|
60
|
+
state = :init
|
61
|
+
count = 0
|
62
|
+
|
63
|
+
options_start = "Converter options:"
|
64
|
+
options_stop = "--"
|
65
|
+
|
66
|
+
File.read(file).each_line { |line|
|
67
|
+
if line.strip.start_with? "#"
|
68
|
+
content = line.strip[1..-1].strip
|
69
|
+
case state
|
70
|
+
when :init
|
71
|
+
new_lines << line
|
72
|
+
if content == options_start
|
73
|
+
count += 1
|
74
|
+
state = :in_options
|
75
|
+
padding = line.index("#")
|
76
|
+
new_lines.concat(ascii_table.lines.map { |l| "#{" " * padding}# #{l.chomp}\n" })
|
77
|
+
end
|
78
|
+
when :in_options
|
79
|
+
if content.start_with? options_stop
|
80
|
+
new_lines << line
|
81
|
+
state = :init
|
82
|
+
end
|
83
|
+
end
|
84
|
+
else
|
85
|
+
state = :error unless state == :init
|
86
|
+
new_lines << line
|
87
|
+
end
|
88
|
+
}
|
89
|
+
|
90
|
+
if state == :error
|
91
|
+
puts "Missing '#{options_stop}' delimiter after '#{options_start}' in file://#{file}"
|
92
|
+
else
|
93
|
+
File.write(file, new_lines.join) if count > 0
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
metadata
ADDED
@@ -0,0 +1,128 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: kwalify_to_json_schema
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Sylvain Gamot
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-06-10 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: thor
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: coderay
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: kwalify
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.7.2
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.7.2
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: json-schema
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '2.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '2.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 12.3.0
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 12.3.0
|
83
|
+
description: Allows to convert Kwalify schemas to JSON schemas Draft 7
|
84
|
+
email: ''
|
85
|
+
executables:
|
86
|
+
- kwalify_to_json_schema
|
87
|
+
extensions: []
|
88
|
+
extra_rdoc_files: []
|
89
|
+
files:
|
90
|
+
- "/home/sylvain/kwalify_to_json_schema/lib/kwalify_to_json_schema.rb"
|
91
|
+
- "/home/sylvain/kwalify_to_json_schema/lib/kwalify_to_json_schema/cli.rb"
|
92
|
+
- "/home/sylvain/kwalify_to_json_schema/lib/kwalify_to_json_schema/converter.rb"
|
93
|
+
- "/home/sylvain/kwalify_to_json_schema/lib/kwalify_to_json_schema/custom_processing.rb"
|
94
|
+
- "/home/sylvain/kwalify_to_json_schema/lib/kwalify_to_json_schema/kwalify_to_json_schema.rb"
|
95
|
+
- "/home/sylvain/kwalify_to_json_schema/lib/kwalify_to_json_schema/limitations.rb"
|
96
|
+
- "/home/sylvain/kwalify_to_json_schema/lib/kwalify_to_json_schema/options.rb"
|
97
|
+
- "/home/sylvain/kwalify_to_json_schema/lib/kwalify_to_json_schema/serialization.rb"
|
98
|
+
- "/home/sylvain/kwalify_to_json_schema/test/custom_processing.rb"
|
99
|
+
- "/home/sylvain/kwalify_to_json_schema/test/test_kwalify_to_json_schema.rb"
|
100
|
+
- "/home/sylvain/kwalify_to_json_schema/tools/all.rb"
|
101
|
+
- "/home/sylvain/kwalify_to_json_schema/tools/doc_template.rb"
|
102
|
+
- "/home/sylvain/kwalify_to_json_schema/tools/limitations.rb"
|
103
|
+
- "/home/sylvain/kwalify_to_json_schema/tools/options.rb"
|
104
|
+
- bin/kwalify_to_json_schema
|
105
|
+
homepage: https://rubygems.org/gems/kwalify_to_json_schema
|
106
|
+
licenses:
|
107
|
+
- MIT
|
108
|
+
metadata: {}
|
109
|
+
post_install_message:
|
110
|
+
rdoc_options: []
|
111
|
+
require_paths:
|
112
|
+
- lib
|
113
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
119
|
+
requirements:
|
120
|
+
- - ">="
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: '0'
|
123
|
+
requirements: []
|
124
|
+
rubygems_version: 3.1.2
|
125
|
+
signing_key:
|
126
|
+
specification_version: 4
|
127
|
+
summary: Kwalify schemas to JSON schemas conversion
|
128
|
+
test_files: []
|