diff --git a/assets/stylesheets/application.css.scss b/assets/stylesheets/application.css.scss
index e4314a0f..fb0c08cd 100644
--- a/assets/stylesheets/application.css.scss
+++ b/assets/stylesheets/application.css.scss
@@ -56,6 +56,7 @@
'pages/go',
'pages/haskell',
'pages/jquery',
+ 'pages/jsdoc',
'pages/julia',
'pages/knockout',
'pages/kotlin',
diff --git a/assets/stylesheets/pages/_jsdoc.scss b/assets/stylesheets/pages/_jsdoc.scss
new file mode 100644
index 00000000..05e83f1d
--- /dev/null
+++ b/assets/stylesheets/pages/_jsdoc.scss
@@ -0,0 +1,25 @@
+._jsdoc {
+ > h2 { @extend %block-heading; }
+
+ > h3 {
+ @extend %lined-heading;
+ font-size: 1.1em;
+ }
+
+ figure {
+ margin-left: 0;
+ font-size: inherit;
+
+ pre {
+ margin-bottom: 0.5em;
+ }
+
+ figcaption {
+ font-style: italic;
+ }
+ }
+
+ pre {
+ font-size: inherit;
+ }
+}
diff --git a/lib/docs/filters/jsdoc/clean_html.rb b/lib/docs/filters/jsdoc/clean_html.rb
new file mode 100644
index 00000000..f61593e2
--- /dev/null
+++ b/lib/docs/filters/jsdoc/clean_html.rb
@@ -0,0 +1,43 @@
+module Docs
+ class Jsdoc
+ class CleanHtmlFilter < Filter
+ def call
+ css('h2').each do |node|
+ next unless node.content.strip == 'Table of Contents'
+ toc_ul = node.next_element
+ toc_block = node.add_next_sibling('').first
+
+ node.name = 'h3'
+ node['class'] = '_toc-title'
+ node.remove
+ toc_block.add_child(node)
+
+ toc_ul.remove
+ toc_ul['class'] = '_toc-list'
+ toc_ul.css('ul').each do |child_list|
+ child_list.remove
+ end
+ toc_block.add_child(toc_ul)
+ end
+
+ css('.prettyprint').each do |node|
+ match = /lang-(\w+)/.match(node['class'])
+ next unless match
+
+ lang = match[1]
+ node.remove_attribute('class')
+ node['data-language'] = lang
+ end
+
+ css('figure').each do |node|
+ caption = node.at_css 'figcaption'
+ next unless caption
+
+ node.children.last.add_next_sibling(caption)
+ end
+
+ doc
+ end
+ end
+ end
+end
diff --git a/lib/docs/filters/jsdoc/entries.rb b/lib/docs/filters/jsdoc/entries.rb
new file mode 100644
index 00000000..62170151
--- /dev/null
+++ b/lib/docs/filters/jsdoc/entries.rb
@@ -0,0 +1,25 @@
+module Docs
+ class Jsdoc
+ class EntriesFilter < Docs::EntriesFilter
+ def get_name
+ at_css('h1').content
+ end
+ def get_type
+ case slug
+ when /^about-/
+ 'Getting Started'
+ when /^plugins-/
+ 'Plugins'
+ when /^howto-/
+ 'Examples'
+ when /^tags-inline-/
+ 'Inline Tags'
+ when /^tags-/
+ 'Tags'
+ else
+ 'Other' # Only shown if a new category gets added in the upstream docs
+ end
+ end
+ end
+ end
+end
diff --git a/lib/docs/scrapers/jsdoc.rb b/lib/docs/scrapers/jsdoc.rb
new file mode 100644
index 00000000..de43eb4e
--- /dev/null
+++ b/lib/docs/scrapers/jsdoc.rb
@@ -0,0 +1,30 @@
+module Docs
+ class Jsdoc < UrlScraper
+ self.name = 'JSDoc'
+ self.type = 'jsdoc'
+ self.release = '3.5.5'
+ self.base_url = 'http://usejsdoc.org/'
+ self.links = {
+ home: 'http://usejsdoc.org/',
+ code: 'https://github.com/jsdoc3/jsdoc'
+ }
+
+ html_filters.push 'jsdoc/clean_html', 'jsdoc/entries'
+
+ options[:trailing_slash] = false
+ options[:container] = 'article'
+ options[:skip] = [
+ 'about-license-jsdoc3.html'
+ ]
+ options[:attribution] = <<-HTML
+ © 2011–2017
+
+ JSDoc 3 contributors
+
+ Licensed under
+
+ CC BY-SA 3.0
+
+ HTML
+ end
+end
diff --git a/public/icons/docs/jsdoc/16.png b/public/icons/docs/jsdoc/16.png
new file mode 100644
index 00000000..6f1ad033
Binary files /dev/null and b/public/icons/docs/jsdoc/16.png differ
diff --git a/public/icons/docs/jsdoc/16@2x.png b/public/icons/docs/jsdoc/16@2x.png
new file mode 100644
index 00000000..76971d4f
Binary files /dev/null and b/public/icons/docs/jsdoc/16@2x.png differ
diff --git a/public/icons/docs/jsdoc/SOURCE b/public/icons/docs/jsdoc/SOURCE
new file mode 100644
index 00000000..fedec80b
--- /dev/null
+++ b/public/icons/docs/jsdoc/SOURCE
@@ -0,0 +1 @@
+https://avatars2.githubusercontent.com/u/1530630