govuk_tech_docs 2.0.13 → 2.2.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.

Potentially problematic release.


This version of govuk_tech_docs might be problematic. Click here for more details.

Files changed (31) hide show
  1. checksums.yaml +4 -4
  2. data/.github/pull_request_template.md +1 -0
  3. data/.ruby-version +1 -1
  4. data/.travis.yml +3 -0
  5. data/CHANGELOG.md +54 -1
  6. data/README.md +15 -22
  7. data/example/.ruby-version +1 -1
  8. data/example/source/index.html.md.erb +1 -0
  9. data/example/source/prevent-index-page.html.md +10 -0
  10. data/govuk_tech_docs.gemspec +1 -7
  11. data/lib/assets/javascripts/_modules/search.js +13 -2
  12. data/lib/assets/javascripts/_modules/table-of-contents.js +9 -14
  13. data/lib/assets/stylesheets/modules/_page-review.scss +3 -5
  14. data/lib/assets/stylesheets/modules/_search.scss +47 -9
  15. data/lib/assets/stylesheets/modules/_technical-documentation.scss +11 -2
  16. data/lib/assets/stylesheets/modules/_toc.scss +12 -2
  17. data/lib/govuk_tech_docs/api_reference/api_reference_extension.rb +0 -1
  18. data/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb +70 -186
  19. data/lib/govuk_tech_docs/api_reference/templates/api_reference_full.html.erb +3 -2
  20. data/lib/govuk_tech_docs/api_reference/templates/operation.html.erb +1 -1
  21. data/lib/govuk_tech_docs/api_reference/templates/parameters.html.erb +1 -1
  22. data/lib/govuk_tech_docs/api_reference/templates/responses.html.erb +1 -1
  23. data/lib/govuk_tech_docs/api_reference/templates/schema.html.erb +12 -12
  24. data/lib/govuk_tech_docs/meta_tags.rb +27 -8
  25. data/lib/govuk_tech_docs/tech_docs_html_renderer.rb +75 -1
  26. data/lib/govuk_tech_docs/version.rb +1 -1
  27. data/lib/source/images/search-button.png +0 -0
  28. data/lib/source/layouts/_search.erb +10 -4
  29. data/lib/source/layouts/core.erb +7 -10
  30. data/package-lock.json +3 -3
  31. metadata +7 -74
@@ -118,11 +118,20 @@
118
118
  }
119
119
 
120
120
  pre {
121
+ $padding: 15px;
122
+ $border-width: 1px;
123
+
121
124
  background: $code-00;
122
- padding: 15px;
125
+ padding: $padding;
123
126
  overflow: auto;
124
127
  position: relative;
125
- border: 1px solid $code-02;
128
+ border: $border-width solid $code-02;
129
+
130
+ &:focus {
131
+ padding: $padding - ($govuk-focus-width - $border-width);
132
+ border: $govuk-focus-width solid $govuk-focus-text-colour;
133
+ outline: $govuk-focus-width solid $govuk-focus-colour;
134
+ }
126
135
  }
127
136
 
128
137
  pre code {
@@ -127,7 +127,7 @@
127
127
  display: block;
128
128
  position: relative;
129
129
  z-index: 10;
130
-
130
+ width: 100%;
131
131
  padding: govuk-spacing(3) govuk-spacing(3) 10px;
132
132
 
133
133
  background: govuk-colour("light-grey");
@@ -135,10 +135,12 @@
135
135
  background: transparentize(govuk-colour("light-grey"), 0.05);
136
136
  backdrop-filter: blur(2px);
137
137
  }
138
+ border: 0;
138
139
  border-bottom: 1px solid govuk-colour("mid-grey");
139
140
  box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.1);
140
141
  color: $govuk-text-colour;
141
142
  text-decoration: none;
143
+ text-align: left;
142
144
 
143
145
  &:focus {
144
146
  @include govuk-focused-text;
@@ -163,6 +165,9 @@
163
165
 
164
166
  .toc__list {
165
167
  margin-right: govuk-spacing(7);
168
+ &.search-results-open {
169
+ display: none;
170
+ }
166
171
  }
167
172
 
168
173
  .toc__close {
@@ -170,7 +175,7 @@
170
175
  position: sticky;
171
176
  right: 0;
172
177
  top: 0;
173
-
178
+ border: 0;
174
179
  float: right;
175
180
  width: 20px;
176
181
  height: 20px;
@@ -207,6 +212,10 @@
207
212
  height: 100%;
208
213
  overflow: hidden;
209
214
  pointer-events: none;
215
+ // set visibility hidden on the body when TOC is open
216
+ // this is a hack to prevent tabbing to out-of-view elements when the TOC is active
217
+ // it's preferable to keyboard trapping... probably.
218
+ visibility: hidden;
210
219
  }
211
220
 
212
221
  .toc-show {
@@ -214,6 +223,7 @@
214
223
  }
215
224
 
216
225
  .toc {
226
+ visibility: visible;
217
227
  display: block;
218
228
  pointer-events: auto;
219
229
  position: fixed;
@@ -1,7 +1,6 @@
1
1
  require "erb"
2
2
  require "openapi3_parser"
3
3
  require "uri"
4
- require "pry"
5
4
  require "govuk_tech_docs/api_reference/api_reference_renderer"
6
5
 
7
6
  module GovukTechDocs
@@ -18,20 +18,15 @@ module GovukTechDocs
18
18
  end
19
19
 
20
20
  def api_full(info, servers)
21
- paths = ""
22
- paths_data = @document.paths
23
- paths_data.each do |path_data|
24
- # For some reason paths.each returns an array of arrays [title, object]
25
- # instead of an array of objects
26
- text = path_data[0]
27
- paths += path(text)
21
+ paths = @document.paths.keys.inject("") do |memo, text|
22
+ memo + path(text)
28
23
  end
29
- schemas = ""
30
- schemas_data = @document.components.schemas
31
- schemas_data.each do |schema_data|
32
- text = schema_data[0]
33
- schemas += schema(text)
24
+
25
+ schema_names = @document.components.schemas.keys
26
+ schemas = schema_names.inject("") do |memo, schema_name|
27
+ memo + schema(schema_name)
34
28
  end
29
+
35
30
  @template_api_full.result(binding)
36
31
  end
37
32
 
@@ -42,128 +37,78 @@ module GovukTechDocs
42
37
  @template_path.result(binding)
43
38
  end
44
39
 
45
- def schema(text)
46
- schemas = ""
47
- schemas_data = @document.components.schemas
48
- schemas_data.each do |schema_data|
49
- all_of = schema_data[1]["allOf"]
50
- properties = []
51
- if !all_of.blank?
52
- all_of.each do |schema_nested|
53
- schema_nested.properties.each do |property|
54
- properties.push property
55
- end
56
- end
57
- end
40
+ def schema(title)
41
+ schema = @document.components.schemas[title]
42
+ return unless schema
58
43
 
59
- schema_data[1].properties.each do |property|
60
- properties.push property
61
- end
44
+ properties = if schema.all_of
45
+ schema.all_of.each_with_object({}) do |nested, memo|
46
+ memo.merge!(nested.properties.to_h)
47
+ end
48
+ else
49
+ {}
50
+ end
62
51
 
63
- if schema_data[0] == text
64
- title = schema_data[0]
65
- schema = schema_data[1]
66
- return @template_schema.result(binding)
67
- end
68
- end
52
+ properties.merge!(schema.properties.to_h)
53
+ @template_schema.result(binding)
69
54
  end
70
55
 
71
56
  def schemas_from_path(text)
72
- path = @document.paths[text]
73
- operations = get_operations(path)
74
- # Get all referenced schemas
75
- schemas = []
76
- operations.compact.each_value do |operation|
77
- responses = operation.responses
78
- responses.each do |_rkey, response|
79
- if response.content["application/json"]
80
- schema = response.content["application/json"].schema
81
- schema_name = get_schema_name(schema.node_context.source_location.to_s)
82
- if !schema_name.nil?
83
- schemas.push schema_name
84
- end
85
- schemas.concat(schemas_from_schema(schema))
86
- end
57
+ operations = get_operations(@document.paths[text])
58
+ schemas = operations.flat_map do |_, operation|
59
+ operation.responses.inject([]) do |memo, (_, response)|
60
+ next memo unless response.content["application/json"]
61
+
62
+ schema = response.content["application/json"].schema
63
+
64
+ memo << schema.name if schema.name
65
+ memo + schemas_from_schema(schema)
87
66
  end
88
67
  end
68
+
89
69
  # Render all referenced schemas
90
- output = ""
91
- schemas.uniq.each do |schema_name|
92
- output += schema(schema_name)
93
- end
94
- if !output.empty?
95
- output.prepend('<h2 id="schemas">Schemas</h2>')
70
+ output = schemas.uniq.inject("") do |memo, schema_name|
71
+ memo + schema(schema_name)
96
72
  end
73
+
74
+ output.prepend('<h2 id="schemas">Schemas</h2>') unless output.empty?
97
75
  output
98
76
  end
99
77
 
100
78
  def schemas_from_schema(schema)
101
- schemas = []
102
- properties = []
103
- schema.properties.each do |property|
104
- properties.push property[1]
105
- end
106
- if schema.type == "array"
107
- properties.push schema.items
108
- end
109
- all_of = schema["allOf"]
110
- if !all_of.blank?
111
- all_of.each do |schema_nested|
112
- schema_nested.properties.each do |property|
113
- properties.push property[1]
114
- end
115
- end
116
- end
117
- properties.each do |property|
118
- # Must be a schema be referenced by another schema
119
- # And not a property of a schema
120
- if property.node_context.referenced_by.to_s.include?("#/components/schemas") &&
121
- !property.node_context.source_location.to_s.include?("/properties/")
122
- schema_name = get_schema_name(property.node_context.source_location.to_s)
123
- end
124
- if !schema_name.nil?
125
- schemas.push schema_name
126
- end
127
- # Check sub-properties for references
128
- schemas.concat(schemas_from_schema(property))
79
+ schemas = schema.properties.map(&:last)
80
+ schemas << schema.items if schema.items && schema.type == "array"
81
+ schemas += schema.all_of.to_a.flat_map { |s| s.properties.map(&:last) }
82
+
83
+ schemas.flat_map do |nested|
84
+ sub_schemas = schemas_from_schema(nested)
85
+ nested.name ? [nested.name] + sub_schemas : sub_schemas
129
86
  end
130
- schemas
131
87
  end
132
88
 
133
89
  def operations(path, path_id)
134
- output = ""
135
- operations = get_operations(path)
136
- operations.compact.each do |key, operation|
90
+ get_operations(path).inject("") do |memo, (key, operation)|
137
91
  id = "#{path_id}-#{key.parameterize}"
138
92
  parameters = parameters(operation, id)
139
93
  responses = responses(operation, id)
140
- output += @template_operation.result(binding)
94
+ memo + @template_operation.result(binding)
141
95
  end
142
- output
143
96
  end
144
97
 
145
98
  def parameters(operation, operation_id)
146
99
  parameters = operation.parameters
147
100
  id = "#{operation_id}-parameters"
148
- output = @template_parameters.result(binding)
149
- output
101
+ @template_parameters.result(binding)
150
102
  end
151
103
 
152
104
  def responses(operation, operation_id)
153
105
  responses = operation.responses
154
106
  id = "#{operation_id}-responses"
155
- output = @template_responses.result(binding)
156
- output
157
- end
158
-
159
- def markdown(text)
160
- if text
161
- Tilt["markdown"].new(context: @app) { text }.render
162
- end
107
+ @template_responses.result(binding)
163
108
  end
164
109
 
165
110
  def json_output(schema)
166
- properties = schema_properties(schema)
111
+ properties = schema_properties(schema)
167
112
  JSON.pretty_generate(properties)
168
113
  end
169
114
 
@@ -172,76 +117,26 @@ module GovukTechDocs
172
117
  end
173
118
 
174
119
  def schema_properties(schema_data)
175
- properties = Hash.new
176
- if defined? schema_data.properties
177
- schema_data.properties.each do |key, property|
178
- properties[key] = property
179
- end
180
- end
181
- properties.merge! get_all_of_hash(schema_data)
182
- properties_hash = Hash.new
183
- properties.each do |pkey, property|
184
- if property.type == "object"
185
- properties_hash[pkey] = Hash.new
186
- items = property.items
187
- if !items.blank?
188
- properties_hash[pkey] = schema_properties(items)
189
- end
190
- if !property.properties.blank?
191
- properties_hash[pkey] = schema_properties(property)
192
- end
193
- elsif property.type == "array"
194
- properties_hash[pkey] = Array.new
195
- items = property.items
196
- if !items.blank?
197
- properties_hash[pkey].push schema_properties(items)
198
- end
199
- else
200
- properties_hash[pkey] = !property.example.nil? ? property.example : property.type
201
- end
202
- end
203
-
204
- properties_hash
205
- end
206
-
207
- private
120
+ properties = schema_data.properties.to_h
208
121
 
209
- def get_all_of_array(schema)
210
- properties = Array.new
211
- if schema.is_a?(Array)
212
- schema = schema[1]
213
- end
214
- if schema["allOf"]
215
- all_of = schema["allOf"]
216
- end
217
- if !all_of.blank?
218
- all_of.each do |schema_nested|
219
- schema_nested.properties.each do |property|
220
- if property.is_a?(Array)
221
- property = property[1]
222
- end
223
- properties.push property
224
- end
225
- end
122
+ schema_data.all_of.to_a.each do |all_of_schema|
123
+ properties.merge!(all_of_schema.properties.to_h)
226
124
  end
227
- properties
228
- end
229
125
 
230
- def get_all_of_hash(schema)
231
- properties = Hash.new
232
- if schema["allOf"]
233
- all_of = schema["allOf"]
234
- end
235
- if !all_of.blank?
236
- all_of.each do |schema_nested|
237
- schema_nested.properties.each do |key, property|
238
- properties[key] = property
239
- end
240
- end
126
+ properties.each_with_object({}) do |(name, schema), memo|
127
+ memo[name] = case schema.type
128
+ when "object"
129
+ schema_properties(schema.items || schema)
130
+ when "array"
131
+ schema.items ? [schema_properties(schema.items)] : []
132
+ else
133
+ schema.example || schema.type
134
+ end
241
135
  end
242
- properties
243
136
  end
244
137
 
138
+ private
139
+
245
140
  def get_renderer(file)
246
141
  template_path = File.join(File.dirname(__FILE__), "templates/" + file)
247
142
  template = File.open(template_path, "r").read
@@ -249,31 +144,20 @@ module GovukTechDocs
249
144
  end
250
145
 
251
146
  def get_operations(path)
252
- operations = {}
253
- operations["get"] = path.get if defined? path.get
254
- operations["put"] = path.put if defined? path.put
255
- operations["post"] = path.post if defined? path.post
256
- operations["delete"] = path.delete if defined? path.delete
257
- operations["patch"] = path.patch if defined? path.patch
258
- operations
259
- end
260
-
261
- def get_schema_name(text)
262
- unless text.is_a?(String)
263
- return nil
264
- end
265
-
266
- # Schema dictates that it's always components['schemas']
267
- text.gsub(/#\/components\/schemas\//, "")
147
+ {
148
+ "get" => path.get,
149
+ "put" => path.put,
150
+ "post" => path.post,
151
+ "delete" => path.delete,
152
+ "patch" => path.patch,
153
+ }.compact
268
154
  end
269
155
 
270
156
  def get_schema_link(schema)
271
- schema_name = get_schema_name schema.node_context.source_location.to_s
272
- if !schema_name.nil?
273
- id = "schema-#{schema_name.parameterize}"
274
- output = "<a href='\##{id}'>#{schema_name}</a>"
275
- output
276
- end
157
+ return unless schema.name
158
+
159
+ id = "schema-#{schema.name.parameterize}"
160
+ "<a href='\##{id}'>#{schema.name}</a>"
277
161
  end
278
162
  end
279
163
  end
@@ -1,7 +1,8 @@
1
1
  <h1 id="<%= info.title.parameterize %>"><%= info.title %> v<%= info.version %></h1>
2
- <%= markdown(info.description) %>
2
+ <%= info.description_html %>
3
3
 
4
- <% unless servers.empty? %>
4
+ <%# OpenAPI files default to having a single server of URL "/" %>
5
+ <% if servers.length > 1 || servers[0].url != "/" %>
5
6
  <h2 id="servers">Servers</h2>
6
7
  <div id="server-list">
7
8
  <% servers.each do |server| %>
@@ -3,7 +3,7 @@
3
3
  <p><em><%= operation.summary %></em></p>
4
4
  <% end %>
5
5
  <% if operation.description %>
6
- <p><%= markdown(operation.description) %></p>
6
+ <%= operation.description_html %>
7
7
  <% end %>
8
8
 
9
9
  <%= parameters %>
@@ -11,7 +11,7 @@
11
11
  <td><%= parameter.in %></td>
12
12
  <td><%= parameter.schema.type %></td>
13
13
  <td><%= parameter.required? %></td>
14
- <td><%= markdown(parameter.description) %>
14
+ <td><%= parameter.description_html %>
15
15
  <% if parameter.schema.enum %>
16
16
  <p>Available items:</p>
17
17
  <ul>