jekyll-openapi 0.2.0 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 115a158c4677920431b493e1d8941d8bc84f7ac71f0d9813f386ed9a1391878d
4
- data.tar.gz: 2444e2822f9181d34c4ade929b0903861d43ea6b9a9376db09baef3abe779906
3
+ metadata.gz: 7c592a43f900f36f1afbfc4432c1dc6b9e55302ec6e481bc6284596a728c36ea
4
+ data.tar.gz: 047ef58c76751ad0cc91415d838dc367ea302f83b4f88fa95f430397db3563b3
5
5
  SHA512:
6
- metadata.gz: 800e3dd82c5c47f0b5b1e31319199ffc5045eb72ebc5285062ab2ecb0e831bcb56a842b7fd168bd239b9b4ac194056c1a2d059650361f6cf484857ac3d0704de
7
- data.tar.gz: 677f5f4053e77ec018823e08e24cf89e3a2b44c70ea5267368eee22e83195407872487f134646743a2dcfca9bc78d284501b3140e12c771598e0bfa4bca0e1fc
6
+ metadata.gz: 9a2fe7b1a1ca251142a4592cc1222aed94895e1dd8dbe4d13b7106436e4a50812e08c0756bb5051c24f3918ea99c4e0e348bb46ad9158d89848187c5a9e75c9d
7
+ data.tar.gz: 93542f7e0c5bdafa05d21442d67044ab751642163571dd01671165a6af69a21fd94461dd96150ea1bbf49b9e3594686194dbca97f3525fe1d33ccec68717b705
data/README.md CHANGED
@@ -1,7 +1,9 @@
1
1
  # jekyll-openapi
2
2
 
3
3
  A (mostly) spec-compliant [OpenAPI 3.1](https://spec.openapis.org/oas/v3.1.0) toolkit for
4
- Liquid-based static site generators (Jekyll in particular).
4
+ Liquid-based static site generators (Jekyll in particular), with partial
5
+ [OpenAPI 3.2](https://spec.openapis.org/oas/v3.2.0) support (see
6
+ [OpenAPI 3.2 support](#openapi-32-support)).
5
7
 
6
8
  It deliberately does **not** render HTML. The gem provides:
7
9
 
@@ -75,19 +77,20 @@ title: API Reference
75
77
  operation, grouped by tag. That's a complete, working integration.
76
78
 
77
79
  `oapi_operations` already does the tedious parts for you: it skips
78
- non-operation path-item keys, handles `x-` extension methods, filters by tag,
79
- and merges path-level parameters into each operation.
80
+ non-operation path-item keys, handles `x-` extension methods and OpenAPI 3.2
81
+ `additionalOperations`, filters by tag, and merges path-level parameters into
82
+ each operation.
80
83
 
81
84
  Each `op` in the loop is a plain Hash you can traverse further:
82
85
 
83
86
  | key | content |
84
87
  |------------------------|------------------------------------------------------|
85
88
  | `"path"` | `"/pets/{petId}"` |
86
- | `"method"` | normalized method, `x-` prefix stripped (`"mkcol"`) |
87
- | `"raw_method"` | the literal key (`"x-mkcol"`) |
89
+ | `"method"` | normalized method, lowercase, `x-` prefix stripped (`"mkcol"`) |
90
+ | `"raw_method"` | the literal key (`"x-mkcol"`, `"MKCOL"`) |
88
91
  | `"operation"` | the Operation object, dereferenced |
89
92
  | `"parameters"` | path-level + operation-level parameters, merged (operation wins on same name/location) |
90
- | `"grouped_parameters"` | same, grouped: `{"query" => [...], "path" => [...], "header" => [...], "cookie" => [...]}` |
93
+ | `"grouped_parameters"` | same, grouped: `{"query" => [...], "querystring" => [...], "path" => [...], "header" => [...], "cookie" => [...]}` |
91
94
 
92
95
  ### Going further
93
96
 
@@ -159,6 +162,51 @@ when followed; recursive schemas terminate (rendered as a link, or their name in
159
162
  the text renderers); invalid schemas render as `""`. Your build never breaks on
160
163
  a bad spec.
161
164
 
165
+ ## OpenAPI 3.2 support
166
+
167
+ Partial. Because the model hands templates plain hashes, most new 3.2 *fields*
168
+ flow through untouched and are usable today; "supported" below means the
169
+ library actively understands the feature, "passthrough" means the raw data
170
+ reaches your template but no helper interprets it.
171
+
172
+ Supported:
173
+
174
+ - [x] `additionalOperations` — enumerated by `oapi_operations` like any other
175
+ operation, with path-level parameters merged; `method` is the lowercased
176
+ method name, `raw_method` the literal key (`"PROPFIND"`). Gives webDAV-style
177
+ APIs first-class treatment (previously only reachable via `x-` methods).
178
+ - [x] The `query` HTTP method — recognized as a first-class path-item key.
179
+ - [x] Tag `summary` — passes through `oapi_tags` (tested); use it as a short
180
+ display name where `description` is prose.
181
+ - [x] `in: querystring` parameters — grouped under their own `"querystring"`
182
+ key by `oapi_parameters` / `grouped_parameters` (the parameter is
183
+ `content`-based: render its media-type schema, not a name/value pair). An
184
+ operation-level querystring parameter overrides a path-level one regardless
185
+ of name, and mixing it with `in: query` parameters warns (the spec forbids
186
+ it) but keeps both.
187
+
188
+ Passthrough (data reaches templates, no helper logic):
189
+
190
+ - [ ] Tag `parent` / `kind` — the fields are readable, but `oapi_operations`
191
+ and `oapi_tags` treat tags as a flat list: no hierarchy building, no
192
+ filtering by kind.
193
+ - [ ] Response `summary`, Server `name` — readable on the raw objects.
194
+ - [ ] Security scheme additions (`deviceAuthorization` flow,
195
+ `oauth2MetadataUrl`, `deprecated`) — readable via `oapi_security_schemes`.
196
+
197
+ Not supported (TODO):
198
+
199
+ - [ ] Streaming / sequential media types — `itemSchema`, `itemEncoding` and
200
+ `prefixEncoding` are ignored by the schema renderers and `oapi_examples`.
201
+ - [ ] Example Object `dataValue` / `serializedValue` — `oapi_examples` only
202
+ reads `value`.
203
+ - [ ] `xml.nodeType` — the XML renderer still keys off the 3.1 `attribute` /
204
+ `wrapped` flags.
205
+ - [ ] `$self` and multi-document descriptions — consistent with the existing
206
+ local-`$ref`s-only policy.
207
+ - [ ] `components.mediaTypes` reuse — untested; generic local `$ref`
208
+ resolution may already handle it, but no guarantees.
209
+
162
210
  ## Compliance notes
163
211
 
164
212
  Intentional simplifications, in the spirit of "readable docs over exhaustive
@@ -178,8 +226,8 @@ fidelity":
178
226
  rake test # or: ruby -Ilib -Itest test/test_<name>.rb
179
227
  ```
180
228
 
181
- Tests run against generic fixtures (`test/fixtures/petstore.yml`); when the gem
229
+ Tests run against generic fixtures (`test/fixtures/petstore.yml`, a pristine
230
+ OpenAPI 3.1 document, and `test/fixtures/filestore.yml`, a WebDAV-flavored
231
+ OpenAPI 3.2 one); when the gem
182
232
  sources live inside the eCorpus_doc repository, an extra integration suite runs
183
233
  the whole pipeline over the real eCorpus API definition.
184
- </content>
185
- </invoke>
@@ -14,7 +14,7 @@ module JekyllOpenAPI
14
14
  # page needs. `$ref`s stay navigable but keep their names (see Reference), so
15
15
  # templates can link named schemas instead of inlining them.
16
16
  class Document
17
- HTTP_METHODS = %w[get put post delete options head patch trace].freeze
17
+ HTTP_METHODS = %w[get put post delete options head patch trace query].freeze
18
18
  PATH_ITEM_FIELDS = %w[summary description servers parameters $ref].freeze
19
19
 
20
20
  attr_reader :data
@@ -116,32 +116,49 @@ module JekyllOpenAPI
116
116
  # follow it so referenced operations are not silently dropped.
117
117
  path_item = follow(path_item)
118
118
  next [] unless path_item.is_a?(Hash)
119
- path_item.filter_map do |key, operation|
120
- next if PATH_ITEM_FIELDS.include?(key)
121
- next unless HTTP_METHODS.include?(key) || key.start_with?("x-")
122
- operation = follow(operation)
123
- next unless operation.is_a?(Hash)
124
- # `x-` is OpenAPI's extension mechanism, not a method namespace: a
125
- # path-item extension is only an operation when it actually carries an
126
- # Operation Object. `operationId`/`responses` mark one; vendor metadata
127
- # (x-internal, x-codegen, …) has neither and must not become a phantom
128
- # method. Standard HTTP verbs are always operations.
129
- next if key.start_with?("x-") &&
130
- !(operation.key?("operationId") || operation.key?("responses"))
131
-
132
- params = Parameters.merge(path_item["parameters"], operation["parameters"])
133
- {
134
- "path" => path,
135
- "method" => key.delete_prefix("x-"),
136
- "raw_method" => key,
137
- "operation" => operation,
138
- "parameters" => params,
139
- "grouped_parameters" => Parameters.group(params, logger: @logger),
140
- }
119
+ path_item.flat_map do |key, value|
120
+ if key == "additionalOperations"
121
+ # OpenAPI 3.2: a map of custom HTTP method name => Operation Object.
122
+ value = follow(value)
123
+ next [] unless value.is_a?(Hash)
124
+ value.filter_map do |method, operation|
125
+ build_operation(path, path_item, method.downcase, method, operation)
126
+ end
127
+ else
128
+ next [] if PATH_ITEM_FIELDS.include?(key)
129
+ next [] unless HTTP_METHODS.include?(key) || key.start_with?("x-")
130
+ operation = follow(value)
131
+ # `x-` is OpenAPI's extension mechanism, not a method namespace: a
132
+ # path-item extension is only an operation when it actually carries an
133
+ # Operation Object. `operationId`/`responses` mark one; vendor metadata
134
+ # (x-internal, x-codegen, …) has neither and must not become a phantom
135
+ # method. Standard HTTP verbs are always operations.
136
+ next [] if operation.is_a?(Hash) && key.start_with?("x-") &&
137
+ !(operation.key?("operationId") || operation.key?("responses"))
138
+
139
+ [build_operation(path, path_item, key.delete_prefix("x-"), key, operation)].compact
140
+ end
141
141
  end
142
142
  end
143
143
  end
144
144
 
145
+ # @return [Hash, nil] a normalized operation entry, or nil when `operation`
146
+ # is not an Operation Object
147
+ def build_operation(path, path_item, method, raw_method, operation)
148
+ operation = follow(operation)
149
+ return unless operation.is_a?(Hash)
150
+
151
+ params = Parameters.merge(path_item["parameters"], operation["parameters"])
152
+ {
153
+ "path" => path,
154
+ "method" => method,
155
+ "raw_method" => raw_method,
156
+ "operation" => operation,
157
+ "parameters" => params,
158
+ "grouped_parameters" => Parameters.group(params, logger: @logger),
159
+ }
160
+ end
161
+
145
162
  # Resolve a $ref used where a mapping (path item / operation) is expected.
146
163
  def follow(node)
147
164
  node.is_a?(Reference) ? node.resolve : node
@@ -5,7 +5,9 @@ module JekyllOpenAPI
5
5
  # Helpers for OpenAPI Parameter objects.
6
6
  # @see https://spec.openapis.org/oas/v3.1.0.html#parameter-object
7
7
  module Parameters
8
- LOCATIONS = %w[query path header cookie].freeze
8
+ # "querystring" is OpenAPI 3.2: a single parameter describing the entire
9
+ # query string through `content` (its `name` is not used in serialization).
10
+ LOCATIONS = %w[query querystring path header cookie].freeze
9
11
 
10
12
  # A parameter may arrive inline (Hash) or as a $ref (Reference). Both read
11
13
  # like a mapping, so both are valid parameter objects here.
@@ -15,7 +17,7 @@ module JekyllOpenAPI
15
17
 
16
18
  ##
17
19
  # Groups a parameter list by location ("in").
18
- # Always returns all four location keys so templates can test emptiness.
20
+ # Always returns all five location keys so templates can test emptiness.
19
21
  # @param params [Array<Hash>, nil]
20
22
  # @return [Hash{String => Array<Hash>}]
21
23
  def self.group(params, logger: JekyllOpenAPI.logger)
@@ -28,18 +30,24 @@ module JekyllOpenAPI
28
30
  logger.warn("invalid parameter location #{location.inspect} in #{param.inspect}")
29
31
  end
30
32
  end
33
+ unless output["querystring"].empty? || output["query"].empty?
34
+ logger.warn("`in: querystring` must not be combined with `in: query` parameters")
35
+ end
31
36
  output
32
37
  end
33
38
 
34
39
  ##
35
40
  # Merges path-item level and operation level parameter lists.
36
41
  # An operation parameter overrides a path one with the same (name, in) pair.
42
+ # A querystring parameter overrides on location alone: its name is not used
43
+ # in serialization and only one may describe the query string.
37
44
  # @return [Array<Hash>]
38
45
  def self.merge(path_params, operation_params)
39
46
  merged = {}
40
47
  (Array(path_params) + Array(operation_params)).each do |param|
41
48
  next unless mapping?(param)
42
- merged[[param["name"], param["in"]]] = param
49
+ name = param["in"] == "querystring" ? nil : param["name"]
50
+ merged[[name, param["in"]]] = param
43
51
  end
44
52
  merged.values
45
53
  end
@@ -1,3 +1,3 @@
1
1
  module JekyllOpenAPI
2
- VERSION = "0.2.0"
2
+ VERSION = "0.3.0"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jekyll-openapi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sebastien Dumetz
@@ -9,6 +9,20 @@ bindir: bin
9
9
  cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: base64
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '0'
19
+ type: :development
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '0'
12
26
  - !ruby/object:Gem::Dependency
13
27
  name: liquid
14
28
  requirement: !ruby/object:Gem::Requirement