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.
Files changed (202) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +2 -2
  3. data/README.md +117 -1
  4. data/Rakefile +5 -3
  5. data/app/controllers/apiwork/errors_controller.rb +13 -0
  6. data/app/controllers/apiwork/exports_controller.rb +22 -0
  7. data/lib/apiwork/abstractable.rb +26 -0
  8. data/lib/apiwork/adapter/base.rb +369 -0
  9. data/lib/apiwork/adapter/builder/api/base.rb +66 -0
  10. data/lib/apiwork/adapter/builder/contract/base.rb +86 -0
  11. data/lib/apiwork/adapter/capability/api/base.rb +51 -0
  12. data/lib/apiwork/adapter/capability/api/scope.rb +64 -0
  13. data/lib/apiwork/adapter/capability/base.rb +291 -0
  14. data/lib/apiwork/adapter/capability/contract/base.rb +37 -0
  15. data/lib/apiwork/adapter/capability/contract/scope.rb +110 -0
  16. data/lib/apiwork/adapter/capability/operation/base.rb +172 -0
  17. data/lib/apiwork/adapter/capability/operation/metadata_shape.rb +165 -0
  18. data/lib/apiwork/adapter/capability/result.rb +21 -0
  19. data/lib/apiwork/adapter/capability/runner.rb +56 -0
  20. data/lib/apiwork/adapter/capability/transformer/request/base.rb +72 -0
  21. data/lib/apiwork/adapter/capability/transformer/response/base.rb +45 -0
  22. data/lib/apiwork/adapter/registry.rb +16 -0
  23. data/lib/apiwork/adapter/serializer/error/base.rb +72 -0
  24. data/lib/apiwork/adapter/serializer/error/default/api_builder.rb +32 -0
  25. data/lib/apiwork/adapter/serializer/error/default.rb +37 -0
  26. data/lib/apiwork/adapter/serializer/resource/base.rb +84 -0
  27. data/lib/apiwork/adapter/serializer/resource/default/contract_builder.rb +209 -0
  28. data/lib/apiwork/adapter/serializer/resource/default.rb +39 -0
  29. data/lib/apiwork/adapter/standard/capability/filtering/api_builder.rb +75 -0
  30. data/lib/apiwork/adapter/standard/capability/filtering/constants.rb +37 -0
  31. data/lib/apiwork/adapter/standard/capability/filtering/contract_builder.rb +193 -0
  32. data/lib/apiwork/adapter/standard/capability/filtering/operation/filter/builder.rb +47 -0
  33. data/lib/apiwork/adapter/standard/capability/filtering/operation/filter/operator_builder.rb +36 -0
  34. data/lib/apiwork/adapter/standard/capability/filtering/operation/filter.rb +462 -0
  35. data/lib/apiwork/adapter/standard/capability/filtering/operation.rb +22 -0
  36. data/lib/apiwork/adapter/standard/capability/filtering/request_transformer.rb +47 -0
  37. data/lib/apiwork/adapter/standard/capability/filtering.rb +18 -0
  38. data/lib/apiwork/adapter/standard/capability/including/contract_builder.rb +169 -0
  39. data/lib/apiwork/adapter/standard/capability/including/operation.rb +20 -0
  40. data/lib/apiwork/adapter/standard/capability/including.rb +16 -0
  41. data/lib/apiwork/adapter/standard/capability/pagination/api_builder.rb +34 -0
  42. data/lib/apiwork/adapter/standard/capability/pagination/contract_builder.rb +35 -0
  43. data/lib/apiwork/adapter/standard/capability/pagination/operation/paginate/cursor.rb +84 -0
  44. data/lib/apiwork/adapter/standard/capability/pagination/operation/paginate/offset.rb +66 -0
  45. data/lib/apiwork/adapter/standard/capability/pagination/operation/paginate.rb +24 -0
  46. data/lib/apiwork/adapter/standard/capability/pagination/operation.rb +24 -0
  47. data/lib/apiwork/adapter/standard/capability/pagination.rb +21 -0
  48. data/lib/apiwork/adapter/standard/capability/sorting/api_builder.rb +19 -0
  49. data/lib/apiwork/adapter/standard/capability/sorting/contract_builder.rb +84 -0
  50. data/lib/apiwork/adapter/standard/capability/sorting/operation/sort.rb +83 -0
  51. data/lib/apiwork/adapter/standard/capability/sorting/operation.rb +22 -0
  52. data/lib/apiwork/adapter/standard/capability/sorting.rb +17 -0
  53. data/lib/apiwork/adapter/standard/capability/writing/constants.rb +15 -0
  54. data/lib/apiwork/adapter/standard/capability/writing/contract_builder.rb +253 -0
  55. data/lib/apiwork/adapter/standard/capability/writing/operation/issue_mapper.rb +210 -0
  56. data/lib/apiwork/adapter/standard/capability/writing/operation.rb +32 -0
  57. data/lib/apiwork/adapter/standard/capability/writing/request_transformer.rb +37 -0
  58. data/lib/apiwork/adapter/standard/capability/writing.rb +17 -0
  59. data/lib/apiwork/adapter/standard/includes_resolver.rb +106 -0
  60. data/lib/apiwork/adapter/standard.rb +22 -0
  61. data/lib/apiwork/adapter/wrapper/base.rb +70 -0
  62. data/lib/apiwork/adapter/wrapper/collection/base.rb +60 -0
  63. data/lib/apiwork/adapter/wrapper/collection/default.rb +47 -0
  64. data/lib/apiwork/adapter/wrapper/error/base.rb +30 -0
  65. data/lib/apiwork/adapter/wrapper/error/default.rb +34 -0
  66. data/lib/apiwork/adapter/wrapper/member/base.rb +58 -0
  67. data/lib/apiwork/adapter/wrapper/member/default.rb +40 -0
  68. data/lib/apiwork/adapter/wrapper/shape.rb +203 -0
  69. data/lib/apiwork/adapter.rb +50 -0
  70. data/lib/apiwork/api/base.rb +802 -0
  71. data/lib/apiwork/api/element.rb +110 -0
  72. data/lib/apiwork/api/enum_registry/definition.rb +51 -0
  73. data/lib/apiwork/api/enum_registry.rb +98 -0
  74. data/lib/apiwork/api/info/contact.rb +67 -0
  75. data/lib/apiwork/api/info/license.rb +50 -0
  76. data/lib/apiwork/api/info/server.rb +50 -0
  77. data/lib/apiwork/api/info.rb +221 -0
  78. data/lib/apiwork/api/object.rb +235 -0
  79. data/lib/apiwork/api/registry.rb +33 -0
  80. data/lib/apiwork/api/representation_registry.rb +76 -0
  81. data/lib/apiwork/api/resource/action.rb +41 -0
  82. data/lib/apiwork/api/resource.rb +648 -0
  83. data/lib/apiwork/api/router.rb +104 -0
  84. data/lib/apiwork/api/type_registry/definition.rb +117 -0
  85. data/lib/apiwork/api/type_registry.rb +99 -0
  86. data/lib/apiwork/api/union.rb +49 -0
  87. data/lib/apiwork/api.rb +85 -0
  88. data/lib/apiwork/configurable.rb +71 -0
  89. data/lib/apiwork/configuration/option.rb +125 -0
  90. data/lib/apiwork/configuration/validatable.rb +25 -0
  91. data/lib/apiwork/configuration.rb +95 -0
  92. data/lib/apiwork/configuration_error.rb +6 -0
  93. data/lib/apiwork/constraint_error.rb +20 -0
  94. data/lib/apiwork/contract/action/request.rb +79 -0
  95. data/lib/apiwork/contract/action/response.rb +87 -0
  96. data/lib/apiwork/contract/action.rb +258 -0
  97. data/lib/apiwork/contract/base.rb +714 -0
  98. data/lib/apiwork/contract/element.rb +130 -0
  99. data/lib/apiwork/contract/object/coercer.rb +194 -0
  100. data/lib/apiwork/contract/object/deserializer.rb +101 -0
  101. data/lib/apiwork/contract/object/transformer.rb +95 -0
  102. data/lib/apiwork/contract/object/validator/result.rb +27 -0
  103. data/lib/apiwork/contract/object/validator.rb +734 -0
  104. data/lib/apiwork/contract/object.rb +566 -0
  105. data/lib/apiwork/contract/request_parser/result.rb +25 -0
  106. data/lib/apiwork/contract/request_parser.rb +72 -0
  107. data/lib/apiwork/contract/response_parser/result.rb +25 -0
  108. data/lib/apiwork/contract/response_parser.rb +35 -0
  109. data/lib/apiwork/contract/union.rb +56 -0
  110. data/lib/apiwork/contract_error.rb +9 -0
  111. data/lib/apiwork/controller.rb +300 -0
  112. data/lib/apiwork/domain_error.rb +13 -0
  113. data/lib/apiwork/element.rb +386 -0
  114. data/lib/apiwork/engine.rb +20 -0
  115. data/lib/apiwork/error.rb +6 -0
  116. data/lib/apiwork/error_code/definition.rb +63 -0
  117. data/lib/apiwork/error_code/registry.rb +18 -0
  118. data/lib/apiwork/error_code.rb +132 -0
  119. data/lib/apiwork/export/base.rb +291 -0
  120. data/lib/apiwork/export/open_api.rb +600 -0
  121. data/lib/apiwork/export/pipeline/writer.rb +66 -0
  122. data/lib/apiwork/export/pipeline.rb +84 -0
  123. data/lib/apiwork/export/registry.rb +16 -0
  124. data/lib/apiwork/export/surface_resolver.rb +189 -0
  125. data/lib/apiwork/export/type_analysis.rb +170 -0
  126. data/lib/apiwork/export/type_script.rb +23 -0
  127. data/lib/apiwork/export/type_script_mapper.rb +349 -0
  128. data/lib/apiwork/export/zod.rb +39 -0
  129. data/lib/apiwork/export/zod_mapper.rb +421 -0
  130. data/lib/apiwork/export.rb +80 -0
  131. data/lib/apiwork/http_error.rb +16 -0
  132. data/lib/apiwork/introspection/action/request.rb +66 -0
  133. data/lib/apiwork/introspection/action/response.rb +57 -0
  134. data/lib/apiwork/introspection/action.rb +124 -0
  135. data/lib/apiwork/introspection/api/info/contact.rb +59 -0
  136. data/lib/apiwork/introspection/api/info/license.rb +49 -0
  137. data/lib/apiwork/introspection/api/info/server.rb +50 -0
  138. data/lib/apiwork/introspection/api/info.rb +107 -0
  139. data/lib/apiwork/introspection/api/resource.rb +83 -0
  140. data/lib/apiwork/introspection/api.rb +92 -0
  141. data/lib/apiwork/introspection/contract.rb +63 -0
  142. data/lib/apiwork/introspection/dump/action.rb +101 -0
  143. data/lib/apiwork/introspection/dump/api.rb +119 -0
  144. data/lib/apiwork/introspection/dump/contract.rb +129 -0
  145. data/lib/apiwork/introspection/dump/param.rb +486 -0
  146. data/lib/apiwork/introspection/dump/resource.rb +112 -0
  147. data/lib/apiwork/introspection/dump/type.rb +339 -0
  148. data/lib/apiwork/introspection/dump.rb +17 -0
  149. data/lib/apiwork/introspection/enum.rb +63 -0
  150. data/lib/apiwork/introspection/error_code.rb +44 -0
  151. data/lib/apiwork/introspection/param/array.rb +88 -0
  152. data/lib/apiwork/introspection/param/base.rb +285 -0
  153. data/lib/apiwork/introspection/param/binary.rb +73 -0
  154. data/lib/apiwork/introspection/param/boolean.rb +73 -0
  155. data/lib/apiwork/introspection/param/date.rb +73 -0
  156. data/lib/apiwork/introspection/param/date_time.rb +73 -0
  157. data/lib/apiwork/introspection/param/decimal.rb +121 -0
  158. data/lib/apiwork/introspection/param/integer.rb +131 -0
  159. data/lib/apiwork/introspection/param/literal.rb +45 -0
  160. data/lib/apiwork/introspection/param/number.rb +121 -0
  161. data/lib/apiwork/introspection/param/object.rb +59 -0
  162. data/lib/apiwork/introspection/param/reference.rb +45 -0
  163. data/lib/apiwork/introspection/param/string.rb +122 -0
  164. data/lib/apiwork/introspection/param/time.rb +73 -0
  165. data/lib/apiwork/introspection/param/union.rb +57 -0
  166. data/lib/apiwork/introspection/param/unknown.rb +26 -0
  167. data/lib/apiwork/introspection/param/uuid.rb +73 -0
  168. data/lib/apiwork/introspection/param.rb +31 -0
  169. data/lib/apiwork/introspection/type.rb +129 -0
  170. data/lib/apiwork/introspection.rb +28 -0
  171. data/lib/apiwork/issue.rb +80 -0
  172. data/lib/apiwork/json_pointer.rb +21 -0
  173. data/lib/apiwork/object.rb +1618 -0
  174. data/lib/apiwork/reference_generator.rb +622 -0
  175. data/lib/apiwork/registry.rb +56 -0
  176. data/lib/apiwork/representation/association.rb +391 -0
  177. data/lib/apiwork/representation/attribute.rb +335 -0
  178. data/lib/apiwork/representation/base.rb +819 -0
  179. data/lib/apiwork/representation/deserializer.rb +95 -0
  180. data/lib/apiwork/representation/element.rb +128 -0
  181. data/lib/apiwork/representation/inheritance.rb +78 -0
  182. data/lib/apiwork/representation/model_detector.rb +75 -0
  183. data/lib/apiwork/representation/root_key.rb +35 -0
  184. data/lib/apiwork/representation/serializer.rb +127 -0
  185. data/lib/apiwork/request.rb +79 -0
  186. data/lib/apiwork/response.rb +56 -0
  187. data/lib/apiwork/union.rb +102 -0
  188. data/lib/apiwork/version.rb +2 -2
  189. data/lib/apiwork.rb +61 -3
  190. data/lib/generators/apiwork/api_generator.rb +38 -0
  191. data/lib/generators/apiwork/contract_generator.rb +25 -0
  192. data/lib/generators/apiwork/install_generator.rb +27 -0
  193. data/lib/generators/apiwork/representation_generator.rb +25 -0
  194. data/lib/generators/apiwork/templates/api/api.rb.tt +4 -0
  195. data/lib/generators/apiwork/templates/contract/contract.rb.tt +6 -0
  196. data/lib/generators/apiwork/templates/install/application_contract.rb.tt +5 -0
  197. data/lib/generators/apiwork/templates/install/application_representation.rb.tt +5 -0
  198. data/lib/generators/apiwork/templates/representation/representation.rb.tt +6 -0
  199. data/lib/tasks/apiwork.rake +102 -0
  200. metadata +319 -19
  201. data/.rubocop.yml +0 -8
  202. 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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Apiwork
4
- VERSION = "0.0.0.pre"
5
- end
4
+ VERSION = '0.1.1'
5
+ end
data/lib/apiwork.rb CHANGED
@@ -1,8 +1,66 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "apiwork/version"
3
+ require 'zeitwerk'
4
+ require_relative 'apiwork/version'
4
5
 
5
6
  module Apiwork
6
- class Error < StandardError; end
7
- # Your code goes here...
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,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ Apiwork::API.define '<%= api_mount_path %>' do
4
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ <% module_namespacing do -%>
4
+ class <%= class_name %>Contract < <%= parent_class_name %>
5
+ end
6
+ <% end -%>
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ApplicationContract < Apiwork::Contract::Base
4
+ abstract!
5
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ApplicationRepresentation < Apiwork::Representation::Base
4
+ abstract!
5
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ <% module_namespacing do -%>
4
+ class <%= class_name %>Representation < <%= parent_class_name %>
5
+ end
6
+ <% 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