apiwork 0.0.0.pre → 0.1.1
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/LICENSE.txt +2 -2
- data/README.md +117 -1
- data/Rakefile +5 -3
- data/app/controllers/apiwork/errors_controller.rb +13 -0
- data/app/controllers/apiwork/exports_controller.rb +22 -0
- data/lib/apiwork/abstractable.rb +26 -0
- data/lib/apiwork/adapter/base.rb +369 -0
- data/lib/apiwork/adapter/builder/api/base.rb +66 -0
- data/lib/apiwork/adapter/builder/contract/base.rb +86 -0
- data/lib/apiwork/adapter/capability/api/base.rb +51 -0
- data/lib/apiwork/adapter/capability/api/scope.rb +64 -0
- data/lib/apiwork/adapter/capability/base.rb +291 -0
- data/lib/apiwork/adapter/capability/contract/base.rb +37 -0
- data/lib/apiwork/adapter/capability/contract/scope.rb +110 -0
- data/lib/apiwork/adapter/capability/operation/base.rb +172 -0
- data/lib/apiwork/adapter/capability/operation/metadata_shape.rb +165 -0
- data/lib/apiwork/adapter/capability/result.rb +21 -0
- data/lib/apiwork/adapter/capability/runner.rb +56 -0
- data/lib/apiwork/adapter/capability/transformer/request/base.rb +72 -0
- data/lib/apiwork/adapter/capability/transformer/response/base.rb +45 -0
- data/lib/apiwork/adapter/registry.rb +16 -0
- data/lib/apiwork/adapter/serializer/error/base.rb +72 -0
- data/lib/apiwork/adapter/serializer/error/default/api_builder.rb +32 -0
- data/lib/apiwork/adapter/serializer/error/default.rb +37 -0
- data/lib/apiwork/adapter/serializer/resource/base.rb +84 -0
- data/lib/apiwork/adapter/serializer/resource/default/contract_builder.rb +209 -0
- data/lib/apiwork/adapter/serializer/resource/default.rb +39 -0
- data/lib/apiwork/adapter/standard/capability/filtering/api_builder.rb +75 -0
- data/lib/apiwork/adapter/standard/capability/filtering/constants.rb +37 -0
- data/lib/apiwork/adapter/standard/capability/filtering/contract_builder.rb +193 -0
- data/lib/apiwork/adapter/standard/capability/filtering/operation/filter/builder.rb +47 -0
- data/lib/apiwork/adapter/standard/capability/filtering/operation/filter/operator_builder.rb +36 -0
- data/lib/apiwork/adapter/standard/capability/filtering/operation/filter.rb +462 -0
- data/lib/apiwork/adapter/standard/capability/filtering/operation.rb +22 -0
- data/lib/apiwork/adapter/standard/capability/filtering/request_transformer.rb +47 -0
- data/lib/apiwork/adapter/standard/capability/filtering.rb +18 -0
- data/lib/apiwork/adapter/standard/capability/including/contract_builder.rb +169 -0
- data/lib/apiwork/adapter/standard/capability/including/operation.rb +20 -0
- data/lib/apiwork/adapter/standard/capability/including.rb +16 -0
- data/lib/apiwork/adapter/standard/capability/pagination/api_builder.rb +34 -0
- data/lib/apiwork/adapter/standard/capability/pagination/contract_builder.rb +35 -0
- data/lib/apiwork/adapter/standard/capability/pagination/operation/paginate/cursor.rb +84 -0
- data/lib/apiwork/adapter/standard/capability/pagination/operation/paginate/offset.rb +66 -0
- data/lib/apiwork/adapter/standard/capability/pagination/operation/paginate.rb +24 -0
- data/lib/apiwork/adapter/standard/capability/pagination/operation.rb +24 -0
- data/lib/apiwork/adapter/standard/capability/pagination.rb +21 -0
- data/lib/apiwork/adapter/standard/capability/sorting/api_builder.rb +19 -0
- data/lib/apiwork/adapter/standard/capability/sorting/contract_builder.rb +84 -0
- data/lib/apiwork/adapter/standard/capability/sorting/operation/sort.rb +83 -0
- data/lib/apiwork/adapter/standard/capability/sorting/operation.rb +22 -0
- data/lib/apiwork/adapter/standard/capability/sorting.rb +17 -0
- data/lib/apiwork/adapter/standard/capability/writing/constants.rb +15 -0
- data/lib/apiwork/adapter/standard/capability/writing/contract_builder.rb +253 -0
- data/lib/apiwork/adapter/standard/capability/writing/operation/issue_mapper.rb +210 -0
- data/lib/apiwork/adapter/standard/capability/writing/operation.rb +32 -0
- data/lib/apiwork/adapter/standard/capability/writing/request_transformer.rb +37 -0
- data/lib/apiwork/adapter/standard/capability/writing.rb +17 -0
- data/lib/apiwork/adapter/standard/includes_resolver.rb +106 -0
- data/lib/apiwork/adapter/standard.rb +22 -0
- data/lib/apiwork/adapter/wrapper/base.rb +70 -0
- data/lib/apiwork/adapter/wrapper/collection/base.rb +60 -0
- data/lib/apiwork/adapter/wrapper/collection/default.rb +47 -0
- data/lib/apiwork/adapter/wrapper/error/base.rb +30 -0
- data/lib/apiwork/adapter/wrapper/error/default.rb +34 -0
- data/lib/apiwork/adapter/wrapper/member/base.rb +58 -0
- data/lib/apiwork/adapter/wrapper/member/default.rb +40 -0
- data/lib/apiwork/adapter/wrapper/shape.rb +203 -0
- data/lib/apiwork/adapter.rb +50 -0
- data/lib/apiwork/api/base.rb +802 -0
- data/lib/apiwork/api/element.rb +110 -0
- data/lib/apiwork/api/enum_registry/definition.rb +51 -0
- data/lib/apiwork/api/enum_registry.rb +98 -0
- data/lib/apiwork/api/info/contact.rb +67 -0
- data/lib/apiwork/api/info/license.rb +50 -0
- data/lib/apiwork/api/info/server.rb +50 -0
- data/lib/apiwork/api/info.rb +221 -0
- data/lib/apiwork/api/object.rb +235 -0
- data/lib/apiwork/api/registry.rb +33 -0
- data/lib/apiwork/api/representation_registry.rb +76 -0
- data/lib/apiwork/api/resource/action.rb +41 -0
- data/lib/apiwork/api/resource.rb +648 -0
- data/lib/apiwork/api/router.rb +104 -0
- data/lib/apiwork/api/type_registry/definition.rb +117 -0
- data/lib/apiwork/api/type_registry.rb +99 -0
- data/lib/apiwork/api/union.rb +49 -0
- data/lib/apiwork/api.rb +85 -0
- data/lib/apiwork/configurable.rb +71 -0
- data/lib/apiwork/configuration/option.rb +125 -0
- data/lib/apiwork/configuration/validatable.rb +25 -0
- data/lib/apiwork/configuration.rb +95 -0
- data/lib/apiwork/configuration_error.rb +6 -0
- data/lib/apiwork/constraint_error.rb +20 -0
- data/lib/apiwork/contract/action/request.rb +79 -0
- data/lib/apiwork/contract/action/response.rb +87 -0
- data/lib/apiwork/contract/action.rb +258 -0
- data/lib/apiwork/contract/base.rb +714 -0
- data/lib/apiwork/contract/element.rb +130 -0
- data/lib/apiwork/contract/object/coercer.rb +194 -0
- data/lib/apiwork/contract/object/deserializer.rb +101 -0
- data/lib/apiwork/contract/object/transformer.rb +95 -0
- data/lib/apiwork/contract/object/validator/result.rb +27 -0
- data/lib/apiwork/contract/object/validator.rb +734 -0
- data/lib/apiwork/contract/object.rb +566 -0
- data/lib/apiwork/contract/request_parser/result.rb +25 -0
- data/lib/apiwork/contract/request_parser.rb +72 -0
- data/lib/apiwork/contract/response_parser/result.rb +25 -0
- data/lib/apiwork/contract/response_parser.rb +35 -0
- data/lib/apiwork/contract/union.rb +56 -0
- data/lib/apiwork/contract_error.rb +9 -0
- data/lib/apiwork/controller.rb +300 -0
- data/lib/apiwork/domain_error.rb +13 -0
- data/lib/apiwork/element.rb +386 -0
- data/lib/apiwork/engine.rb +20 -0
- data/lib/apiwork/error.rb +6 -0
- data/lib/apiwork/error_code/definition.rb +63 -0
- data/lib/apiwork/error_code/registry.rb +18 -0
- data/lib/apiwork/error_code.rb +132 -0
- data/lib/apiwork/export/base.rb +291 -0
- data/lib/apiwork/export/open_api.rb +600 -0
- data/lib/apiwork/export/pipeline/writer.rb +66 -0
- data/lib/apiwork/export/pipeline.rb +84 -0
- data/lib/apiwork/export/registry.rb +16 -0
- data/lib/apiwork/export/surface_resolver.rb +189 -0
- data/lib/apiwork/export/type_analysis.rb +170 -0
- data/lib/apiwork/export/type_script.rb +23 -0
- data/lib/apiwork/export/type_script_mapper.rb +349 -0
- data/lib/apiwork/export/zod.rb +39 -0
- data/lib/apiwork/export/zod_mapper.rb +421 -0
- data/lib/apiwork/export.rb +80 -0
- data/lib/apiwork/http_error.rb +16 -0
- data/lib/apiwork/introspection/action/request.rb +66 -0
- data/lib/apiwork/introspection/action/response.rb +57 -0
- data/lib/apiwork/introspection/action.rb +124 -0
- data/lib/apiwork/introspection/api/info/contact.rb +59 -0
- data/lib/apiwork/introspection/api/info/license.rb +49 -0
- data/lib/apiwork/introspection/api/info/server.rb +50 -0
- data/lib/apiwork/introspection/api/info.rb +107 -0
- data/lib/apiwork/introspection/api/resource.rb +83 -0
- data/lib/apiwork/introspection/api.rb +92 -0
- data/lib/apiwork/introspection/contract.rb +63 -0
- data/lib/apiwork/introspection/dump/action.rb +101 -0
- data/lib/apiwork/introspection/dump/api.rb +119 -0
- data/lib/apiwork/introspection/dump/contract.rb +129 -0
- data/lib/apiwork/introspection/dump/param.rb +486 -0
- data/lib/apiwork/introspection/dump/resource.rb +112 -0
- data/lib/apiwork/introspection/dump/type.rb +339 -0
- data/lib/apiwork/introspection/dump.rb +17 -0
- data/lib/apiwork/introspection/enum.rb +63 -0
- data/lib/apiwork/introspection/error_code.rb +44 -0
- data/lib/apiwork/introspection/param/array.rb +88 -0
- data/lib/apiwork/introspection/param/base.rb +285 -0
- data/lib/apiwork/introspection/param/binary.rb +73 -0
- data/lib/apiwork/introspection/param/boolean.rb +73 -0
- data/lib/apiwork/introspection/param/date.rb +73 -0
- data/lib/apiwork/introspection/param/date_time.rb +73 -0
- data/lib/apiwork/introspection/param/decimal.rb +121 -0
- data/lib/apiwork/introspection/param/integer.rb +131 -0
- data/lib/apiwork/introspection/param/literal.rb +45 -0
- data/lib/apiwork/introspection/param/number.rb +121 -0
- data/lib/apiwork/introspection/param/object.rb +59 -0
- data/lib/apiwork/introspection/param/reference.rb +45 -0
- data/lib/apiwork/introspection/param/string.rb +122 -0
- data/lib/apiwork/introspection/param/time.rb +73 -0
- data/lib/apiwork/introspection/param/union.rb +57 -0
- data/lib/apiwork/introspection/param/unknown.rb +26 -0
- data/lib/apiwork/introspection/param/uuid.rb +73 -0
- data/lib/apiwork/introspection/param.rb +31 -0
- data/lib/apiwork/introspection/type.rb +129 -0
- data/lib/apiwork/introspection.rb +28 -0
- data/lib/apiwork/issue.rb +80 -0
- data/lib/apiwork/json_pointer.rb +21 -0
- data/lib/apiwork/object.rb +1618 -0
- data/lib/apiwork/reference_generator.rb +622 -0
- data/lib/apiwork/registry.rb +56 -0
- data/lib/apiwork/representation/association.rb +391 -0
- data/lib/apiwork/representation/attribute.rb +335 -0
- data/lib/apiwork/representation/base.rb +819 -0
- data/lib/apiwork/representation/deserializer.rb +95 -0
- data/lib/apiwork/representation/element.rb +128 -0
- data/lib/apiwork/representation/inheritance.rb +78 -0
- data/lib/apiwork/representation/model_detector.rb +75 -0
- data/lib/apiwork/representation/root_key.rb +35 -0
- data/lib/apiwork/representation/serializer.rb +127 -0
- data/lib/apiwork/request.rb +79 -0
- data/lib/apiwork/response.rb +56 -0
- data/lib/apiwork/union.rb +102 -0
- data/lib/apiwork/version.rb +2 -2
- data/lib/apiwork.rb +61 -3
- data/lib/generators/apiwork/api_generator.rb +38 -0
- data/lib/generators/apiwork/contract_generator.rb +25 -0
- data/lib/generators/apiwork/install_generator.rb +27 -0
- data/lib/generators/apiwork/representation_generator.rb +25 -0
- data/lib/generators/apiwork/templates/api/api.rb.tt +4 -0
- data/lib/generators/apiwork/templates/contract/contract.rb.tt +6 -0
- data/lib/generators/apiwork/templates/install/application_contract.rb.tt +5 -0
- data/lib/generators/apiwork/templates/install/application_representation.rb.tt +5 -0
- data/lib/generators/apiwork/templates/representation/representation.rb.tt +6 -0
- data/lib/tasks/apiwork.rake +102 -0
- metadata +319 -19
- data/.rubocop.yml +0 -8
- data/sig/apiwork.rbs +0 -4
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Apiwork
|
|
4
|
+
class Union
|
|
5
|
+
attr_reader :discriminator,
|
|
6
|
+
:variants
|
|
7
|
+
|
|
8
|
+
def initialize(discriminator: nil)
|
|
9
|
+
@discriminator = discriminator
|
|
10
|
+
@variants = []
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# @api public
|
|
14
|
+
# Defines a union variant.
|
|
15
|
+
#
|
|
16
|
+
# @param deprecated [Boolean] (false)
|
|
17
|
+
# Whether deprecated. Metadata included in exports.
|
|
18
|
+
# @param description [String, nil] (nil)
|
|
19
|
+
# The description. Metadata included in exports.
|
|
20
|
+
# @param partial [Boolean] (false)
|
|
21
|
+
# Whether partial. Partial variants include only the specified fields.
|
|
22
|
+
# @param tag [String, nil] (nil)
|
|
23
|
+
# The discriminator tag value. Required when union has a discriminator.
|
|
24
|
+
# @yield block defining the variant type
|
|
25
|
+
# @yieldparam variant [Element]
|
|
26
|
+
# @return [void]
|
|
27
|
+
#
|
|
28
|
+
# @example instance_eval style
|
|
29
|
+
# variant tag: 'card' do
|
|
30
|
+
# object do
|
|
31
|
+
# string :last_four
|
|
32
|
+
# end
|
|
33
|
+
# end
|
|
34
|
+
#
|
|
35
|
+
# @example yield style
|
|
36
|
+
# variant tag: 'card' do |variant|
|
|
37
|
+
# variant.object do |object|
|
|
38
|
+
# object.string :last_four
|
|
39
|
+
# end
|
|
40
|
+
# end
|
|
41
|
+
def variant(deprecated: false, description: nil, partial: false, tag: nil, &block)
|
|
42
|
+
validate_tag!(tag)
|
|
43
|
+
raise ConfigurationError, 'variant requires a block' unless block
|
|
44
|
+
|
|
45
|
+
element = build_element
|
|
46
|
+
block.arity.positive? ? yield(element) : element.instance_eval(&block)
|
|
47
|
+
element.validate!
|
|
48
|
+
|
|
49
|
+
data = {
|
|
50
|
+
deprecated:,
|
|
51
|
+
description:,
|
|
52
|
+
partial:,
|
|
53
|
+
tag:,
|
|
54
|
+
custom_type: element.custom_type,
|
|
55
|
+
enum: element.enum,
|
|
56
|
+
format: element.format,
|
|
57
|
+
max: element.max,
|
|
58
|
+
min: element.min,
|
|
59
|
+
of: element.inner,
|
|
60
|
+
shape: element.shape,
|
|
61
|
+
type: element.type,
|
|
62
|
+
value: element.value,
|
|
63
|
+
}.compact
|
|
64
|
+
|
|
65
|
+
append_or_merge_variant(data, tag)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
private
|
|
69
|
+
|
|
70
|
+
def build_element
|
|
71
|
+
raise NotImplementedError, "#{self.class} must implement #build_element"
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def append_or_merge_variant(data, tag)
|
|
75
|
+
if tag && (index = @variants.find_index { |variant| variant[:tag] == tag })
|
|
76
|
+
existing = @variants[index]
|
|
77
|
+
merge_variant_shapes(existing, data[:shape]) if data[:shape] && existing[:shape]
|
|
78
|
+
data.delete(:shape) if data[:shape] && existing[:shape]
|
|
79
|
+
@variants[index] = existing.merge(data)
|
|
80
|
+
else
|
|
81
|
+
@variants << data
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def merge_variant_shapes(existing_variant, new_shape)
|
|
86
|
+
return unless new_shape.respond_to?(:params)
|
|
87
|
+
|
|
88
|
+
new_shape.params.each do |name, param_options|
|
|
89
|
+
existing_variant[:shape].params[name] =
|
|
90
|
+
(existing_variant[:shape].params[name] || {}).merge(param_options)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def validate_tag!(tag)
|
|
95
|
+
raise ConfigurationError, 'tag can only be used when union has a discriminator' if tag.present? && @discriminator.nil?
|
|
96
|
+
|
|
97
|
+
return unless @discriminator.present? && tag.blank?
|
|
98
|
+
|
|
99
|
+
raise ConfigurationError, 'tag is required for all variants when union has a discriminator'
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
data/lib/apiwork/version.rb
CHANGED
data/lib/apiwork.rb
CHANGED
|
@@ -1,8 +1,66 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
require 'zeitwerk'
|
|
4
|
+
require_relative 'apiwork/version'
|
|
4
5
|
|
|
5
6
|
module Apiwork
|
|
6
|
-
class
|
|
7
|
-
|
|
7
|
+
class << self
|
|
8
|
+
def call(env)
|
|
9
|
+
routes.call(env)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def prepare!(eager_load: false)
|
|
13
|
+
API.clear!
|
|
14
|
+
Adapter.clear!
|
|
15
|
+
ErrorCode.clear!
|
|
16
|
+
Export.clear!
|
|
17
|
+
|
|
18
|
+
Adapter.register_defaults!
|
|
19
|
+
ErrorCode.register_defaults!
|
|
20
|
+
Export.register_defaults!
|
|
21
|
+
|
|
22
|
+
load_api_definitions!
|
|
23
|
+
eager_load_representations! if eager_load
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def routes
|
|
29
|
+
return draw_routes if Rails.env.development?
|
|
30
|
+
|
|
31
|
+
@routes ||= draw_routes
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def draw_routes
|
|
35
|
+
API::Router.draw
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def eager_load_representations!
|
|
39
|
+
Dir[Rails.root.join('app/representations/**/*.rb')].sort.each(&method(:require_dependency))
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def load_api_definitions!
|
|
43
|
+
Dir[Rails.root.join('config/apis/**/*.rb')].sort.each(&method(:load))
|
|
44
|
+
end
|
|
45
|
+
end
|
|
8
46
|
end
|
|
47
|
+
|
|
48
|
+
loader = Zeitwerk::Loader.for_gem
|
|
49
|
+
|
|
50
|
+
loader.inflector.inflect(
|
|
51
|
+
'api' => 'API',
|
|
52
|
+
'api_builder' => 'APIBuilder',
|
|
53
|
+
'api_serializer' => 'APISerializer',
|
|
54
|
+
'json_pointer' => 'JSONPointer',
|
|
55
|
+
'json' => 'JSON',
|
|
56
|
+
'open_api' => 'OpenAPI',
|
|
57
|
+
'type_script_mapper' => 'TypeScriptMapper',
|
|
58
|
+
'uuid' => 'UUID',
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
loader.ignore("#{__dir__}/rubocop")
|
|
62
|
+
loader.ignore("#{__dir__}/generators")
|
|
63
|
+
|
|
64
|
+
loader.setup
|
|
65
|
+
|
|
66
|
+
require_relative 'apiwork/engine' if defined?(Rails::Engine)
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Apiwork
|
|
4
|
+
module Generators
|
|
5
|
+
class ApiGenerator < Rails::Generators::Base
|
|
6
|
+
source_root File.expand_path('templates/api', __dir__)
|
|
7
|
+
|
|
8
|
+
argument :mount_path, desc: 'The API mount path (e.g., /api/v1 or /)', type: :string
|
|
9
|
+
|
|
10
|
+
desc 'Creates an Apiwork API definition'
|
|
11
|
+
|
|
12
|
+
def create_api_definition
|
|
13
|
+
template 'api.rb.tt', "config/apis/#{file_name}.rb"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
def file_name
|
|
19
|
+
path_segments.empty? ? 'root' : path_segments.join('_')
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def api_mount_path
|
|
23
|
+
path_segments.empty? ? '/' : "/#{path_segments.join('/')}"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def path_segments
|
|
27
|
+
@path_segments ||= normalize(mount_path)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def normalize(input)
|
|
31
|
+
normalized = input.to_s.gsub('::', '/').underscore.delete_prefix('/').strip
|
|
32
|
+
return [] if normalized.empty?
|
|
33
|
+
|
|
34
|
+
normalized.split('/')
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Apiwork
|
|
4
|
+
module Generators
|
|
5
|
+
class ContractGenerator < Rails::Generators::NamedBase
|
|
6
|
+
source_root File.expand_path('templates/contract', __dir__)
|
|
7
|
+
|
|
8
|
+
desc 'Creates an Apiwork contract'
|
|
9
|
+
|
|
10
|
+
def create_contract
|
|
11
|
+
template 'contract.rb.tt', contract_path
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
private
|
|
15
|
+
|
|
16
|
+
def contract_path
|
|
17
|
+
File.join('app/contracts', class_path, "#{file_name}_contract.rb")
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def parent_class_name
|
|
21
|
+
'ApplicationContract'
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Apiwork
|
|
4
|
+
module Generators
|
|
5
|
+
class InstallGenerator < Rails::Generators::Base
|
|
6
|
+
source_root File.expand_path('templates/install', __dir__)
|
|
7
|
+
|
|
8
|
+
desc 'Creates the Apiwork directory structure'
|
|
9
|
+
|
|
10
|
+
def create_application_contract
|
|
11
|
+
template 'application_contract.rb.tt', 'app/contracts/application_contract.rb'
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def create_application_representation
|
|
15
|
+
template 'application_representation.rb.tt', 'app/representations/application_representation.rb'
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def create_apis_directory
|
|
19
|
+
empty_directory 'config/apis'
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def add_route
|
|
23
|
+
route "mount Apiwork => '/'"
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Apiwork
|
|
4
|
+
module Generators
|
|
5
|
+
class RepresentationGenerator < Rails::Generators::NamedBase
|
|
6
|
+
source_root File.expand_path('templates/representation', __dir__)
|
|
7
|
+
|
|
8
|
+
desc 'Creates an Apiwork representation'
|
|
9
|
+
|
|
10
|
+
def create_representation
|
|
11
|
+
template 'representation.rb.tt', representation_path
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
private
|
|
15
|
+
|
|
16
|
+
def representation_path
|
|
17
|
+
File.join('app/representations', class_path, "#{file_name}_representation.rb")
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def parent_class_name
|
|
21
|
+
'ApplicationRepresentation'
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
namespace :apiwork do
|
|
4
|
+
namespace :docs do
|
|
5
|
+
desc 'Generate API reference documentation from YARD comments'
|
|
6
|
+
task reference: :environment do
|
|
7
|
+
require 'apiwork/reference_generator'
|
|
8
|
+
Apiwork::ReferenceGenerator.generate
|
|
9
|
+
puts 'Reference documentation generated in docs/reference/'
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
namespace :export do
|
|
14
|
+
desc 'Write exports to files'
|
|
15
|
+
task write: :environment do
|
|
16
|
+
# Load API definitions
|
|
17
|
+
Dir[Rails.root.join('config/apis/**/*.rb')].sort.each { |file| load file }
|
|
18
|
+
|
|
19
|
+
api_base_path = ENV['API_PATH']
|
|
20
|
+
export_name = ENV['EXPORT_NAME']&.to_sym
|
|
21
|
+
format = ENV['FORMAT']&.to_sym
|
|
22
|
+
output = ENV['OUTPUT']
|
|
23
|
+
|
|
24
|
+
unless output
|
|
25
|
+
puts 'Error: OUTPUT required'
|
|
26
|
+
puts ''
|
|
27
|
+
puts 'Usage: rake apiwork:export:write OUTPUT=path [API_PATH=/api/v1] [EXPORT_NAME=openapi] [OPTIONS...]'
|
|
28
|
+
puts ''
|
|
29
|
+
puts 'Examples:'
|
|
30
|
+
puts ' rake apiwork:export:write OUTPUT=public/exports'
|
|
31
|
+
puts ' rake apiwork:export:write API_PATH=/api/v1 OUTPUT=public/exports'
|
|
32
|
+
puts ' rake apiwork:export:write API_PATH=/api/v1 EXPORT_NAME=openapi OUTPUT=public/openapi.json'
|
|
33
|
+
puts ' rake apiwork:export:write EXPORT_NAME=openapi FORMAT=yaml OUTPUT=public/openapi.yaml'
|
|
34
|
+
puts ' rake apiwork:export:write EXPORT_NAME=zod KEY_FORMAT=camel OUTPUT=public/exports'
|
|
35
|
+
puts ' rake apiwork:export:write OUTPUT=public/exports LOCALE=sv'
|
|
36
|
+
puts ''
|
|
37
|
+
puts 'Available exports:'
|
|
38
|
+
puts " #{Apiwork::Export.keys.join(', ')}"
|
|
39
|
+
puts ''
|
|
40
|
+
puts 'Built-in options (uppercase ENV vars):'
|
|
41
|
+
puts ' FORMAT: json, yaml (only for data exports like openapi)'
|
|
42
|
+
puts ' KEY_FORMAT: keep, camel, underscore'
|
|
43
|
+
puts " LOCALE: #{I18n.available_locales.join(', ')}"
|
|
44
|
+
puts ''
|
|
45
|
+
puts 'Custom export options are also supported via ENV vars.'
|
|
46
|
+
exit 1
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
custom_options = if export_name
|
|
50
|
+
Apiwork::Export.find!(export_name).extract_options_from_env
|
|
51
|
+
else
|
|
52
|
+
{}
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
begin
|
|
56
|
+
Apiwork::Export::Pipeline.write(
|
|
57
|
+
api_base_path:,
|
|
58
|
+
export_name:,
|
|
59
|
+
format:,
|
|
60
|
+
output:,
|
|
61
|
+
**custom_options,
|
|
62
|
+
)
|
|
63
|
+
rescue ArgumentError => e
|
|
64
|
+
puts "Error: #{e.message}"
|
|
65
|
+
exit 1
|
|
66
|
+
rescue Apiwork::ConfigurationError => e
|
|
67
|
+
puts "Error: #{e.message}"
|
|
68
|
+
exit 1
|
|
69
|
+
rescue StandardError => e
|
|
70
|
+
puts "Error: #{e.message}"
|
|
71
|
+
puts e.backtrace.first(5).join("\n") if ENV['VERBOSE']
|
|
72
|
+
exit 1
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
desc 'Clean generated export files'
|
|
77
|
+
task clean: :environment do
|
|
78
|
+
output = ENV['OUTPUT']
|
|
79
|
+
|
|
80
|
+
unless output
|
|
81
|
+
puts 'Error: OUTPUT required'
|
|
82
|
+
puts ''
|
|
83
|
+
puts 'Usage: rake apiwork:export:clean OUTPUT=path'
|
|
84
|
+
puts ''
|
|
85
|
+
puts 'Examples:'
|
|
86
|
+
puts ' rake apiwork:export:clean OUTPUT=public/exports'
|
|
87
|
+
puts ' rake apiwork:export:clean OUTPUT=public/openapi.json'
|
|
88
|
+
exit 1
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
begin
|
|
92
|
+
Apiwork::Export::Pipeline.clean(output:)
|
|
93
|
+
rescue ArgumentError => e
|
|
94
|
+
puts "Error: #{e.message}"
|
|
95
|
+
exit 1
|
|
96
|
+
rescue StandardError => e
|
|
97
|
+
puts "Error: #{e.message}"
|
|
98
|
+
exit 1
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|