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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 95ab4bc20c02f63be2acd6f1383fd57184719a7e
4
- data.tar.gz: 79679c4f467ceef22e31677a22b4706011c555c6
3
+ metadata.gz: 540afb95d491f00898705c8bd73fdb8a31d685c9
4
+ data.tar.gz: 23b419944ad81f60fff9264e3691d604ffeda467
5
5
  SHA512:
6
- metadata.gz: d4d9f76f49551625f2509138f44e90bae1e5643ea736b1b949a2efbd66366acb262b8710813a1afe401515c8525b788ca95a77f60163a9ee1c3c0130c148b418
7
- data.tar.gz: 087bfd499ba9196fbd85c6026dd16911b0f270cc81fd162782ad0d1a70822112d55bf745906f03ab21c5d7ea196ddd80fa99c76ee01a776b28819ae0725dc4ec
6
+ metadata.gz: 6ee639a760366f5f240dc117d5770045700e1676eaf9abb06041009513e0a31470a3c6bd77eaf1da4642e542fdc35e2669f9ee22dff23da6ee8c2aa6ee74edf5
7
+ data.tar.gz: 78561641aae9442b65c565b1f198f0dc9da933bfbefc8ad1f6ad50b3d553d4670fcebf3c3d094fb5ecc18779cd2fa7b043a572fe7b1c1d4181302a8fc6e2bddb
data/.gitignore CHANGED
@@ -9,3 +9,5 @@
9
9
  /tmp/
10
10
  /output/
11
11
  /test/graphql-docs/fixtures/output/
12
+ /.sass-cache/
13
+ /sample/
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 three phases going on in one little `GraphQLDocs.build` call:
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
- client = GraphQLDocs::Client.new(options)
65
- response = client.fetch
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
- # do something
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
- # do something else
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
- The HTML generation process uses [html-pipeline](https://github.com/jch/html-pipeline) and ERB to style the output. 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.
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
- ### Herlper methods
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.11'
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.5.0'
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
- PageTocFilter),
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 = Renderer.new(@options)
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
- input = graphql_input_object_types.find { |t| t['name'] = mutation['args'].first['type']['ofType']['name'] }
49
- payload = graphql_object_types.find { |t| t['name'] == mutation['type']['name'] }
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>