kwalify_to_json_schema 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|