govuk_tech_docs 2.1.0 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.

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/.nvmrc +1 -1
  4. data/.ruby-version +1 -1
  5. data/.travis.yml +5 -0
  6. data/CHANGELOG.md +41 -2
  7. data/README.md +15 -22
  8. data/example/.ruby-version +1 -1
  9. data/govuk_tech_docs.gemspec +2 -7
  10. data/lib/assets/javascripts/_modules/search.js +13 -2
  11. data/lib/assets/javascripts/_modules/table-of-contents.js +9 -14
  12. data/lib/assets/stylesheets/_govuk_tech_docs.scss +9 -10
  13. data/lib/assets/stylesheets/modules/_page-review.scss +3 -5
  14. data/lib/assets/stylesheets/modules/_search.scss +50 -24
  15. data/lib/assets/stylesheets/modules/_technical-documentation.scss +11 -2
  16. data/lib/assets/stylesheets/modules/_toc.scss +23 -13
  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/tech_docs_html_renderer.rb +75 -1
  25. data/lib/govuk_tech_docs/version.rb +1 -1
  26. data/lib/source/images/search-button.png +0 -0
  27. data/lib/source/layouts/_search.erb +10 -4
  28. data/lib/source/layouts/core.erb +4 -4
  29. data/package-lock.json +358 -288
  30. data/package.json +2 -2
  31. metadata +48 -65
@@ -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 {
@@ -15,14 +15,18 @@
15
15
 
16
16
  &__list {
17
17
  li {
18
+ a {
19
+ @include govuk-link-decoration;
20
+ @include govuk-link-style-no-visited-state;
21
+ @include govuk-link-style-no-underline;
22
+ }
23
+
18
24
  a:link, a:visited {
19
25
  display: block;
20
26
  position: relative;
21
27
  padding: 8px govuk-spacing(6) 8px govuk-spacing(2);
22
28
  margin: 0 -1 * govuk-spacing(3);
23
29
  border-left: 5px solid transparent;
24
- text-decoration: none;
25
- color: $govuk-link-colour;
26
30
 
27
31
  @include govuk-media-query(tablet) {
28
32
  &.toc-link--in-view {
@@ -33,21 +37,17 @@
33
37
  }
34
38
  }
35
39
 
40
+ a:hover {
41
+ @include govuk-link-hover-decoration;
42
+ }
43
+
36
44
  a:focus {
37
- outline: none;
45
+ text-decoration: none;
38
46
 
39
47
  span {
40
48
  @include govuk-focused-text;
41
49
  }
42
50
  }
43
-
44
- a:hover {
45
- text-decoration: underline;
46
-
47
- &:focus {
48
- text-decoration: none;
49
- }
50
- }
51
51
  }
52
52
 
53
53
  // Top level
@@ -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