graphql-docs 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/README.md +75 -15
- data/Rakefile +28 -0
- data/graphql-docs.gemspec +3 -3
- data/lib/graphql-docs.rb +3 -2
- data/lib/graphql-docs/configuration.rb +6 -2
- data/lib/graphql-docs/generator.rb +10 -35
- data/lib/graphql-docs/helpers.rb +74 -0
- data/lib/graphql-docs/layouts/default.html +39 -0
- data/lib/graphql-docs/layouts/includes/sidebar.html +127 -0
- data/lib/graphql-docs/parser.rb +3 -0
- data/lib/graphql-docs/renderer.rb +13 -4
- data/lib/graphql-docs/version.rb +1 -1
- data/sample_assets/_sass/_api-box.scss +75 -0
- data/sample_assets/_sass/_content.scss +497 -0
- data/sample_assets/_sass/_fonts.scss +21 -0
- data/sample_assets/_sass/_header.scss +59 -0
- data/sample_assets/_sass/_mobile.scss +92 -0
- data/sample_assets/_sass/_normalize.scss +127 -0
- data/sample_assets/_sass/_search.scss +34 -0
- data/sample_assets/_sass/_sidebar.scss +81 -0
- data/sample_assets/_sass/_syntax.scss +291 -0
- data/sample_assets/_sass/_types.scss +0 -0
- data/sample_assets/_sass/screen.scss +647 -0
- data/sample_assets/css/screen.scss +48 -0
- metadata +39 -25
- data/lib/graphql-docs/generator/helpers.rb +0 -46
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 540afb95d491f00898705c8bd73fdb8a31d685c9
|
4
|
+
data.tar.gz: 23b419944ad81f60fff9264e3691d604ffeda467
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6ee639a760366f5f240dc117d5770045700e1676eaf9abb06041009513e0a31470a3c6bd77eaf1da4642e542fdc35e2669f9ee22dff23da6ee8c2aa6ee74edf5
|
7
|
+
data.tar.gz: 78561641aae9442b65c565b1f198f0dc9da933bfbefc8ad1f6ad50b3d553d4670fcebf3c3d094fb5ecc18779cd2fa7b043a572fe7b1c1d4181302a8fc6e2bddb
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -26,12 +26,6 @@ Simple! Call `GraphQLDocs.generate`, taking care to pass in the GraphQL endpoint
|
|
26
26
|
GraphQLDocs.build(url: "http://graphql.org/swapi-graphql/")
|
27
27
|
```
|
28
28
|
|
29
|
-
If you already have the JSON locally, great! Call the same method with `path` instead:
|
30
|
-
|
31
|
-
``` ruby
|
32
|
-
GraphQLDocs.build(path: "location/to/sw-api.json")
|
33
|
-
```
|
34
|
-
|
35
29
|
If your GraphQL endpoint requires authentication, you can provide a username or password, or an access token:
|
36
30
|
|
37
31
|
``` ruby
|
@@ -50,37 +44,103 @@ options = {
|
|
50
44
|
GraphQLDocs.build(options)
|
51
45
|
```
|
52
46
|
|
47
|
+
If you already have the JSON locally, great! Call the same method with `path` instead:
|
48
|
+
|
49
|
+
``` ruby
|
50
|
+
GraphQLDocs.build(path: 'location/to/sw-api.json')
|
51
|
+
```
|
52
|
+
|
53
53
|
## Breakdown
|
54
54
|
|
55
|
-
There are
|
55
|
+
There are several phaseses going on in one little `GraphQLDocs.build` call:
|
56
56
|
|
57
57
|
* The GraphQL JSON is _fetched_ (if you passed `url`) through `GraphQL::Client` (or simply read if you passed `path`).
|
58
58
|
* `GraphQL::Parser` manipulates that JSON into a slightly saner format.
|
59
59
|
* `GraphQL::Generator` takes that JSON and converts it into HTML.
|
60
|
+
* `GraphQL::Parser` technically runs as part of the generation phase. It passes the contents of each page through a Markdown renderer.
|
60
61
|
|
61
|
-
If you wanted to, you could break these calls up individually:
|
62
|
+
If you wanted to, you could break these calls up individually. For example:
|
62
63
|
|
63
64
|
``` ruby
|
64
|
-
|
65
|
-
|
65
|
+
options = {}
|
66
|
+
options[:path] = "#{File.dirname(__FILE__)}/../data/graphql/docs.json"
|
67
|
+
my_renderer = MySuperCoolRenderer(options)
|
68
|
+
options[:renderer] = my_renderer
|
66
69
|
|
67
|
-
|
70
|
+
options = GraphQLDocs::Configuration::GRAPHQLDOCS_DEFAULTS.merge(options)
|
71
|
+
|
72
|
+
response = File.read(options[:path])
|
68
73
|
|
69
74
|
parser = GraphQLDocs::Parser.new(response, options)
|
70
75
|
parsed_schema = parser.parse
|
71
76
|
|
72
|
-
|
73
|
-
generator = Generator.new(parsed_schema, options)
|
77
|
+
generator = GraphQLDocs::Generator.new(parsed_schema, options)
|
74
78
|
|
75
79
|
generator.generate
|
76
80
|
```
|
77
81
|
|
78
82
|
## Generating output
|
79
83
|
|
80
|
-
|
84
|
+
By default, the HTML generation process uses ERB to layout the content. There are a bunch of default options provided for you, but feel free to override any of these. The *Configuration* section below has more information on what you can change.
|
85
|
+
|
86
|
+
It also uses [html-pipeline](https://github.com/jch/html-pipeline) to perform the Markdown rendering by default. You can override this by providing a custom rendering class. `initialize` takes two arguments, the configuration options and the parsed schema. You must implement at least one method, `render`, which takes the GraphQL type, the name, and the layout contents. For example:
|
87
|
+
|
88
|
+
``` ruby
|
89
|
+
class CustomRenderer
|
90
|
+
def initialize(options, parsed_schema)
|
91
|
+
@options = options
|
92
|
+
@parsed_schema = parsed_schema
|
93
|
+
end
|
94
|
+
|
95
|
+
def render(type, name, contents)
|
96
|
+
contents.sub(/Repository/i, 'Meow Woof!')
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
options[:path] = 'location/to/sw-api.json'
|
101
|
+
options[:renderer] = CustomRenderer
|
81
102
|
|
82
|
-
|
103
|
+
GraphQLDocs.build(options)
|
104
|
+
```
|
105
|
+
|
106
|
+
### Helper methods
|
107
|
+
|
108
|
+
In your ERB layouts, there are several helper methods you can use. The helper methods are:
|
109
|
+
|
110
|
+
* `slugify(str)` - This slugifies the given string.
|
111
|
+
* `include(filename, opts)` - This embeds a template from your `includes` folder, passing along the local options provided.
|
112
|
+
* `markdown(string)` - This converts a string from Markdown to HTML.
|
113
|
+
|
114
|
+
To call these methods, you must use the dot notation, such as `<%= slugify.(text) %>`.
|
115
|
+
|
116
|
+
## Configuration
|
117
|
+
|
118
|
+
The following options are available:
|
119
|
+
|
120
|
+
|
121
|
+
| Option | Description | Default |
|
122
|
+
| :----- | :---------- | :------ |
|
123
|
+
| `access_token` | Uses this token while making requests through `GraphQLDocs::Client`. | `nil` |
|
124
|
+
| `login` | Uses this login while making requests through `GraphQLDocs::Client`. | `nil` |
|
125
|
+
| `password` | Uses this password while making requests through `GraphQLDocs::Client`. | `nil` |
|
126
|
+
| `path` | `GraphQLDocs::Client` loads a JSON file found at this location, representing the response from an introspection query. | `nil` |
|
127
|
+
| `url` | `GraphQLDocs::Client` makes a `POST` request to this URL, passing along the introspection query. | `nil` |
|
128
|
+
| `output_dir` | The location of the output HTML. | `./output/` |
|
129
|
+
| `delete_output` | Deletes `output_dir` before generating content. | `false` |
|
130
|
+
| `pipeline_config` | Defines two sub-keys, `pipeline` and `context`, which are used by `html-pipeline` when rendering your output. | `pipeline` has `ExtendedMarkdownFilter`, `EmojiFilter`, and `TableOfContentsFilter`. `context` has `gfm: false` and `asset_root` set to GitHub's CDN. |
|
131
|
+
| `renderer` | The rendering class to use. | `GraphQLDocs::Renderer`
|
132
|
+
| `templates` | The templates to use when generating HTML. You may override any of the following keys: `includes`, `objects`, `mutations`, `interfaces`, `enums`, `unions`, `input_objects`, `scalars`. | The default gem ones are found in _layouts/_.
|
83
133
|
|
84
134
|
## Development
|
85
135
|
|
86
136
|
After checking out the repo, run `script/bootstrap` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
137
|
+
|
138
|
+
## Sample site
|
139
|
+
|
140
|
+
Clone this repository and run:
|
141
|
+
|
142
|
+
```
|
143
|
+
bundle exec rake sample
|
144
|
+
```
|
145
|
+
|
146
|
+
to see some sample output.
|
data/Rakefile
CHANGED
@@ -21,3 +21,31 @@ task :console do
|
|
21
21
|
ARGV.clear
|
22
22
|
Pry.start
|
23
23
|
end
|
24
|
+
|
25
|
+
task :sample do
|
26
|
+
require 'graphql-docs'
|
27
|
+
require 'sass'
|
28
|
+
|
29
|
+
options = {}
|
30
|
+
options[:output_dir] = 'sample'
|
31
|
+
options[:delete_output] = true
|
32
|
+
options[:path] = File.join(File.dirname(__FILE__), 'test', 'graphql-docs', 'fixtures', 'gh-api.json')
|
33
|
+
|
34
|
+
GraphQLDocs.build(options)
|
35
|
+
|
36
|
+
assets_dir = File.join('sample', 'assets')
|
37
|
+
FileUtils.mkdir_p(assets_dir)
|
38
|
+
|
39
|
+
sass = File.join('sample_assets', 'css', 'screen.scss')
|
40
|
+
system `sass --sourcemap=none #{sass}:style.css`
|
41
|
+
|
42
|
+
FileUtils.mv('style.css', File.join('sample', 'assets/style.css'))
|
43
|
+
|
44
|
+
starting_dir = 'sample'
|
45
|
+
starting_file = File.join(starting_dir, 'object', 'repository', 'index.html')
|
46
|
+
|
47
|
+
puts 'Navigate to http://localhost:3000 to see the sample docs'
|
48
|
+
puts "Launching #{starting_file}"
|
49
|
+
system "open #{starting_file}"
|
50
|
+
system "ruby -run -e httpd #{starting_dir} -p 3000"
|
51
|
+
end
|
data/graphql-docs.gemspec
CHANGED
@@ -20,15 +20,14 @@ Gem::Specification.new do |spec|
|
|
20
20
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
21
21
|
spec.require_paths = ['lib']
|
22
22
|
|
23
|
-
spec.add_dependency 'faraday', '~> 0.
|
23
|
+
spec.add_dependency 'faraday', '< 0.10'#'~> 0.9'
|
24
24
|
spec.add_dependency 'graphql', '~> 1.4'
|
25
25
|
|
26
26
|
# rendering
|
27
|
-
spec.add_dependency 'html-pipeline', '2.
|
27
|
+
spec.add_dependency 'html-pipeline', '~> 2.2'
|
28
28
|
spec.add_dependency 'github-markdown', '0.6.9'
|
29
29
|
spec.add_dependency 'extended-markdown-filter', '~> 0.4'
|
30
30
|
spec.add_dependency 'gemoji', '2.1.0'
|
31
|
-
spec.add_dependency 'page-toc-filter', '~> 0.0.1'
|
32
31
|
|
33
32
|
spec.add_development_dependency 'awesome_print'
|
34
33
|
spec.add_development_dependency 'bundler', '~> 1.14'
|
@@ -37,5 +36,6 @@ Gem::Specification.new do |spec|
|
|
37
36
|
spec.add_development_dependency 'pry', '~> 0.10.0'
|
38
37
|
spec.add_development_dependency 'rake', '~> 10.0'
|
39
38
|
spec.add_development_dependency 'rubocop-github'
|
39
|
+
spec.add_development_dependency 'sass', '~> 3.4'
|
40
40
|
spec.add_development_dependency 'webmock', '~> 2.3'
|
41
41
|
end
|
data/lib/graphql-docs.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
require 'graphql-docs/client'
|
2
|
+
require 'graphql-docs/helpers'
|
3
|
+
require 'graphql-docs/renderer'
|
2
4
|
require 'graphql-docs/configuration'
|
3
5
|
require 'graphql-docs/generator'
|
4
6
|
require 'graphql-docs/parser'
|
5
|
-
require 'graphql-docs/renderer'
|
6
7
|
require 'graphql-docs/version'
|
7
8
|
|
8
9
|
begin
|
@@ -32,7 +33,7 @@ module GraphQLDocs
|
|
32
33
|
parser = GraphQLDocs::Parser.new(response, options)
|
33
34
|
parsed_schema = parser.parse
|
34
35
|
|
35
|
-
generator = Generator.new(parsed_schema, options)
|
36
|
+
generator = GraphQLDocs::Generator.new(parsed_schema, options)
|
36
37
|
|
37
38
|
generator.generate
|
38
39
|
end
|
@@ -9,18 +9,22 @@ module GraphQLDocs
|
|
9
9
|
url: nil,
|
10
10
|
|
11
11
|
# Generating
|
12
|
+
delete_output: false,
|
12
13
|
output_dir: './output/',
|
13
14
|
pipeline_config: {
|
14
15
|
pipeline:
|
15
16
|
%i(ExtendedMarkdownFilter
|
16
17
|
EmojiFilter
|
17
|
-
|
18
|
+
TableOfContentsFilter),
|
18
19
|
context: {
|
19
20
|
gfm: false,
|
20
21
|
asset_root: 'https://a248.e.akamai.net/assets.github.com/images/icons'
|
21
22
|
}
|
22
23
|
},
|
24
|
+
renderer: GraphQLDocs::Renderer,
|
25
|
+
|
23
26
|
templates: {
|
27
|
+
default: "#{File.dirname(__FILE__)}/layouts/default.html",
|
24
28
|
includes: "#{File.dirname(__FILE__)}/layouts/includes",
|
25
29
|
objects: "#{File.dirname(__FILE__)}/layouts/graphql_objects.html",
|
26
30
|
mutations: "#{File.dirname(__FILE__)}/layouts/graphql_mutations.html",
|
@@ -30,6 +34,6 @@ module GraphQLDocs
|
|
30
34
|
input_objects: "#{File.dirname(__FILE__)}/layouts/graphql_input_objects.html",
|
31
35
|
scalars: "#{File.dirname(__FILE__)}/layouts/graphql_scalars.html"
|
32
36
|
}
|
33
|
-
}
|
37
|
+
}.freeze
|
34
38
|
end
|
35
39
|
end
|
@@ -1,15 +1,16 @@
|
|
1
1
|
require 'erb'
|
2
|
-
require 'graphql-docs/generator/helpers'
|
3
2
|
|
4
3
|
module GraphQLDocs
|
5
4
|
class Generator
|
6
5
|
include Helpers
|
7
6
|
|
7
|
+
attr_accessor :parsed_schema
|
8
|
+
|
8
9
|
def initialize(parsed_schema, options)
|
9
10
|
@parsed_schema = parsed_schema
|
10
11
|
@options = options
|
11
12
|
|
12
|
-
@renderer =
|
13
|
+
@renderer = @options[:renderer].new(@options, @parsed_schema)
|
13
14
|
|
14
15
|
@graphql_object_template = ERB.new(File.read(@options[:templates][:objects]))
|
15
16
|
@graphql_mutations_template = ERB.new(File.read(@options[:templates][:mutations]))
|
@@ -21,7 +22,7 @@ module GraphQLDocs
|
|
21
22
|
end
|
22
23
|
|
23
24
|
def generate
|
24
|
-
FileUtils.rm_rf(@options[:output_dir])
|
25
|
+
FileUtils.rm_rf(@options[:output_dir]) if @options[:delete_output]
|
25
26
|
|
26
27
|
create_graphql_object_pages
|
27
28
|
create_graphql_mutation_pages
|
@@ -45,8 +46,10 @@ module GraphQLDocs
|
|
45
46
|
|
46
47
|
def create_graphql_mutation_pages
|
47
48
|
graphql_mutation_types.each do |mutation|
|
48
|
-
|
49
|
-
|
49
|
+
input_name = mutation['args'].first['type']['ofType']['name']
|
50
|
+
return_name = mutation['type']['name']
|
51
|
+
input = graphql_input_object_types.find { |t| t['name'] == input_name }
|
52
|
+
payload = graphql_object_types.find { |t| t['name'] == return_name }
|
50
53
|
|
51
54
|
opts = { type: mutation, input_fields: input, return_fields: payload }.merge(helper_methods)
|
52
55
|
|
@@ -102,39 +105,11 @@ module GraphQLDocs
|
|
102
105
|
|
103
106
|
private
|
104
107
|
|
105
|
-
def graphql_mutation_types
|
106
|
-
graphql_object_types.find { |t| t['name'] == 'Mutation' }['fields']
|
107
|
-
end
|
108
|
-
|
109
|
-
def graphql_object_types
|
110
|
-
@parsed_schema['object_types']
|
111
|
-
end
|
112
|
-
|
113
|
-
def graphql_interface_types
|
114
|
-
@parsed_schema['interface_types']
|
115
|
-
end
|
116
|
-
|
117
|
-
def graphql_enum_types
|
118
|
-
@parsed_schema['enum_types']
|
119
|
-
end
|
120
|
-
|
121
|
-
def graphql_union_types
|
122
|
-
@parsed_schema['union_types']
|
123
|
-
end
|
124
|
-
|
125
|
-
def graphql_input_object_types
|
126
|
-
@parsed_schema['input_object_types']
|
127
|
-
end
|
128
|
-
|
129
|
-
def graphql_scalar_types
|
130
|
-
@parsed_schema['scalar_types']
|
131
|
-
end
|
132
|
-
|
133
108
|
def write_file(type, name, contents)
|
134
109
|
path = File.join(@options[:output_dir], type, name.downcase)
|
135
110
|
FileUtils.mkdir_p(path)
|
136
|
-
contents = @renderer.render(contents)
|
137
|
-
File.write(File.join(path, 'index.html'), contents)
|
111
|
+
contents = @renderer.render(type, name, contents)
|
112
|
+
File.write(File.join(path, 'index.html'), contents) unless contents.nil?
|
138
113
|
end
|
139
114
|
end
|
140
115
|
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module GraphQLDocs
|
2
|
+
module Helpers
|
3
|
+
SLUGIFY_PRETTY_REGEXP = Regexp.new("[^[:alnum:]._~!$&'()+,;=@]+").freeze
|
4
|
+
|
5
|
+
attr_accessor :templates
|
6
|
+
|
7
|
+
def slugify(str)
|
8
|
+
slug = str.gsub(SLUGIFY_PRETTY_REGEXP, '-')
|
9
|
+
slug.gsub!(%r!^\-|\-$!i, '')
|
10
|
+
slug.downcase
|
11
|
+
end
|
12
|
+
|
13
|
+
def include(filename, opts = {})
|
14
|
+
template = fetch_include(filename)
|
15
|
+
template.result(OpenStruct.new(opts.merge(helper_methods)).instance_eval { binding })
|
16
|
+
end
|
17
|
+
|
18
|
+
def markdown(string)
|
19
|
+
GitHub::Markdown.render(string || 'n/a')
|
20
|
+
end
|
21
|
+
|
22
|
+
def graphql_mutation_types
|
23
|
+
@parsed_schema['mutation_types']
|
24
|
+
end
|
25
|
+
|
26
|
+
def graphql_object_types
|
27
|
+
@parsed_schema['object_types']
|
28
|
+
end
|
29
|
+
|
30
|
+
def graphql_interface_types
|
31
|
+
@parsed_schema['interface_types']
|
32
|
+
end
|
33
|
+
|
34
|
+
def graphql_enum_types
|
35
|
+
@parsed_schema['enum_types']
|
36
|
+
end
|
37
|
+
|
38
|
+
def graphql_union_types
|
39
|
+
@parsed_schema['union_types']
|
40
|
+
end
|
41
|
+
|
42
|
+
def graphql_input_object_types
|
43
|
+
@parsed_schema['input_object_types']
|
44
|
+
end
|
45
|
+
|
46
|
+
def graphql_scalar_types
|
47
|
+
@parsed_schema['scalar_types']
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def fetch_include(filename)
|
53
|
+
@templates ||= {}
|
54
|
+
|
55
|
+
return @templates[filename] unless @templates[filename].nil?
|
56
|
+
|
57
|
+
@templates[filename] = ERB.new(File.read(File.join(@options[:templates][:includes], filename)))
|
58
|
+
@templates[filename]
|
59
|
+
end
|
60
|
+
|
61
|
+
def helper_methods
|
62
|
+
return @helper_methods if defined?(@helper_methods)
|
63
|
+
|
64
|
+
@helper_methods = {}
|
65
|
+
|
66
|
+
Helpers.instance_methods.each do |name|
|
67
|
+
next if name == :helper_methods
|
68
|
+
@helper_methods[name] = method(name)
|
69
|
+
end
|
70
|
+
|
71
|
+
@helper_methods
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8">
|
5
|
+
<meta name="description" content="<%= name %> GraphQL documentation">
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
7
|
+
<title><%= name %></title>
|
8
|
+
<link href='https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,300,200,300italic,400italic' rel='stylesheet' type='text/css'>
|
9
|
+
<link rel="stylesheet" href="../../assets/style.css">
|
10
|
+
<script src="https://code.jquery.com/jquery-3.0.0.min.js" integrity="sha256-JmvOoLtYsmqlsWxa7mDSLMwa6dZ9rrIdtrrVYRnDRH0=" crossorigin="anonymous"></script>
|
11
|
+
</head>
|
12
|
+
<body>
|
13
|
+
|
14
|
+
<div id="wrap">
|
15
|
+
<div id="header">
|
16
|
+
</div>
|
17
|
+
<div id="sidebar">
|
18
|
+
<%= include.('sidebar.html') %>
|
19
|
+
</div>
|
20
|
+
<div id="content">
|
21
|
+
|
22
|
+
<h1><%= name %></h1>
|
23
|
+
|
24
|
+
<%= contents %>
|
25
|
+
|
26
|
+
</div>
|
27
|
+
|
28
|
+
<!-- mobile only -->
|
29
|
+
<div id="mobile-header">
|
30
|
+
<a class="menu-button"></a>
|
31
|
+
<a class="logo" href="/">
|
32
|
+
|
33
|
+
</a>
|
34
|
+
</div>
|
35
|
+
<div id="mobile-shade"></div>
|
36
|
+
|
37
|
+
</div>
|
38
|
+
</body>
|
39
|
+
</html>
|