graphql-docs 0.1.0 → 0.1.1
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/.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>
|