openapi-sourcetools 0.7.1 → 0.8.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 +4 -4
- data/bin/openapi-addheaders +8 -7
- data/bin/openapi-addparameters +50 -9
- data/bin/openapi-addresponses +8 -8
- data/bin/openapi-addschemas +10 -9
- data/bin/openapi-checkschemas +16 -15
- data/bin/openapi-frequencies +23 -25
- data/bin/openapi-generate +15 -12
- data/bin/openapi-merge +6 -6
- data/bin/openapi-modifypaths +16 -15
- data/bin/openapi-processpaths +15 -26
- data/lib/openapi/sourcetools/apiobjects.rb +191 -0
- data/lib/openapi/sourcetools/common.rb +82 -0
- data/lib/openapi/sourcetools/config.rb +158 -0
- data/lib/openapi/sourcetools/docs.rb +41 -0
- data/lib/{gen.rb → openapi/sourcetools/gen.rb} +38 -13
- data/lib/openapi/sourcetools/generate.rb +96 -0
- data/lib/openapi/sourcetools/helper.rb +93 -0
- data/lib/openapi/sourcetools/loaders.rb +164 -0
- data/lib/openapi/sourcetools/output.rb +83 -0
- data/lib/openapi/sourcetools/securityschemes.rb +268 -0
- data/lib/openapi/sourcetools/task.rb +137 -0
- data/lib/openapi/sourcetools/version.rb +13 -0
- data/lib/openapi/sourcetools.rb +15 -0
- metadata +42 -18
- data/lib/apiobjects.rb +0 -306
- data/lib/common.rb +0 -114
- data/lib/docs.rb +0 -33
- data/lib/generate.rb +0 -90
- data/lib/helper.rb +0 -94
- data/lib/loaders.rb +0 -96
- data/lib/output.rb +0 -58
- data/lib/task.rb +0 -101
data/lib/docs.rb
DELETED
@@ -1,33 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Copyright © 2024 Ismo Kärkkäinen
|
4
|
-
# Licensed under Universal Permissive License. See LICENSE.txt.
|
5
|
-
|
6
|
-
require_relative 'common'
|
7
|
-
|
8
|
-
|
9
|
-
class Docs
|
10
|
-
attr_reader :docs
|
11
|
-
|
12
|
-
def initialize
|
13
|
-
@docs = {}
|
14
|
-
end
|
15
|
-
|
16
|
-
def method_missing(method_name, *args)
|
17
|
-
name = method_name.to_s
|
18
|
-
if name.end_with?('=')
|
19
|
-
name = name[0...(name.size - 1)]
|
20
|
-
super unless @docs.key?(name)
|
21
|
-
@docs[name] = args.first
|
22
|
-
return args.first
|
23
|
-
end
|
24
|
-
super unless @docs.key?(name)
|
25
|
-
@docs[name]
|
26
|
-
end
|
27
|
-
|
28
|
-
def add(name, content)
|
29
|
-
return false if docs.key?(name)
|
30
|
-
@docs[name] = content
|
31
|
-
true
|
32
|
-
end
|
33
|
-
end
|
data/lib/generate.rb
DELETED
@@ -1,90 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
# Copyright © 2024 Ismo Kärkkäinen
|
5
|
-
# Licensed under Universal Permissive License. See LICENSE.txt.
|
6
|
-
|
7
|
-
require_relative 'common'
|
8
|
-
require_relative 'loaders'
|
9
|
-
require_relative 'gen'
|
10
|
-
|
11
|
-
|
12
|
-
def executable_bits_on(mode)
|
13
|
-
mode = mode.to_s(8).split('')
|
14
|
-
mode.size.times do |k|
|
15
|
-
m = mode[k].to_i(8)
|
16
|
-
# Applies to Unix-likes. Other system, check and handle.
|
17
|
-
m += 1 unless 3 < mode.size - k || m.zero? || m % 2 == 1
|
18
|
-
mode[k] = m
|
19
|
-
end
|
20
|
-
m = 0
|
21
|
-
mode.each do |v|
|
22
|
-
m = 8 * m + v
|
23
|
-
end
|
24
|
-
m
|
25
|
-
end
|
26
|
-
|
27
|
-
class Generator
|
28
|
-
def initialize(document_content, input_name, output_directory)
|
29
|
-
Gen.setup(document_content, input_name, output_directory)
|
30
|
-
Gen.loaders = Loaders.loaders
|
31
|
-
end
|
32
|
-
|
33
|
-
def context_binding
|
34
|
-
binding
|
35
|
-
end
|
36
|
-
|
37
|
-
def load(generator_names)
|
38
|
-
generator_names.each do |name|
|
39
|
-
idx = Gen.loaders.index { |loader| loader.call(name) }
|
40
|
-
return aargh("No loader could handle #{name}", 2) if idx.nil?
|
41
|
-
end
|
42
|
-
0
|
43
|
-
rescue StandardError => e
|
44
|
-
aargh(e.to_s, 2)
|
45
|
-
end
|
46
|
-
|
47
|
-
def generate(t)
|
48
|
-
t.generate(context_binding)
|
49
|
-
rescue Exception => e
|
50
|
-
aargh(e.to_s, 4)
|
51
|
-
end
|
52
|
-
|
53
|
-
def output_name(t, index)
|
54
|
-
name = t.output_name
|
55
|
-
name = "#{index}.txt" if name.nil?
|
56
|
-
File.join(Gen.outdir, name)
|
57
|
-
end
|
58
|
-
|
59
|
-
def save(name, contents, executable)
|
60
|
-
f = File.new(name, File::WRONLY | File::CREAT | File::TRUNC)
|
61
|
-
s = executable ? f.stat : nil
|
62
|
-
f.write(contents)
|
63
|
-
f.close
|
64
|
-
return unless executable
|
65
|
-
mode = executable_bits_on(s.mode)
|
66
|
-
File.chmod(mode, name) unless mode == s.mode
|
67
|
-
end
|
68
|
-
|
69
|
-
def run
|
70
|
-
# This allows tasks to be added while processing.
|
71
|
-
# Not intended to be done but might prove handy.
|
72
|
-
# Also exposes current task index in case new task is added in the middle.
|
73
|
-
Gen.task_index = 0
|
74
|
-
while Gen.task_index < Gen.tasks.size
|
75
|
-
Gen.t = Gen.tasks[Gen.task_index]
|
76
|
-
out = generate(Gen.t)
|
77
|
-
Gen.task_index += 1
|
78
|
-
next if Gen.t.discard # Check first to ignore result if no output.
|
79
|
-
return out if out.is_a?(Integer)
|
80
|
-
next if out.empty? # Allows no output but return value still checked.
|
81
|
-
name = output_name(Gen.t, Gen.task_index - 1)
|
82
|
-
begin
|
83
|
-
save(name, out, Gen.t.executable)
|
84
|
-
rescue StandardError => e
|
85
|
-
return aargh("Error writing output file: #{name}\n#{e}", 3)
|
86
|
-
end
|
87
|
-
end
|
88
|
-
0
|
89
|
-
end
|
90
|
-
end
|
data/lib/helper.rb
DELETED
@@ -1,94 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Copyright © 2024 Ismo Kärkkäinen
|
4
|
-
# Licensed under Universal Permissive License. See LICENSE.txt.
|
5
|
-
|
6
|
-
require_relative 'task'
|
7
|
-
|
8
|
-
|
9
|
-
class Helper
|
10
|
-
attr_reader :doc, :parents
|
11
|
-
attr_accessor :parent_parameters
|
12
|
-
|
13
|
-
# Stores the nearest Hash for each Hash.
|
14
|
-
def store_parents(obj, parent = nil)
|
15
|
-
if obj.is_a?(Hash)
|
16
|
-
@parents[obj.object_id] = parent
|
17
|
-
obj.each do |k, v|
|
18
|
-
store_parents(v, obj)
|
19
|
-
end
|
20
|
-
elsif obj.is_a?(Array)
|
21
|
-
obj.each do |v|
|
22
|
-
store_parents(v, parent)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
def initialize(doc)
|
28
|
-
@doc = doc
|
29
|
-
@parents = {}
|
30
|
-
store_parents(@doc)
|
31
|
-
end
|
32
|
-
|
33
|
-
def parent(object)
|
34
|
-
@parents[object.object_id]
|
35
|
-
end
|
36
|
-
|
37
|
-
COMPONENTS = '#/components/'
|
38
|
-
|
39
|
-
def category_and_name(ref_or_obj)
|
40
|
-
ref = ref_or_obj.is_a?(Hash) ? ref_or_obj['$ref'] : ref_or_obj
|
41
|
-
return nil unless ref.is_a?(String)
|
42
|
-
return nil unless ref.start_with?(Helper::COMPONENTS)
|
43
|
-
idx = ref.index('/', Helper::COMPONENTS.size)
|
44
|
-
return nil if idx.nil?
|
45
|
-
category = ref[Helper::COMPONENTS.size...idx]
|
46
|
-
[ category, ref[(idx + 1)...ref.size] ]
|
47
|
-
end
|
48
|
-
|
49
|
-
def dereference(ref_or_obj)
|
50
|
-
cn = category_and_name(ref_or_obj)
|
51
|
-
return nil if cn.nil?
|
52
|
-
cs = @doc.dig('components', cn.first) || {}
|
53
|
-
cs[cn.last]
|
54
|
-
end
|
55
|
-
|
56
|
-
def basename(ref_or_obj)
|
57
|
-
cn = category_and_name(ref_or_obj)
|
58
|
-
return nil if cn.nil?
|
59
|
-
cn.last
|
60
|
-
end
|
61
|
-
|
62
|
-
def parameters(operation_object, empty_unless_local = false)
|
63
|
-
return [] if empty_unless_local && !operation_object.key?('parameters')
|
64
|
-
cps = @doc.dig('components', 'parameters') || {}
|
65
|
-
uniqs = {}
|
66
|
-
path_item_object = parent(operation_object)
|
67
|
-
[path_item_object, operation_object].each do |p|
|
68
|
-
p.fetch('parameters', []).each do |param|
|
69
|
-
r = basename(param)
|
70
|
-
r = cps[r] if r.is_a?(String)
|
71
|
-
uniqs["#{r['name']}:#{r['in']}"] = param
|
72
|
-
end
|
73
|
-
end
|
74
|
-
uniqs.keys.sort!.map { |k| uniqs[k] }
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
|
79
|
-
class HelperTask
|
80
|
-
include TaskInterface
|
81
|
-
|
82
|
-
def generate(context_binding)
|
83
|
-
Gen.h = Helper.new(Gen.doc)
|
84
|
-
end
|
85
|
-
|
86
|
-
def output_name
|
87
|
-
nil
|
88
|
-
end
|
89
|
-
|
90
|
-
def discard
|
91
|
-
true
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
data/lib/loaders.rb
DELETED
@@ -1,96 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Copyright © 2024 Ismo Kärkkäinen
|
4
|
-
# Licensed under Universal Permissive License. See LICENSE.txt.
|
5
|
-
|
6
|
-
|
7
|
-
# Original loader functions. These are accessible via Gen.loaders. New loaders
|
8
|
-
# should be added there.
|
9
|
-
module Loaders
|
10
|
-
|
11
|
-
GEM_PREFIX = 'gem:'
|
12
|
-
|
13
|
-
def self.gem_loader(name)
|
14
|
-
return false unless name.downcase.start_with?(GEM_PREFIX)
|
15
|
-
begin
|
16
|
-
require(name.slice(GEM_PREFIX.size...name.size))
|
17
|
-
rescue LoadError => e
|
18
|
-
raise StandardError, "Failed to require #{name}\n#{e.to_s}"
|
19
|
-
rescue Exception => e
|
20
|
-
raise StandardError, "Problem with #{name}\n#{e.to_s}"
|
21
|
-
end
|
22
|
-
true
|
23
|
-
end
|
24
|
-
|
25
|
-
RUBY_EXT = '.rb'
|
26
|
-
|
27
|
-
def self.ruby_loader(name)
|
28
|
-
return false unless name.downcase.end_with?(RUBY_EXT)
|
29
|
-
origwd = Dir.pwd
|
30
|
-
d = File.dirname(name)
|
31
|
-
Dir.chdir(d) unless d == '.'
|
32
|
-
begin
|
33
|
-
require(File.join(Dir.pwd, File.basename(name)))
|
34
|
-
rescue LoadError => e
|
35
|
-
raise StandardError, "Failed to require #{name}\n#{e.to_s}"
|
36
|
-
rescue Exception => e
|
37
|
-
raise StandardError, "Problem with #{name}\n#{e.to_s}"
|
38
|
-
end
|
39
|
-
Dir.chdir(origwd) unless d == '.'
|
40
|
-
true
|
41
|
-
end
|
42
|
-
|
43
|
-
YAML_PREFIX = 'yaml:'
|
44
|
-
YAML_EXTS = [ '.yaml', '.yml' ]
|
45
|
-
|
46
|
-
def self.yaml_loader(name)
|
47
|
-
d = name.downcase
|
48
|
-
if d.start_with?(YAML_PREFIX)
|
49
|
-
name = name.slice(YAML_PREFIX.size...name.size)
|
50
|
-
else
|
51
|
-
return false if (YAML_EXTS.index { |s| d.end_with?(s) }).nil?
|
52
|
-
end
|
53
|
-
n, sep, f = name.partition(':')
|
54
|
-
raise StandardError, "No name given." if n.empty?
|
55
|
-
raise StandardError, "No filename given." if f.empty?
|
56
|
-
doc = YAML.safe_load(File.read(f))
|
57
|
-
raise StandardError, "#{name} #{n} exists already." unless Gen.d.add(n, doc)
|
58
|
-
true
|
59
|
-
rescue Errno::ENOENT
|
60
|
-
raise StandardError, "Not found: #{f}\n#{e.to_s}"
|
61
|
-
rescue Exception => e
|
62
|
-
raise StandardError, "Failed to read as YAML: #{f}\n#{e.to_s}"
|
63
|
-
end
|
64
|
-
|
65
|
-
BIN_PREFIX = 'bin:'
|
66
|
-
|
67
|
-
def self.bin_loader(name)
|
68
|
-
return false unless name.downcase.start_with?(BIN_PREFIX)
|
69
|
-
n, sep, f = name.slice(BIN_PREFIX.size...name.size).partition(':')
|
70
|
-
raise StandardError, "No name given." if n.empty?
|
71
|
-
raise StandardError, "No filename given." if f.empty?
|
72
|
-
doc = IO.binread(f)
|
73
|
-
raise StandardError, "#{name} #{n} exists already." unless Gen.d.add(n, doc)
|
74
|
-
true
|
75
|
-
rescue Errno::ENOENT
|
76
|
-
raise StandardError, "Not found: #{f}\n#{e.to_s}"
|
77
|
-
rescue Exception => e
|
78
|
-
raise StandardError, "Failed to read #{f}\n#{e.to_s}"
|
79
|
-
end
|
80
|
-
|
81
|
-
def self.loaders
|
82
|
-
pre = @preloaders
|
83
|
-
[ method(:gem_loader), method(:ruby_loader), method(:yaml_loader), method(:bin_loader) ]
|
84
|
-
end
|
85
|
-
|
86
|
-
def self.document
|
87
|
-
%(
|
88
|
-
- #{Loaders::GEM_PREFIX}gem_name : requires the gem.
|
89
|
-
- ruby_file#{Loaders::RUBY_EXT} : changes to Ruby file directory and requires the file.
|
90
|
-
- #{Loaders::YAML_PREFIX}name:filename : Loads YAML file into Gen.d.name.
|
91
|
-
- name:filename.{#{(Loaders::YAML_EXTS.map { |s| s[1...s.size] }).join('|')}} : Loads YAML file into Gen.d.name.
|
92
|
-
- #{Loaders::BIN_PREFIX}name:filename : Loads binary file into Gen.d.name.
|
93
|
-
)
|
94
|
-
end
|
95
|
-
|
96
|
-
end
|
data/lib/output.rb
DELETED
@@ -1,58 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Copyright © 2024 Ismo Kärkkäinen
|
4
|
-
# Licensed under Universal Permissive License. See LICENSE.txt.
|
5
|
-
|
6
|
-
require_relative 'task'
|
7
|
-
|
8
|
-
|
9
|
-
class Output
|
10
|
-
# For indentation.
|
11
|
-
attr_accessor :indent_character, :indent_step
|
12
|
-
attr_accessor :tab, :tab_replaces_count
|
13
|
-
attr_accessor :last_indent
|
14
|
-
|
15
|
-
def initialize
|
16
|
-
@indent_character = ' '
|
17
|
-
@indent_step = 4
|
18
|
-
@tab = "\t"
|
19
|
-
@tab_replaces_count = 0
|
20
|
-
@last_indent = 0
|
21
|
-
end
|
22
|
-
|
23
|
-
def join(blocks, separator = "\n")
|
24
|
-
indented = []
|
25
|
-
blocks.flatten!
|
26
|
-
indent = 0
|
27
|
-
blocks.each do |block|
|
28
|
-
if block.nil?
|
29
|
-
indent = 0
|
30
|
-
elsif block.is_a?(Integer)
|
31
|
-
indent += block
|
32
|
-
elsif block.is_a?(TrueClass)
|
33
|
-
indent += @indent_step
|
34
|
-
elsif block.is_a?(FalseClass)
|
35
|
-
indent -= @indent_step
|
36
|
-
else
|
37
|
-
block = block.to_s unless block.is_a?(String)
|
38
|
-
if indent.zero?
|
39
|
-
indented.push(block)
|
40
|
-
next
|
41
|
-
end
|
42
|
-
if 0 < @tab_replaces_count
|
43
|
-
tabs = @tab * (indent / @tab_replaces_count)
|
44
|
-
chars = @indent_character * (indent % @tab_replaces_count)
|
45
|
-
else
|
46
|
-
tabs = ''
|
47
|
-
chars = @indent_character * indent
|
48
|
-
end
|
49
|
-
lines = block.lines(chomp: true)
|
50
|
-
lines.each do |line|
|
51
|
-
indented.push("#{tabs}#{chars}#{line}")
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
@last_indent = indent
|
56
|
-
indented.join(separator)
|
57
|
-
end
|
58
|
-
end
|
data/lib/task.rb
DELETED
@@ -1,101 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Copyright © 2024 Ismo Kärkkäinen
|
4
|
-
# Licensed under Universal Permissive License. See LICENSE.txt.
|
5
|
-
|
6
|
-
require 'erb'
|
7
|
-
require_relative 'common'
|
8
|
-
|
9
|
-
|
10
|
-
module TaskInterface
|
11
|
-
def generate(context_binding)
|
12
|
-
raise NotImplementedError
|
13
|
-
end
|
14
|
-
|
15
|
-
def output_name
|
16
|
-
raise NotImplementedError
|
17
|
-
end
|
18
|
-
|
19
|
-
def discard
|
20
|
-
false
|
21
|
-
end
|
22
|
-
|
23
|
-
def executable
|
24
|
-
false
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
class Task
|
29
|
-
include TaskInterface
|
30
|
-
|
31
|
-
attr_reader :src, :template, :template_name
|
32
|
-
attr_accessor :name, :executable, :discard, :x
|
33
|
-
|
34
|
-
def initialize(src, template, template_name)
|
35
|
-
@src = src
|
36
|
-
@template = template
|
37
|
-
@template_name = template_name
|
38
|
-
if @template.nil?
|
39
|
-
raise ArgumentError, "template_name or template must be given" if @template_name.nil?
|
40
|
-
begin
|
41
|
-
@template = File.read(@template_name)
|
42
|
-
rescue Errno::ENOENT
|
43
|
-
raise StandardError, "Could not load #{@template_name}"
|
44
|
-
rescue StandardError => e
|
45
|
-
raise StandardError, "#{e}\nFailed to read #{@template_name}"
|
46
|
-
end
|
47
|
-
end
|
48
|
-
@name = nil
|
49
|
-
@executable = false
|
50
|
-
@discard = false
|
51
|
-
@x = nil
|
52
|
-
end
|
53
|
-
|
54
|
-
# If this is overridden to perform some processing but not to produce output,
|
55
|
-
# set @discard = true and return value will be ignored. No other methods are
|
56
|
-
# called in that case.
|
57
|
-
def internal_generate(context_binding)
|
58
|
-
ERB.new(@template).result(context_binding)
|
59
|
-
end
|
60
|
-
|
61
|
-
# You can override this instead of internal_generate if you do not need the
|
62
|
-
# exception handling.
|
63
|
-
def generate(context_binding)
|
64
|
-
n = @template_name.nil? ? '' : "#{@template_name} "
|
65
|
-
internal_generate(context_binding)
|
66
|
-
rescue SyntaxError => e
|
67
|
-
aargh("Template #{n}syntax error: #{e.full_message}", 5)
|
68
|
-
rescue Exception => e
|
69
|
-
aargh("Template #{n}error: #{e.full_message}", 6)
|
70
|
-
end
|
71
|
-
|
72
|
-
# This is only called when generate produced output that is not discarded.
|
73
|
-
def output_name
|
74
|
-
return @name unless @name.nil?
|
75
|
-
# Using template name may show where name assignment is missing.
|
76
|
-
# Name assignment may also be missing in the task creation stage.
|
77
|
-
return File.basename(@template_name) unless @template_name.nil?
|
78
|
-
nil
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
class WriteTask
|
83
|
-
include TaskInterface
|
84
|
-
|
85
|
-
attr_reader :name, :contents, :executable
|
86
|
-
|
87
|
-
def initialize(name, contents, executable = false)
|
88
|
-
raise ArgumentError, "name and contents must be given" if name.nil? || contents.nil?
|
89
|
-
@name = name
|
90
|
-
@contents = contents
|
91
|
-
@executable = executable
|
92
|
-
end
|
93
|
-
|
94
|
-
def generate(context_binding)
|
95
|
-
@contents
|
96
|
-
end
|
97
|
-
|
98
|
-
def output_name
|
99
|
-
@name
|
100
|
-
end
|
101
|
-
end
|