prauga-flexdoc 0.1.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 +7 -0
- data/LICENSE +667 -0
- data/README.md +42 -0
- data/assets/flexdoc.standalone.css +1 -0
- data/assets/flexdoc.standalone.js +52 -0
- data/lib/prauga/flexdoc/config.rb +15 -0
- data/lib/prauga/flexdoc/host.rb +67 -0
- data/lib/prauga/flexdoc/rack_app.rb +16 -0
- data/lib/prauga/flexdoc/rails.rb +21 -0
- data/lib/prauga/flexdoc/response.rb +20 -0
- data/lib/prauga/flexdoc/version.rb +7 -0
- data/lib/prauga/flexdoc.rb +8 -0
- metadata +130 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Prauga
|
|
4
|
+
module FlexDoc
|
|
5
|
+
Config = Data.define(:path, :spec_url, :title, :theme, :try_it_enabled) do
|
|
6
|
+
def initialize(path: "/docs", spec_url: "/openapi.json", title: "API Reference", theme: "system", try_it_enabled: true)
|
|
7
|
+
normalized = "/#{path.to_s.gsub(%r{\A/+|/+$}, "")}"
|
|
8
|
+
normalized = "/docs" if normalized == "/"
|
|
9
|
+
raise ArgumentError, "FlexDoc theme must be system, light, or dark" unless %w[system light dark].include?(theme)
|
|
10
|
+
|
|
11
|
+
super(path: normalized, spec_url:, title:, theme:, try_it_enabled: !!try_it_enabled)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "cgi"
|
|
4
|
+
require "digest"
|
|
5
|
+
require "json"
|
|
6
|
+
|
|
7
|
+
module Prauga
|
|
8
|
+
module FlexDoc
|
|
9
|
+
class Host
|
|
10
|
+
IMMUTABLE_CACHE = "public, max-age=31536000, immutable"
|
|
11
|
+
|
|
12
|
+
attr_reader :config, :fingerprint
|
|
13
|
+
|
|
14
|
+
def initialize(config = Config.new, assets_dir: nil)
|
|
15
|
+
@config = config
|
|
16
|
+
root = assets_dir || File.expand_path("../../../assets", __dir__)
|
|
17
|
+
@javascript = File.binread(File.join(root, "flexdoc.standalone.js"))
|
|
18
|
+
@css = File.binread(File.join(root, "flexdoc.standalone.css"))
|
|
19
|
+
@fingerprint = Digest::SHA256.hexdigest(@javascript + "\0" + @css)[0, 16]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def response_for_path(path)
|
|
23
|
+
return documentation if path == config.path || path == "#{config.path}/"
|
|
24
|
+
return renderer_javascript if path == "#{config.path}/__flexdoc/renderer.js"
|
|
25
|
+
return renderer_css if path == "#{config.path}/__flexdoc/renderer.css"
|
|
26
|
+
|
|
27
|
+
Response.new(status: 404, content_type: "text/plain; charset=utf-8", body: "Not Found", cache_control: nil)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def documentation
|
|
31
|
+
options = {
|
|
32
|
+
contractVersion: "1",
|
|
33
|
+
title: config.title,
|
|
34
|
+
theme: config.theme,
|
|
35
|
+
tryIt: { enabled: config.try_it_enabled }
|
|
36
|
+
}
|
|
37
|
+
title = CGI.escapeHTML(config.title.to_s)
|
|
38
|
+
path = CGI.escapeHTML(config.path)
|
|
39
|
+
spec_url = safe_json(config.spec_url)
|
|
40
|
+
options_json = safe_json(options)
|
|
41
|
+
body = <<~HTML.delete("\n")
|
|
42
|
+
<!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover"><title>#{title}</title><link rel="stylesheet" href="#{path}/__flexdoc/renderer.css?v=#{fingerprint}"></head><body><div id="flexdoc-root"></div><script>window.__FLEXDOC_SPEC_URL__=#{spec_url};window.__FLEXDOC_OPTIONS__=#{options_json};</script><script src="#{path}/__flexdoc/renderer.js?v=#{fingerprint}"></script><script>(async function(){const root=document.getElementById('flexdoc-root');try{const baseUri=new URL(window.__FLEXDOC_SPEC_URL__,window.location.href).toString();const response=await fetch(baseUri);if(!response.ok)throw new Error('Unable to load OpenAPI specification: HTTP '+response.status);const spec=await response.json();const config={spec:spec,options:window.__FLEXDOC_OPTIONS__||{},baseUri:baseUri};if(window.FlexDocStandalone.mountAsync)await window.FlexDocStandalone.mountAsync(root,config);else window.FlexDocStandalone.mount(root,config);}catch(error){root.textContent=error instanceof Error?error.message:String(error);}})();</script></body></html>
|
|
43
|
+
HTML
|
|
44
|
+
Response.new(status: 200, content_type: "text/html; charset=utf-8", body:, cache_control: "no-cache")
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def renderer_javascript
|
|
48
|
+
Response.new(status: 200, content_type: "application/javascript; charset=utf-8", body: @javascript, cache_control: IMMUTABLE_CACHE)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def renderer_css
|
|
52
|
+
Response.new(status: 200, content_type: "text/css; charset=utf-8", body: @css, cache_control: IMMUTABLE_CACHE)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
private
|
|
56
|
+
|
|
57
|
+
def safe_json(value)
|
|
58
|
+
JSON.generate(value)
|
|
59
|
+
.gsub("<", "\\u003c")
|
|
60
|
+
.gsub(">", "\\u003e")
|
|
61
|
+
.gsub("&", "\\u0026")
|
|
62
|
+
.gsub("\u2028", "\\u2028")
|
|
63
|
+
.gsub("\u2029", "\\u2029")
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Prauga
|
|
4
|
+
module FlexDoc
|
|
5
|
+
class RackApp
|
|
6
|
+
def initialize(host = Host.new)
|
|
7
|
+
@host = host
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def call(env)
|
|
11
|
+
path = "#{env.fetch("SCRIPT_NAME", "")}#{env.fetch("PATH_INFO", "")}"
|
|
12
|
+
@host.response_for_path(path).rack
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Prauga
|
|
4
|
+
module FlexDoc
|
|
5
|
+
module Rails
|
|
6
|
+
module_function
|
|
7
|
+
|
|
8
|
+
def mount(mapper, host: Host.new, at: nil, as: :flexdoc)
|
|
9
|
+
mount_path = at || host.config.path
|
|
10
|
+
normalized_mount_path = Config.new(path: mount_path).path
|
|
11
|
+
if normalized_mount_path != host.config.path
|
|
12
|
+
raise ArgumentError,
|
|
13
|
+
"Rails mount path #{normalized_mount_path.inspect} must match FlexDoc host path #{host.config.path.inspect}"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
mapper.mount RackApp.new(host), at: normalized_mount_path, as: as
|
|
17
|
+
host
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Prauga
|
|
4
|
+
module FlexDoc
|
|
5
|
+
Response = Data.define(:status, :content_type, :body, :cache_control) do
|
|
6
|
+
def headers
|
|
7
|
+
result = {
|
|
8
|
+
"content-type" => content_type,
|
|
9
|
+
"content-length" => body.bytesize.to_s
|
|
10
|
+
}
|
|
11
|
+
result["cache-control"] = cache_control if cache_control
|
|
12
|
+
result
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def rack
|
|
16
|
+
[status, headers, [body]]
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: prauga-flexdoc
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Prauga
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2026-09-03 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: actionpack
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ">="
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '7.2'
|
|
20
|
+
- - "<"
|
|
21
|
+
- !ruby/object:Gem::Version
|
|
22
|
+
version: '9'
|
|
23
|
+
type: :development
|
|
24
|
+
prerelease: false
|
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
26
|
+
requirements:
|
|
27
|
+
- - ">="
|
|
28
|
+
- !ruby/object:Gem::Version
|
|
29
|
+
version: '7.2'
|
|
30
|
+
- - "<"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '9'
|
|
33
|
+
- !ruby/object:Gem::Dependency
|
|
34
|
+
name: minitest
|
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - "~>"
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '5.25'
|
|
40
|
+
type: :development
|
|
41
|
+
prerelease: false
|
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - "~>"
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '5.25'
|
|
47
|
+
- !ruby/object:Gem::Dependency
|
|
48
|
+
name: rack
|
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - ">="
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '3.1'
|
|
54
|
+
- - "<"
|
|
55
|
+
- !ruby/object:Gem::Version
|
|
56
|
+
version: '4'
|
|
57
|
+
type: :development
|
|
58
|
+
prerelease: false
|
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
60
|
+
requirements:
|
|
61
|
+
- - ">="
|
|
62
|
+
- !ruby/object:Gem::Version
|
|
63
|
+
version: '3.1'
|
|
64
|
+
- - "<"
|
|
65
|
+
- !ruby/object:Gem::Version
|
|
66
|
+
version: '4'
|
|
67
|
+
- !ruby/object:Gem::Dependency
|
|
68
|
+
name: rake
|
|
69
|
+
requirement: !ruby/object:Gem::Requirement
|
|
70
|
+
requirements:
|
|
71
|
+
- - ">="
|
|
72
|
+
- !ruby/object:Gem::Version
|
|
73
|
+
version: '13.2'
|
|
74
|
+
- - "<"
|
|
75
|
+
- !ruby/object:Gem::Version
|
|
76
|
+
version: '14'
|
|
77
|
+
type: :development
|
|
78
|
+
prerelease: false
|
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
80
|
+
requirements:
|
|
81
|
+
- - ">="
|
|
82
|
+
- !ruby/object:Gem::Version
|
|
83
|
+
version: '13.2'
|
|
84
|
+
- - "<"
|
|
85
|
+
- !ruby/object:Gem::Version
|
|
86
|
+
version: '14'
|
|
87
|
+
description: Framework-neutral Ruby host for the canonical FlexDoc OpenAPI renderer
|
|
88
|
+
with thin Rack and Rails integrations.
|
|
89
|
+
email:
|
|
90
|
+
executables: []
|
|
91
|
+
extensions: []
|
|
92
|
+
extra_rdoc_files: []
|
|
93
|
+
files:
|
|
94
|
+
- LICENSE
|
|
95
|
+
- README.md
|
|
96
|
+
- assets/flexdoc.standalone.css
|
|
97
|
+
- assets/flexdoc.standalone.js
|
|
98
|
+
- lib/prauga/flexdoc.rb
|
|
99
|
+
- lib/prauga/flexdoc/config.rb
|
|
100
|
+
- lib/prauga/flexdoc/host.rb
|
|
101
|
+
- lib/prauga/flexdoc/rack_app.rb
|
|
102
|
+
- lib/prauga/flexdoc/rails.rb
|
|
103
|
+
- lib/prauga/flexdoc/response.rb
|
|
104
|
+
- lib/prauga/flexdoc/version.rb
|
|
105
|
+
homepage: https://github.com/prauga/flexdoc
|
|
106
|
+
licenses:
|
|
107
|
+
- AGPL-3.0-or-later
|
|
108
|
+
metadata:
|
|
109
|
+
source_code_uri: https://github.com/prauga/flexdoc
|
|
110
|
+
bug_tracker_uri: https://github.com/prauga/flexdoc/issues
|
|
111
|
+
post_install_message:
|
|
112
|
+
rdoc_options: []
|
|
113
|
+
require_paths:
|
|
114
|
+
- lib
|
|
115
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
116
|
+
requirements:
|
|
117
|
+
- - ">="
|
|
118
|
+
- !ruby/object:Gem::Version
|
|
119
|
+
version: '3.2'
|
|
120
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
121
|
+
requirements:
|
|
122
|
+
- - ">="
|
|
123
|
+
- !ruby/object:Gem::Version
|
|
124
|
+
version: '0'
|
|
125
|
+
requirements: []
|
|
126
|
+
rubygems_version: 3.5.22
|
|
127
|
+
signing_key:
|
|
128
|
+
specification_version: 4
|
|
129
|
+
summary: Self-hosted FlexDoc integration for Rack and Rails
|
|
130
|
+
test_files: []
|