grape-swagger-rails 1.0.1 → 1.0.2
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/.github/workflows/frontend.yml +1 -1
- data/.github/workflows/rubocop.yml +1 -1
- data/.github/workflows/swagger-ui-update.yml +61 -0
- data/.github/workflows/test.yml +1 -1
- data/CHANGELOG.md +6 -0
- data/README.md +8 -6
- data/app/assets/javascripts/grape_swagger_rails/index.js +21 -1
- data/app/assets/javascripts/grape_swagger_rails/index.min.js +1 -1
- data/app/assets/javascripts/grape_swagger_rails/index.min.js.map +3 -3
- data/app/assets/stylesheets/grape_swagger_rails/index.css +4 -1
- data/frontend/grape_swagger_rails/index.ts +24 -1
- data/lib/grape-swagger-rails/version.rb +1 -1
- data/lib/grape-swagger-rails.rb +2 -1
- data/lib/tasks/swagger_ui.rake +20 -3
- data/spec/features/swagger_spec.rb +26 -0
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5bd45e9462ec3fceba7a6b3b75fc6fee6ad6ce11349b52378ee7aaad8fc429f3
|
|
4
|
+
data.tar.gz: 7d531ce1a74556e0ef0ff17c14bf5515ed255916ccd27f63a1a1ec9ec6d0cadb
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fe07aff0e76be3d93a2e4cd62b1effb5517a17f1d79452ba764166a03d1afa5010de6e04d6789dec767536f5cef004c2c6e431bf3ebe5b166fbb784e56ad133e
|
|
7
|
+
data.tar.gz: 04defb6acca696ffc3c24e3f577091afe5f0829ebf8a0c2c7aea11689b256125a9307483ec3582442210d93adf116893b8cb9871892712a6a3ffdc2cc9fe5e17
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
name: Swagger UI Update
|
|
2
|
+
|
|
3
|
+
"on":
|
|
4
|
+
schedule:
|
|
5
|
+
- cron: "0 8 * * 1"
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: write
|
|
10
|
+
pull-requests: write
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
update:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v6
|
|
17
|
+
|
|
18
|
+
- name: Set up Ruby
|
|
19
|
+
uses: ruby/setup-ruby@v1
|
|
20
|
+
with:
|
|
21
|
+
ruby-version: "3.4"
|
|
22
|
+
bundler-cache: true
|
|
23
|
+
|
|
24
|
+
- name: Check latest Swagger UI release
|
|
25
|
+
id: swagger-ui
|
|
26
|
+
env:
|
|
27
|
+
GH_TOKEN: ${{ github.token }}
|
|
28
|
+
run: |
|
|
29
|
+
current_version="$(ruby -r ./lib/grape-swagger-rails/version -e 'print GrapeSwaggerRails::SWAGGER_UI_VERSION')"
|
|
30
|
+
latest_tag="$(gh api repos/swagger-api/swagger-ui/releases/latest --jq .tag_name)"
|
|
31
|
+
latest_version="${latest_tag#v}"
|
|
32
|
+
|
|
33
|
+
echo "current-version=${current_version}" >> "$GITHUB_OUTPUT"
|
|
34
|
+
echo "latest-tag=${latest_tag}" >> "$GITHUB_OUTPUT"
|
|
35
|
+
echo "latest-version=${latest_version}" >> "$GITHUB_OUTPUT"
|
|
36
|
+
|
|
37
|
+
if [ "$current_version" != "$latest_version" ]; then
|
|
38
|
+
echo "update-needed=true" >> "$GITHUB_OUTPUT"
|
|
39
|
+
else
|
|
40
|
+
echo "update-needed=false" >> "$GITHUB_OUTPUT"
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
- name: Update Swagger UI assets
|
|
44
|
+
if: steps.swagger-ui.outputs.update-needed == 'true'
|
|
45
|
+
env:
|
|
46
|
+
SWAGGER_UI_VERSION: ${{ steps.swagger-ui.outputs.latest-tag }}
|
|
47
|
+
run: bundle exec rake swagger_ui:dist:update
|
|
48
|
+
|
|
49
|
+
- name: Create pull request
|
|
50
|
+
if: steps.swagger-ui.outputs.update-needed == 'true'
|
|
51
|
+
uses: peter-evans/create-pull-request@v7
|
|
52
|
+
with:
|
|
53
|
+
token: ${{ github.token }}
|
|
54
|
+
branch: update-swagger-ui-${{ steps.swagger-ui.outputs.latest-version }}
|
|
55
|
+
delete-branch: true
|
|
56
|
+
commit-message: Bump Swagger UI to ${{ steps.swagger-ui.outputs.latest-version }}
|
|
57
|
+
title: Bump Swagger UI to ${{ steps.swagger-ui.outputs.latest-version }}
|
|
58
|
+
body: |
|
|
59
|
+
Updates bundled Swagger UI assets from swagger-api/swagger-ui `${{ steps.swagger-ui.outputs.latest-tag }}`.
|
|
60
|
+
|
|
61
|
+
Generated by the scheduled Swagger UI update workflow.
|
data/.github/workflows/test.yml
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
* Your contribution here.
|
|
4
4
|
|
|
5
|
+
### 1.0.2 (2026/05/26)
|
|
6
|
+
|
|
7
|
+
* [#162](https://github.com/ruby-grape/grape-swagger-rails/pull/162): Fix vertical alignment for property rows in swagger ui model box - [@moskvin](https://github.com/moskvin).
|
|
8
|
+
* [#160](https://github.com/ruby-grape/grape-swagger-rails/pull/160): Hide Swagger UI's confusing "Clear" button by default; expose `display[:clear_button]` to opt back in - [@moskvin](https://github.com/moskvin).
|
|
9
|
+
* [#159](https://github.com/ruby-grape/grape-swagger-rails/pull/159): Added github action update swagger ui version - [@moskvin](https://github.com/moskvin).
|
|
10
|
+
|
|
5
11
|
### 1.0.1 (2026/05/17)
|
|
6
12
|
|
|
7
13
|
* [#155](https://github.com/ruby-grape/grape-swagger-rails/pull/155): Fix: autoload default spec and restyle version dropdown - [@moskvin](https://github.com/moskvin).
|
data/README.md
CHANGED
|
@@ -46,9 +46,9 @@ This gem is continuously tested against the following stack:
|
|
|
46
46
|
|
|
47
47
|
| Ruby | Rails | Grape | grape-swagger | Swagger UI |
|
|
48
48
|
|-----:|--------:|--------:|--------------:|-----------:|
|
|
49
|
-
| 3.4 | 7.2.2.2 | 1.8.x | 1.6.1 | 5.32.
|
|
50
|
-
| 3.2+ | 7.2.2.2 | 3.1.x | 2.1.4 | 5.32.
|
|
51
|
-
| 3.2+ | 8.1.x | 3.1.x | 2.1.4 | 5.32.
|
|
49
|
+
| 3.4 | 7.2.2.2 | 1.8.x | 1.6.1 | 5.32.6 |
|
|
50
|
+
| 3.2+ | 7.2.2.2 | 3.1.x | 2.1.4 | 5.32.6 |
|
|
51
|
+
| 3.2+ | 8.1.x | 3.1.x | 2.1.4 | 5.32.6 |
|
|
52
52
|
|
|
53
53
|
The dummy app and CI also exercise both supported Rails asset pipelines: Sprockets and Propshaft.
|
|
54
54
|
|
|
@@ -267,7 +267,8 @@ GrapeSwaggerRails.options.display = {
|
|
|
267
267
|
api_key_input: false,
|
|
268
268
|
info_url: false,
|
|
269
269
|
doc_version: false,
|
|
270
|
-
version_stamp: false
|
|
270
|
+
version_stamp: false,
|
|
271
|
+
clear_button: true
|
|
271
272
|
}
|
|
272
273
|
```
|
|
273
274
|
|
|
@@ -277,12 +278,13 @@ Supported keys:
|
|
|
277
278
|
- `info_url`: show or hide the API document URL link
|
|
278
279
|
- `doc_version`: show or hide the API document version label
|
|
279
280
|
- `version_stamp`: show or hide the `OAS 2.0` version stamp
|
|
281
|
+
- `clear_button`: show or hide Swagger UI's "Clear" button that appears next to "Execute" after "Try it out". Hidden by default because the upstream button only resets internal request/response state and leaves user-typed input values on screen, which is confusing (see [swagger-api/swagger-ui#5283](https://github.com/swagger-api/swagger-ui/issues/5283)).
|
|
280
282
|
|
|
281
|
-
By default, all of these options are `true`.
|
|
283
|
+
By default, all of these options are `true` except `clear_button`, which defaults to `false`.
|
|
282
284
|
|
|
283
285
|
### Updating Swagger UI from Dist
|
|
284
286
|
|
|
285
|
-
To update Swagger UI from its [distribution](https://github.com/
|
|
287
|
+
To update Swagger UI from its [distribution](https://github.com/swagger-api/swagger-ui), run `bundle exec rake swagger_ui:dist:update`. Examine the changes carefully.
|
|
286
288
|
|
|
287
289
|
NOTE: This action should be run part of this gem (not your application). In case if you want to
|
|
288
290
|
make it up-to-date, clone the repo, run the rake task, examine the diff, fix any bugs, make sure
|
|
@@ -146,10 +146,27 @@ var initializeSwaggerPage = function () {
|
|
|
146
146
|
},
|
|
147
147
|
};
|
|
148
148
|
};
|
|
149
|
+
// Swagger UI's "Clear" button (next to Execute) is confusing — it resets
|
|
150
|
+
// the internal request / response state but does not clear values still visible
|
|
151
|
+
// in the rendered input fields. Upstream issue swagger-api/swagger-ui#5283
|
|
152
|
+
// has acknowledged the UX problem since 2019 without a fix. Hide by default.
|
|
153
|
+
var hideClearButtonPlugin = function () {
|
|
154
|
+
return {
|
|
155
|
+
wrapComponents: {
|
|
156
|
+
clear: function () { return function () { return null; }; },
|
|
157
|
+
},
|
|
158
|
+
};
|
|
159
|
+
};
|
|
149
160
|
var buildPlugins = function () {
|
|
150
161
|
var configuredPlugins = options.swagger_ui_config && options.swagger_ui_config.plugins;
|
|
151
162
|
var plugins = Array.isArray(configuredPlugins) ? configuredPlugins.slice() : [];
|
|
152
|
-
var displayDefaults = {
|
|
163
|
+
var displayDefaults = {
|
|
164
|
+
api_key_input: true,
|
|
165
|
+
info_url: true,
|
|
166
|
+
doc_version: true,
|
|
167
|
+
version_stamp: true,
|
|
168
|
+
clear_button: false,
|
|
169
|
+
};
|
|
153
170
|
var display = Object.assign({}, displayDefaults, options.display || {});
|
|
154
171
|
if (!display.info_url) {
|
|
155
172
|
plugins.push(hideInfoUrlPlugin);
|
|
@@ -160,6 +177,9 @@ var initializeSwaggerPage = function () {
|
|
|
160
177
|
if (!display.version_stamp) {
|
|
161
178
|
plugins.push(hideVersionStampPlugin);
|
|
162
179
|
}
|
|
180
|
+
if (!display.clear_button) {
|
|
181
|
+
plugins.push(hideClearButtonPlugin);
|
|
182
|
+
}
|
|
163
183
|
return plugins;
|
|
164
184
|
};
|
|
165
185
|
applyTheme(getTheme());
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var safeDecodeURIComponent=function(o){try{return decodeURIComponent(o)}catch{return o}},initializeSwaggerPage=function(){var o=document.documentElement.dataset.swaggerOptions;if(!(!o||typeof SwaggerUIBundle>"u"||typeof SwaggerUIStandalonePreset>"u")){var
|
|
1
|
+
"use strict";var safeDecodeURIComponent=function(o){try{return decodeURIComponent(o)}catch{return o}},initializeSwaggerPage=function(){var o=document.documentElement.dataset.swaggerOptions;if(!(!o||typeof SwaggerUIBundle>"u"||typeof SwaggerUIStandalonePreset>"u")){var t=JSON.parse(o),p=document.getElementById("input_apiKey"),s=document.getElementById("spec-selector"),m=document.getElementById("spec-selector-wrapper"),u=document.getElementById("theme-toggle"),g=document.documentElement,_=function(){return t.theme==="dark"?"dark":"light"},v=function(e){g.dataset.theme=e,g.classList.toggle("dark-mode",e==="dark"),u&&(u.textContent=e==="dark"?"Light Mode":"Dark Mode",u.setAttribute("aria-pressed",String(e==="dark")))},y=function(){if(!p)return"";var e=p.value?p.value.trim():"";return e?t.api_auth==="basic"?"Basic "+btoa(e):t.api_auth==="bearer"?"Bearer "+e:t.api_auth==="token"?'Token token="'.concat(e,'"'):e:""},I=function(e){return e.headers||(e.headers={}),e.headers},h=function(e,n,a){var r=I(e);if(r instanceof Headers){r.set(n,a);return}r[n]=a},d=function(e){return e?/^https?:\/\//.test(e)?e:t.app_url+e:""},S=function(){return Array.isArray(t.urls)?t.urls.map(function(e,n){return typeof e=="string"?{name:e,url:d(e),default:!1}:{name:e.name||e.url||"Spec "+(n+1),url:d(e.url),default:!!e.default}}).filter(function(e){return!!e.url}):[]},k=function(e){if(!e.length)return null;for(var n=0;n<e.length;n+=1)if(e[n].default)return e[n];if(t.url){for(var a=d(t.url),r=0;r<e.length;r+=1)if(e[r].url===a)return e[r]}return e[0]},U=function(e,n){!s||!m||e.length<2||(e.forEach(function(a){var r=document.createElement("option");r.value=a.url,r.textContent=a.name,n&&a.url===n.url&&(r.selected=!0),s.appendChild(r)}),m.hidden=!1)},b=function(){return{wrapComponents:{InfoUrl:function(){return function(){return null}}}}},E=function(){return{wrapComponents:{VersionStamp:function(){return function(){return null}}}}},B=function(){return{wrapComponents:{OpenAPIVersion:function(){return function(){return null}}}}},A=function(){return{wrapComponents:{clear:function(){return function(){return null}}}}},C=function(){var e=t.swagger_ui_config&&t.swagger_ui_config.plugins,n=Array.isArray(e)?e.slice():[],a={api_key_input:!0,info_url:!0,doc_version:!0,version_stamp:!0,clear_button:!1},r=Object.assign({},a,t.display||{});return r.info_url||n.push(b),r.doc_version||n.push(E),r.version_stamp||n.push(B),r.clear_button||n.push(A),n};v(_()),u&&u.addEventListener("click",function(){t.theme=g.dataset.theme==="dark"?"light":"dark",v(t.theme)});var l=S(),i=k(l),c=Object.assign({},t.swagger_ui_config||{},{dom_id:"#swagger-ui-container",deepLinking:!0,docExpansion:t.doc_expansion,supportedSubmitMethods:t.supported_submit_methods||[],validatorUrl:t.validator_url,layout:"BaseLayout",presets:[SwaggerUIBundle.presets.apis,SwaggerUIStandalonePreset],plugins:C(),requestInterceptor:function(e){var n=t.headers||{};Object.keys(n).forEach(function(f){h(e,f,n[f])});var a=y();if(!a)return e;if(t.api_key_type==="query"){var r=e.url.indexOf("?")===-1?"?":"&";return e.url+=r+encodeURIComponent(t.api_key_name)+"="+encodeURIComponent(a),e}return h(e,t.api_key_name,a),e}});l.length?(c.urls=l,i&&(c["urls.primaryName"]=i.name)):c.url=d(t.url),window.ui=SwaggerUIBundle(c),i&&(window.ui.specActions.updateUrl(i.url),window.ui.specActions.download(i.url)),U(l,i),s&&l.length>1&&s.addEventListener("change",function(e){var n=e.target,a=n.value;window.ui.specActions.updateUrl(a),window.ui.specActions.download(a)}),window.addEventListener("hashchange",function(){var e=window.location.hash;if(!(!e||e==="#")){var n=e.replace(/^#\/?/,"").split("/").filter(Boolean);if(n.length!==0){var a=safeDecodeURIComponent(n[0]),r=n.length>1?safeDecodeURIComponent(n[1]):null;window.ui.layoutActions.show(["operations-tag",a],!0),r&&window.ui.layoutActions.show(["operations",a,r],!0);var f=r?"operations-"+a+"-"+r:"operations-tag-"+a;requestAnimationFrame(function(){var w=document.getElementById(f);w&&w.scrollIntoView({behavior:"smooth",block:"start"})})}}})}};document.readyState==="loading"?document.addEventListener("DOMContentLoaded",initializeSwaggerPage):initializeSwaggerPage();
|
|
2
2
|
//# sourceMappingURL=index.min.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["index.js"],
|
|
4
|
-
"sourcesContent": ["\"use strict\";\nvar safeDecodeURIComponent = function (value) {\n try {\n return decodeURIComponent(value);\n }\n catch (_a) {\n return value;\n }\n};\nvar initializeSwaggerPage = function () {\n var optionsElement = document.documentElement.dataset.swaggerOptions;\n if (!optionsElement ||\n typeof SwaggerUIBundle === \"undefined\" ||\n typeof SwaggerUIStandalonePreset === \"undefined\") {\n return;\n }\n var options = JSON.parse(optionsElement);\n var authInput = document.getElementById(\"input_apiKey\");\n var specSelector = document.getElementById(\"spec-selector\");\n var specSelectorWrapper = document.getElementById(\"spec-selector-wrapper\");\n var themeToggle = document.getElementById(\"theme-toggle\");\n var root = document.documentElement;\n var getTheme = function () {\n return options.theme === \"dark\" ? \"dark\" : \"light\";\n };\n var applyTheme = function (theme) {\n root.dataset.theme = theme;\n root.classList.toggle(\"dark-mode\", theme === \"dark\");\n if (!themeToggle) {\n return;\n }\n themeToggle.textContent = theme === \"dark\" ? \"Light Mode\" : \"Dark Mode\";\n themeToggle.setAttribute(\"aria-pressed\", String(theme === \"dark\"));\n };\n var getApiKeyValue = function () {\n if (!authInput) {\n return \"\";\n }\n var key = authInput.value ? authInput.value.trim() : \"\";\n if (!key) {\n return \"\";\n }\n if (options.api_auth === \"basic\") {\n return \"Basic \" + btoa(key);\n }\n if (options.api_auth === \"bearer\") {\n return \"Bearer \" + key;\n }\n if (options.api_auth === \"token\") {\n return \"Token token=\\\"\".concat(key, \"\\\"\");\n }\n return key;\n };\n var ensureRequestHeaders = function (request) {\n if (!request.headers) {\n request.headers = {};\n }\n return request.headers;\n };\n var setRequestHeader = function (request, key, value) {\n var headers = ensureRequestHeaders(request);\n if (headers instanceof Headers) {\n headers.set(key, value);\n return;\n }\n headers[key] = value;\n };\n var absoluteSpecUrl = function (url) {\n if (!url) {\n return \"\";\n }\n if (/^https?:\\/\\//.test(url)) {\n return url;\n }\n return options.app_url + url;\n };\n var normalizeSwaggerUrls = function () {\n if (!Array.isArray(options.urls)) {\n return [];\n }\n return options.urls\n .map(function (entry, index) {\n if (typeof entry === \"string\") {\n return { name: entry, url: absoluteSpecUrl(entry), default: false };\n }\n return {\n name: entry.name || entry.url || \"Spec \" + (index + 1),\n url: absoluteSpecUrl(entry.url),\n default: Boolean(entry.default),\n };\n })\n .filter(function (entry) { return Boolean(entry.url); });\n };\n var selectedSwaggerUrl = function (urls) {\n if (!urls.length) {\n return null;\n }\n for (var i = 0; i < urls.length; i += 1) {\n if (urls[i].default) {\n return urls[i];\n }\n }\n if (options.url) {\n var absoluteUrl = absoluteSpecUrl(options.url);\n for (var j = 0; j < urls.length; j += 1) {\n if (urls[j].url === absoluteUrl) {\n return urls[j];\n }\n }\n }\n return urls[0];\n };\n var setupSpecSelector = function (urls, selectedUrl) {\n if (!specSelector || !specSelectorWrapper || urls.length < 2) {\n return;\n }\n urls.forEach(function (entry) {\n var option = document.createElement(\"option\");\n option.value = entry.url;\n option.textContent = entry.name;\n if (selectedUrl && entry.url === selectedUrl.url) {\n option.selected = true;\n }\n specSelector.appendChild(option);\n });\n specSelectorWrapper.hidden = false;\n };\n var hideInfoUrlPlugin = function () {\n return {\n wrapComponents: {\n InfoUrl: function () { return function () { return null; }; },\n },\n };\n };\n var hideDocVersionPlugin = function () {\n return {\n wrapComponents: {\n VersionStamp: function () { return function () { return null; }; },\n },\n };\n };\n var hideVersionStampPlugin = function () {\n return {\n wrapComponents: {\n OpenAPIVersion: function () { return function () { return null; }; },\n },\n };\n };\n var buildPlugins = function () {\n var configuredPlugins = options.swagger_ui_config && options.swagger_ui_config.plugins;\n var plugins = Array.isArray(configuredPlugins) ? configuredPlugins.slice() : [];\n var displayDefaults = { api_key_input: true, info_url: true, doc_version: true, version_stamp: true };\n var display = Object.assign({}, displayDefaults, options.display || {});\n if (!display.info_url) {\n plugins.push(hideInfoUrlPlugin);\n }\n if (!display.doc_version) {\n plugins.push(hideDocVersionPlugin);\n }\n if (!display.version_stamp) {\n plugins.push(hideVersionStampPlugin);\n }\n return plugins;\n };\n applyTheme(getTheme());\n if (themeToggle) {\n themeToggle.addEventListener(\"click\", function () {\n options.theme = root.dataset.theme === \"dark\" ? \"light\" : \"dark\";\n applyTheme(options.theme);\n });\n }\n var swaggerUrls = normalizeSwaggerUrls();\n var selectedUrl = selectedSwaggerUrl(swaggerUrls);\n var bundleConfig = Object.assign({}, options.swagger_ui_config || {}, {\n dom_id: \"#swagger-ui-container\",\n deepLinking: true,\n docExpansion: options.doc_expansion,\n supportedSubmitMethods: options.supported_submit_methods || [],\n validatorUrl: options.validator_url,\n layout: \"BaseLayout\",\n presets: [SwaggerUIBundle.presets.apis, SwaggerUIStandalonePreset],\n plugins: buildPlugins(),\n requestInterceptor: function (request) {\n var headers = options.headers || {};\n Object.keys(headers).forEach(function (key) {\n setRequestHeader(request, key, headers[key]);\n });\n var apiKeyValue = getApiKeyValue();\n if (!apiKeyValue) {\n return request;\n }\n if (options.api_key_type === \"query\") {\n var separator = request.url.indexOf(\"?\") === -1 ? \"?\" : \"&\";\n request.url +=\n separator +\n encodeURIComponent(options.api_key_name) +\n \"=\" +\n encodeURIComponent(apiKeyValue);\n return request;\n }\n setRequestHeader(request, options.api_key_name, apiKeyValue);\n return request;\n },\n });\n if (swaggerUrls.length) {\n bundleConfig.urls = swaggerUrls;\n if (selectedUrl) {\n bundleConfig[\"urls.primaryName\"] = selectedUrl.name;\n }\n }\n else {\n bundleConfig.url = absoluteSpecUrl(options.url);\n }\n window.ui = SwaggerUIBundle(bundleConfig);\n if (selectedUrl) {\n window.ui.specActions.updateUrl(selectedUrl.url);\n window.ui.specActions.download(selectedUrl.url);\n }\n setupSpecSelector(swaggerUrls, selectedUrl);\n if (specSelector && swaggerUrls.length > 1) {\n specSelector.addEventListener(\"change\", function (event) {\n var target = event.target;\n var url = target.value;\n window.ui.specActions.updateUrl(url);\n window.ui.specActions.download(url);\n });\n }\n // Listen for hash changes so that navigating to a deep-link URL in the same\n // tab (e.g. pasting a copied operation URL into the address bar) expands the\n // target operation without requiring a full page refresh.\n //\n // NOTE: We intentionally do NOT use `layoutActions.parseDeepLinkHash()` here.\n // That method is Swagger UI's built-in deep linking plugin action, designed to\n // run during initial spec load (inside the `onComplete` callback). When called\n // after spec rendering is complete, it fails to expand operations \u2014 likely\n // because it depends on internal state or lifecycle context that no longer applies.\n //\n // Instead, we directly call `layoutActions.show()` which reliably toggles the\n // visibility of tags/operations, then scroll into view manually.\n window.addEventListener(\"hashchange\", function () {\n var hash = window.location.hash;\n if (!hash || hash === \"#\") {\n return;\n }\n // Hash format used by Swagger UI deep linking: #/tag/operationId\n var parts = hash.replace(/^#\\/?/, \"\").split(\"/\").filter(Boolean);\n if (parts.length === 0) {\n return;\n }\n var tag = safeDecodeURIComponent(parts[0]);\n var operationId = parts.length > 1 ? safeDecodeURIComponent(parts[1]) : null;\n window.ui.layoutActions.show([\"operations-tag\", tag], true);\n if (operationId) {\n window.ui.layoutActions.show([\"operations\", tag, operationId], true);\n }\n // Scroll to the expanded element. Swagger UI uses id=\"operations-{tag}-{operationId}\"\n // for operations and id=\"operations-tag-{tag}\" for tag sections. Use a small delay\n // to allow the DOM to update after the layout action.\n var targetId = operationId\n ? \"operations-\" + tag + \"-\" + operationId\n : \"operations-tag-\" + tag;\n requestAnimationFrame(function () {\n var element = document.getElementById(targetId);\n if (element) {\n element.scrollIntoView({ behavior: \"smooth\", block: \"start\" });\n }\n });\n });\n};\nif (document.readyState === \"loading\") {\n document.addEventListener(\"DOMContentLoaded\", initializeSwaggerPage);\n}\nelse {\n initializeSwaggerPage();\n}\n"],
|
|
5
|
-
"mappings": "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
|
|
6
|
-
"names": ["value", "optionsElement", "options", "authInput", "specSelector", "specSelectorWrapper", "themeToggle", "root", "getTheme", "applyTheme", "theme", "getApiKeyValue", "key", "ensureRequestHeaders", "request", "setRequestHeader", "headers", "absoluteSpecUrl", "url", "normalizeSwaggerUrls", "entry", "index", "selectedSwaggerUrl", "urls", "i", "absoluteUrl", "j", "setupSpecSelector", "selectedUrl", "option", "hideInfoUrlPlugin", "hideDocVersionPlugin", "hideVersionStampPlugin", "buildPlugins", "configuredPlugins", "plugins", "displayDefaults", "display", "swaggerUrls", "bundleConfig", "apiKeyValue", "separator", "event", "target", "hash", "parts", "tag", "operationId", "targetId", "element"]
|
|
4
|
+
"sourcesContent": ["\"use strict\";\nvar safeDecodeURIComponent = function (value) {\n try {\n return decodeURIComponent(value);\n }\n catch (_a) {\n return value;\n }\n};\nvar initializeSwaggerPage = function () {\n var optionsElement = document.documentElement.dataset.swaggerOptions;\n if (!optionsElement ||\n typeof SwaggerUIBundle === \"undefined\" ||\n typeof SwaggerUIStandalonePreset === \"undefined\") {\n return;\n }\n var options = JSON.parse(optionsElement);\n var authInput = document.getElementById(\"input_apiKey\");\n var specSelector = document.getElementById(\"spec-selector\");\n var specSelectorWrapper = document.getElementById(\"spec-selector-wrapper\");\n var themeToggle = document.getElementById(\"theme-toggle\");\n var root = document.documentElement;\n var getTheme = function () {\n return options.theme === \"dark\" ? \"dark\" : \"light\";\n };\n var applyTheme = function (theme) {\n root.dataset.theme = theme;\n root.classList.toggle(\"dark-mode\", theme === \"dark\");\n if (!themeToggle) {\n return;\n }\n themeToggle.textContent = theme === \"dark\" ? \"Light Mode\" : \"Dark Mode\";\n themeToggle.setAttribute(\"aria-pressed\", String(theme === \"dark\"));\n };\n var getApiKeyValue = function () {\n if (!authInput) {\n return \"\";\n }\n var key = authInput.value ? authInput.value.trim() : \"\";\n if (!key) {\n return \"\";\n }\n if (options.api_auth === \"basic\") {\n return \"Basic \" + btoa(key);\n }\n if (options.api_auth === \"bearer\") {\n return \"Bearer \" + key;\n }\n if (options.api_auth === \"token\") {\n return \"Token token=\\\"\".concat(key, \"\\\"\");\n }\n return key;\n };\n var ensureRequestHeaders = function (request) {\n if (!request.headers) {\n request.headers = {};\n }\n return request.headers;\n };\n var setRequestHeader = function (request, key, value) {\n var headers = ensureRequestHeaders(request);\n if (headers instanceof Headers) {\n headers.set(key, value);\n return;\n }\n headers[key] = value;\n };\n var absoluteSpecUrl = function (url) {\n if (!url) {\n return \"\";\n }\n if (/^https?:\\/\\//.test(url)) {\n return url;\n }\n return options.app_url + url;\n };\n var normalizeSwaggerUrls = function () {\n if (!Array.isArray(options.urls)) {\n return [];\n }\n return options.urls\n .map(function (entry, index) {\n if (typeof entry === \"string\") {\n return { name: entry, url: absoluteSpecUrl(entry), default: false };\n }\n return {\n name: entry.name || entry.url || \"Spec \" + (index + 1),\n url: absoluteSpecUrl(entry.url),\n default: Boolean(entry.default),\n };\n })\n .filter(function (entry) { return Boolean(entry.url); });\n };\n var selectedSwaggerUrl = function (urls) {\n if (!urls.length) {\n return null;\n }\n for (var i = 0; i < urls.length; i += 1) {\n if (urls[i].default) {\n return urls[i];\n }\n }\n if (options.url) {\n var absoluteUrl = absoluteSpecUrl(options.url);\n for (var j = 0; j < urls.length; j += 1) {\n if (urls[j].url === absoluteUrl) {\n return urls[j];\n }\n }\n }\n return urls[0];\n };\n var setupSpecSelector = function (urls, selectedUrl) {\n if (!specSelector || !specSelectorWrapper || urls.length < 2) {\n return;\n }\n urls.forEach(function (entry) {\n var option = document.createElement(\"option\");\n option.value = entry.url;\n option.textContent = entry.name;\n if (selectedUrl && entry.url === selectedUrl.url) {\n option.selected = true;\n }\n specSelector.appendChild(option);\n });\n specSelectorWrapper.hidden = false;\n };\n var hideInfoUrlPlugin = function () {\n return {\n wrapComponents: {\n InfoUrl: function () { return function () { return null; }; },\n },\n };\n };\n var hideDocVersionPlugin = function () {\n return {\n wrapComponents: {\n VersionStamp: function () { return function () { return null; }; },\n },\n };\n };\n var hideVersionStampPlugin = function () {\n return {\n wrapComponents: {\n OpenAPIVersion: function () { return function () { return null; }; },\n },\n };\n };\n // Swagger UI's \"Clear\" button (next to Execute) is confusing \u2014 it resets\n // the internal request / response state but does not clear values still visible\n // in the rendered input fields. Upstream issue swagger-api/swagger-ui#5283\n // has acknowledged the UX problem since 2019 without a fix. Hide by default.\n var hideClearButtonPlugin = function () {\n return {\n wrapComponents: {\n clear: function () { return function () { return null; }; },\n },\n };\n };\n var buildPlugins = function () {\n var configuredPlugins = options.swagger_ui_config && options.swagger_ui_config.plugins;\n var plugins = Array.isArray(configuredPlugins) ? configuredPlugins.slice() : [];\n var displayDefaults = {\n api_key_input: true,\n info_url: true,\n doc_version: true,\n version_stamp: true,\n clear_button: false,\n };\n var display = Object.assign({}, displayDefaults, options.display || {});\n if (!display.info_url) {\n plugins.push(hideInfoUrlPlugin);\n }\n if (!display.doc_version) {\n plugins.push(hideDocVersionPlugin);\n }\n if (!display.version_stamp) {\n plugins.push(hideVersionStampPlugin);\n }\n if (!display.clear_button) {\n plugins.push(hideClearButtonPlugin);\n }\n return plugins;\n };\n applyTheme(getTheme());\n if (themeToggle) {\n themeToggle.addEventListener(\"click\", function () {\n options.theme = root.dataset.theme === \"dark\" ? \"light\" : \"dark\";\n applyTheme(options.theme);\n });\n }\n var swaggerUrls = normalizeSwaggerUrls();\n var selectedUrl = selectedSwaggerUrl(swaggerUrls);\n var bundleConfig = Object.assign({}, options.swagger_ui_config || {}, {\n dom_id: \"#swagger-ui-container\",\n deepLinking: true,\n docExpansion: options.doc_expansion,\n supportedSubmitMethods: options.supported_submit_methods || [],\n validatorUrl: options.validator_url,\n layout: \"BaseLayout\",\n presets: [SwaggerUIBundle.presets.apis, SwaggerUIStandalonePreset],\n plugins: buildPlugins(),\n requestInterceptor: function (request) {\n var headers = options.headers || {};\n Object.keys(headers).forEach(function (key) {\n setRequestHeader(request, key, headers[key]);\n });\n var apiKeyValue = getApiKeyValue();\n if (!apiKeyValue) {\n return request;\n }\n if (options.api_key_type === \"query\") {\n var separator = request.url.indexOf(\"?\") === -1 ? \"?\" : \"&\";\n request.url +=\n separator +\n encodeURIComponent(options.api_key_name) +\n \"=\" +\n encodeURIComponent(apiKeyValue);\n return request;\n }\n setRequestHeader(request, options.api_key_name, apiKeyValue);\n return request;\n },\n });\n if (swaggerUrls.length) {\n bundleConfig.urls = swaggerUrls;\n if (selectedUrl) {\n bundleConfig[\"urls.primaryName\"] = selectedUrl.name;\n }\n }\n else {\n bundleConfig.url = absoluteSpecUrl(options.url);\n }\n window.ui = SwaggerUIBundle(bundleConfig);\n if (selectedUrl) {\n window.ui.specActions.updateUrl(selectedUrl.url);\n window.ui.specActions.download(selectedUrl.url);\n }\n setupSpecSelector(swaggerUrls, selectedUrl);\n if (specSelector && swaggerUrls.length > 1) {\n specSelector.addEventListener(\"change\", function (event) {\n var target = event.target;\n var url = target.value;\n window.ui.specActions.updateUrl(url);\n window.ui.specActions.download(url);\n });\n }\n // Listen for hash changes so that navigating to a deep-link URL in the same\n // tab (e.g. pasting a copied operation URL into the address bar) expands the\n // target operation without requiring a full page refresh.\n //\n // NOTE: We intentionally do NOT use `layoutActions.parseDeepLinkHash()` here.\n // That method is Swagger UI's built-in deep linking plugin action, designed to\n // run during initial spec load (inside the `onComplete` callback). When called\n // after spec rendering is complete, it fails to expand operations \u2014 likely\n // because it depends on internal state or lifecycle context that no longer applies.\n //\n // Instead, we directly call `layoutActions.show()` which reliably toggles the\n // visibility of tags/operations, then scroll into view manually.\n window.addEventListener(\"hashchange\", function () {\n var hash = window.location.hash;\n if (!hash || hash === \"#\") {\n return;\n }\n // Hash format used by Swagger UI deep linking: #/tag/operationId\n var parts = hash.replace(/^#\\/?/, \"\").split(\"/\").filter(Boolean);\n if (parts.length === 0) {\n return;\n }\n var tag = safeDecodeURIComponent(parts[0]);\n var operationId = parts.length > 1 ? safeDecodeURIComponent(parts[1]) : null;\n window.ui.layoutActions.show([\"operations-tag\", tag], true);\n if (operationId) {\n window.ui.layoutActions.show([\"operations\", tag, operationId], true);\n }\n // Scroll to the expanded element. Swagger UI uses id=\"operations-{tag}-{operationId}\"\n // for operations and id=\"operations-tag-{tag}\" for tag sections. Use a small delay\n // to allow the DOM to update after the layout action.\n var targetId = operationId\n ? \"operations-\" + tag + \"-\" + operationId\n : \"operations-tag-\" + tag;\n requestAnimationFrame(function () {\n var element = document.getElementById(targetId);\n if (element) {\n element.scrollIntoView({ behavior: \"smooth\", block: \"start\" });\n }\n });\n });\n};\nif (document.readyState === \"loading\") {\n document.addEventListener(\"DOMContentLoaded\", initializeSwaggerPage);\n}\nelse {\n initializeSwaggerPage();\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["value", "optionsElement", "options", "authInput", "specSelector", "specSelectorWrapper", "themeToggle", "root", "getTheme", "applyTheme", "theme", "getApiKeyValue", "key", "ensureRequestHeaders", "request", "setRequestHeader", "headers", "absoluteSpecUrl", "url", "normalizeSwaggerUrls", "entry", "index", "selectedSwaggerUrl", "urls", "i", "absoluteUrl", "j", "setupSpecSelector", "selectedUrl", "option", "hideInfoUrlPlugin", "hideDocVersionPlugin", "hideVersionStampPlugin", "hideClearButtonPlugin", "buildPlugins", "configuredPlugins", "plugins", "displayDefaults", "display", "swaggerUrls", "bundleConfig", "apiKeyValue", "separator", "event", "target", "hash", "parts", "tag", "operationId", "targetId", "element"]
|
|
7
7
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
html {
|
|
2
2
|
box-sizing: border-box;
|
|
3
|
-
overflow: -moz-scrollbars-vertical;
|
|
4
3
|
overflow-y: scroll;
|
|
5
4
|
}
|
|
6
5
|
|
|
@@ -232,6 +231,10 @@ html[data-theme="dark"] .swagger-ui .model-box {
|
|
|
232
231
|
border-color: #475569;
|
|
233
232
|
}
|
|
234
233
|
|
|
234
|
+
.swagger-ui .model-box table.model tr.property-row > td {
|
|
235
|
+
vertical-align: baseline;
|
|
236
|
+
}
|
|
237
|
+
|
|
235
238
|
@media (max-width: 767px) {
|
|
236
239
|
.swagger-header {
|
|
237
240
|
flex-direction: column;
|
|
@@ -17,6 +17,7 @@ interface SwaggerPageOptions {
|
|
|
17
17
|
info_url: boolean;
|
|
18
18
|
doc_version: boolean;
|
|
19
19
|
version_stamp: boolean;
|
|
20
|
+
clear_button: boolean;
|
|
20
21
|
};
|
|
21
22
|
supported_submit_methods: string[];
|
|
22
23
|
theme: string;
|
|
@@ -236,10 +237,28 @@ const initializeSwaggerPage = (): void => {
|
|
|
236
237
|
};
|
|
237
238
|
}
|
|
238
239
|
|
|
240
|
+
// Swagger UI's "Clear" button (next to Execute) is confusing — it resets
|
|
241
|
+
// the internal request / response state but does not clear values still visible
|
|
242
|
+
// in the rendered input fields. Upstream issue swagger-api/swagger-ui#5283
|
|
243
|
+
// has acknowledged the UX problem since 2019 without a fix. Hide by default.
|
|
244
|
+
const hideClearButtonPlugin = (): SwaggerPlugin => {
|
|
245
|
+
return {
|
|
246
|
+
wrapComponents: {
|
|
247
|
+
clear: () => () => null,
|
|
248
|
+
},
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
|
|
239
252
|
const buildPlugins = (): unknown[] => {
|
|
240
253
|
const configuredPlugins = options.swagger_ui_config && options.swagger_ui_config.plugins;
|
|
241
254
|
const plugins = Array.isArray(configuredPlugins) ? configuredPlugins.slice() : [];
|
|
242
|
-
const displayDefaults = {
|
|
255
|
+
const displayDefaults = {
|
|
256
|
+
api_key_input: true,
|
|
257
|
+
info_url: true,
|
|
258
|
+
doc_version: true,
|
|
259
|
+
version_stamp: true,
|
|
260
|
+
clear_button: false,
|
|
261
|
+
};
|
|
243
262
|
const display = Object.assign({}, displayDefaults, options.display || {});
|
|
244
263
|
|
|
245
264
|
if (!display.info_url) {
|
|
@@ -254,6 +273,10 @@ const initializeSwaggerPage = (): void => {
|
|
|
254
273
|
plugins.push(hideVersionStampPlugin);
|
|
255
274
|
}
|
|
256
275
|
|
|
276
|
+
if (!display.clear_button) {
|
|
277
|
+
plugins.push(hideClearButtonPlugin);
|
|
278
|
+
}
|
|
279
|
+
|
|
257
280
|
return plugins;
|
|
258
281
|
}
|
|
259
282
|
|
data/lib/grape-swagger-rails.rb
CHANGED
data/lib/tasks/swagger_ui.rake
CHANGED
|
@@ -8,7 +8,14 @@ namespace :swagger_ui do
|
|
|
8
8
|
namespace :dist do
|
|
9
9
|
desc 'Update Swagger UI assets from swagger-api/swagger-ui.'
|
|
10
10
|
task :update do
|
|
11
|
-
|
|
11
|
+
root = File.expand_path('../..', __dir__)
|
|
12
|
+
version_file = File.join(root, 'lib/grape-swagger-rails/version.rb')
|
|
13
|
+
match = File.read(version_file).match(/SWAGGER_UI_VERSION = '([^']+)'/)
|
|
14
|
+
raise "Could not find SWAGGER_UI_VERSION in #{version_file}" unless match
|
|
15
|
+
|
|
16
|
+
current_version = match[1]
|
|
17
|
+
version = ENV.fetch('SWAGGER_UI_VERSION', "v#{current_version}")
|
|
18
|
+
version = "v#{version}" unless version.start_with?('v')
|
|
12
19
|
|
|
13
20
|
Dir.mktmpdir('swagger-ui') do |dir|
|
|
14
21
|
puts "Cloning swagger-api/swagger-ui #{version} into #{dir} ..."
|
|
@@ -20,7 +27,6 @@ namespace :swagger_ui do
|
|
|
20
27
|
branch: version
|
|
21
28
|
)
|
|
22
29
|
|
|
23
|
-
root = File.expand_path('../..', __dir__)
|
|
24
30
|
dist = File.join(dir, 'swagger-ui', 'dist')
|
|
25
31
|
|
|
26
32
|
raise "Missing dist directory at #{dist}" unless Dir.exist?(dist)
|
|
@@ -39,11 +45,22 @@ namespace :swagger_ui do
|
|
|
39
45
|
File.join(root, 'app/assets/stylesheets/grape_swagger_rails/swagger-ui.css')
|
|
40
46
|
|
|
41
47
|
semver = version.sub(/\Av/, '')
|
|
42
|
-
version_file = File.join(root, 'lib/grape-swagger-rails/version.rb')
|
|
43
48
|
content = File.read(version_file)
|
|
44
49
|
updated = content.gsub(/SWAGGER_UI_VERSION = '[^']*'/, "SWAGGER_UI_VERSION = '#{semver}'")
|
|
45
50
|
File.write(version_file, updated)
|
|
46
51
|
puts "Updated SWAGGER_UI_VERSION to #{semver} in #{version_file}"
|
|
52
|
+
|
|
53
|
+
readme_file = File.join(root, 'README.md')
|
|
54
|
+
readme = File.read(readme_file)
|
|
55
|
+
compatibility_table = readme.match(/(## Compatibility.*?)(\n\nThe dummy app)/m)
|
|
56
|
+
raise 'Could not find README compatibility table' unless compatibility_table
|
|
57
|
+
|
|
58
|
+
updated_table = compatibility_table[1].gsub(
|
|
59
|
+
/^(\|\s*[^|\n]+\|\s*[^|\n]+\|\s*[^|\n]+\|\s*[^|\n]+\|\s*)\d+\.\d+\.\d+(\s*\|)$/m,
|
|
60
|
+
"\\1#{semver}\\2"
|
|
61
|
+
)
|
|
62
|
+
File.write(readme_file, readme.sub(compatibility_table[1], updated_table))
|
|
63
|
+
puts "Updated Swagger UI compatibility table to #{semver} in #{readme_file}"
|
|
47
64
|
end
|
|
48
65
|
end
|
|
49
66
|
end
|
|
@@ -231,6 +231,32 @@ describe 'Swagger' do
|
|
|
231
231
|
end
|
|
232
232
|
end
|
|
233
233
|
|
|
234
|
+
describe 'display[:clear_button] option' do
|
|
235
|
+
include_context 'with isolated options'
|
|
236
|
+
|
|
237
|
+
it 'hides the Clear button by default after Execute' do
|
|
238
|
+
visit_swagger
|
|
239
|
+
open_operation('operations-tag-foos', 'operations-foos-getApiFoos')
|
|
240
|
+
execute_operation('operations-foos-getApiFoos')
|
|
241
|
+
|
|
242
|
+
within('#operations-foos-getApiFoos') do
|
|
243
|
+
expect(page).to have_css('.responses-wrapper')
|
|
244
|
+
expect(page).to have_no_css('.btn-clear')
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
it 'shows the Clear button when enabled' do
|
|
249
|
+
GrapeSwaggerRails.options.display = GrapeSwaggerRails.options.display.merge(clear_button: true)
|
|
250
|
+
visit_swagger
|
|
251
|
+
open_operation('operations-tag-foos', 'operations-foos-getApiFoos')
|
|
252
|
+
execute_operation('operations-foos-getApiFoos')
|
|
253
|
+
|
|
254
|
+
within('#operations-foos-getApiFoos') do
|
|
255
|
+
expect(page).to have_css('.btn-clear', text: 'Clear')
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
|
|
234
260
|
describe 'same-session deep link navigation' do
|
|
235
261
|
# Regression tests for: navigating to a Swagger deep-link URL in the same
|
|
236
262
|
# tab/session should expand the target operation without a full page refresh.
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: grape-swagger-rails
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0.
|
|
4
|
+
version: 1.0.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Alexander Logunov
|
|
@@ -83,6 +83,7 @@ files:
|
|
|
83
83
|
- ".github/workflows/danger.yml"
|
|
84
84
|
- ".github/workflows/frontend.yml"
|
|
85
85
|
- ".github/workflows/rubocop.yml"
|
|
86
|
+
- ".github/workflows/swagger-ui-update.yml"
|
|
86
87
|
- ".github/workflows/test.yml"
|
|
87
88
|
- ".gitignore"
|
|
88
89
|
- ".pnp.cjs"
|
|
@@ -171,7 +172,7 @@ licenses:
|
|
|
171
172
|
metadata:
|
|
172
173
|
bug_tracker_uri: https://github.com/ruby-grape/grape-swagger-rails/issues
|
|
173
174
|
changelog_uri: https://github.com/ruby-grape/grape-swagger-rails/blob/master/CHANGELOG.md
|
|
174
|
-
source_code_uri: https://github.com/ruby-grape/grape-swagger-rails/tree/v1.0.
|
|
175
|
+
source_code_uri: https://github.com/ruby-grape/grape-swagger-rails/tree/v1.0.2
|
|
175
176
|
rubygems_mfa_required: 'true'
|
|
176
177
|
rdoc_options: []
|
|
177
178
|
require_paths:
|