mirror of https://github.com/freeCodeCamp/devdocs
commit
39d3696efe
@ -1,4 +1,43 @@
|
|||||||
._scala {
|
._scala {
|
||||||
@extend %simple;
|
@extend %simple;
|
||||||
|
|
||||||
.deprecated { @extend %label-red; }
|
.deprecated { @extend %label-red; }
|
||||||
|
|
||||||
|
.attributes dl,
|
||||||
|
.attributes pre {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.related-types {
|
||||||
|
@extend %pre;
|
||||||
|
margin: 0;
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.links {
|
||||||
|
@extend %box;
|
||||||
|
margin-left: -1rem;
|
||||||
|
text-align: center;
|
||||||
|
padding: .5em;
|
||||||
|
|
||||||
|
a { padding: .4em }
|
||||||
|
|
||||||
|
@include print {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.source-link {
|
||||||
|
float: right;
|
||||||
|
font-size: .75rem;
|
||||||
|
color: var(--linkColor);
|
||||||
|
cursor: pointer;
|
||||||
|
@extend %user-select-none;
|
||||||
|
|
||||||
|
&:hover { text-decoration: underline; }
|
||||||
|
|
||||||
|
@include print {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
module Docs
|
module Docs
|
||||||
class Scala
|
class Scala
|
||||||
class CleanHtmlFilter < Filter
|
class CleanHtmlV2Filter < Filter
|
||||||
def call
|
def call
|
||||||
@doc = at_css('#content')
|
@doc = at_css('#content')
|
||||||
|
|
@ -0,0 +1,253 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Docs
|
||||||
|
class Scala
|
||||||
|
class CleanHtmlV3Filter < Filter
|
||||||
|
def call
|
||||||
|
# Remove unneeded elements
|
||||||
|
css('.documentableFilter, .documentableAnchor, .documentableBrief').remove
|
||||||
|
|
||||||
|
format_title
|
||||||
|
format_signature
|
||||||
|
format_top_links
|
||||||
|
format_metadata
|
||||||
|
|
||||||
|
# Remove the redundant long descriptions on the main page
|
||||||
|
if slug == 'index'
|
||||||
|
css('.contents').remove
|
||||||
|
else
|
||||||
|
format_members
|
||||||
|
end
|
||||||
|
|
||||||
|
simplify_html
|
||||||
|
|
||||||
|
doc
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
# Formats the title of the page
|
||||||
|
def format_title
|
||||||
|
cover_header = at_css('.cover-header')
|
||||||
|
return if cover_header.nil?
|
||||||
|
|
||||||
|
# Add the kind of page to the title
|
||||||
|
icon = cover_header.at_css('.micon')
|
||||||
|
types = {
|
||||||
|
cl: 'Class',
|
||||||
|
ob: 'Object',
|
||||||
|
tr: 'Trait',
|
||||||
|
en: 'Enum',
|
||||||
|
ty: 'Type',
|
||||||
|
pa: 'Package',
|
||||||
|
}
|
||||||
|
type_id = cover_header.at_css('.micon')['class']
|
||||||
|
type_id.remove!('micon ')
|
||||||
|
type_id.remove!('-wc')
|
||||||
|
type = types[type_id.to_sym]
|
||||||
|
name = CGI.escapeHTML cover_header.at_css('h1').text
|
||||||
|
|
||||||
|
# Add the package name
|
||||||
|
package = at_css('.breadcrumbs a:nth-of-type(3)').text
|
||||||
|
package = package + '.' unless name.empty? || package.empty?
|
||||||
|
|
||||||
|
# Replace the title
|
||||||
|
title = root_page? ? 'Package root' : "#{type} #{package}#{name}".strip
|
||||||
|
cover_header.replace "<h1>#{title}</h1>"
|
||||||
|
end
|
||||||
|
|
||||||
|
# Formats the signature block at the top of the page
|
||||||
|
def format_signature
|
||||||
|
signature = at_css('.signature')
|
||||||
|
signature_annotations = signature.at_css('.annotations')
|
||||||
|
signature_annotations.name = 'small' unless signature_annotations.nil?
|
||||||
|
signature.replace "<h2 id=\"signature\">#{signature.inner_html}</h2>"
|
||||||
|
end
|
||||||
|
|
||||||
|
# Formats the top links (companion page, source code)
|
||||||
|
def format_top_links
|
||||||
|
# Companion page (e.g. List ↔ List$)
|
||||||
|
links = []
|
||||||
|
at_css('.attributes').css('dt').each do |dt|
|
||||||
|
next if dt.content.strip != 'Companion:'
|
||||||
|
dd = dt.next_sibling
|
||||||
|
|
||||||
|
companion_link = dd.at_css('a')
|
||||||
|
companion_link.content = "Companion #{companion_link.content}"
|
||||||
|
links.append(companion_link.to_html)
|
||||||
|
|
||||||
|
dt.remove
|
||||||
|
dd.remove
|
||||||
|
end
|
||||||
|
|
||||||
|
# Source code
|
||||||
|
at_css('.attributes').css('dt').each do |dt|
|
||||||
|
next if dt.content.strip != 'Source:'
|
||||||
|
dd = dt.next_sibling
|
||||||
|
|
||||||
|
source_link = dd.at_css('a')
|
||||||
|
source_link.content = 'Source code'
|
||||||
|
links.append(source_link.to_html)
|
||||||
|
|
||||||
|
dt.remove
|
||||||
|
dd.remove
|
||||||
|
end
|
||||||
|
|
||||||
|
# Format the links
|
||||||
|
title = at_css('h1')
|
||||||
|
title.add_next_sibling("<div class=\"links\">#{links.join(' • ')}</div>")
|
||||||
|
end
|
||||||
|
|
||||||
|
# Metadata about the whole file (e.g. supertypes)
|
||||||
|
def format_metadata
|
||||||
|
# Format the values
|
||||||
|
css('.tabs.single .monospace').each do |node|
|
||||||
|
node.css('> div').each do |div|
|
||||||
|
div['class'] = 'member'
|
||||||
|
end
|
||||||
|
|
||||||
|
node['class'] = 'related-types'
|
||||||
|
|
||||||
|
if node.children.count > 15 # Hide too large lists
|
||||||
|
node.replace "<details>
|
||||||
|
<summary>#{node.children.count} types</summary>
|
||||||
|
#{node.to_html}
|
||||||
|
</details>"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
attributes = at_css('.attributes')
|
||||||
|
|
||||||
|
# Change the HTML structure
|
||||||
|
tabs_names = css('.tabs.single .names .tab')
|
||||||
|
tabs_contents = css('.tabs.single .contents .tab')
|
||||||
|
tabs_names.zip(tabs_contents).each do |name, contents|
|
||||||
|
next if name.content == "Graph"
|
||||||
|
|
||||||
|
attributes.add_child("<dt>#{name.content}</dt>")
|
||||||
|
attributes.add_child("<dd>#{contents.inner_html.strip}</dd>")
|
||||||
|
end
|
||||||
|
|
||||||
|
convert_dl_to_table(attributes)
|
||||||
|
|
||||||
|
tabs = at_css('.tabs')
|
||||||
|
tabs.remove unless tabs.nil? || tabs.parent['class'] == 'membersList'
|
||||||
|
end
|
||||||
|
|
||||||
|
# Format the members (methods, values…)
|
||||||
|
def format_members
|
||||||
|
# Section headings
|
||||||
|
css('.cover h2').each do |node|
|
||||||
|
node.name = 'h3'
|
||||||
|
end
|
||||||
|
css('h2:not(#signature)').remove
|
||||||
|
css(
|
||||||
|
'.membersList h3',
|
||||||
|
|
||||||
|
# Custom group headers for which Scaladoc generates invalid HTML
|
||||||
|
# (<h3><p>…</p></h3>)
|
||||||
|
'.documentableList > h3:empty + p'
|
||||||
|
).each do |node|
|
||||||
|
node.name = 'h2'
|
||||||
|
node.content = node.content
|
||||||
|
end
|
||||||
|
|
||||||
|
# Individual members
|
||||||
|
css('.documentableElement').each do |element|
|
||||||
|
header = element.at_css('.header')
|
||||||
|
header.name = 'h3'
|
||||||
|
|
||||||
|
id = element['id']
|
||||||
|
element.remove_attribute('id')
|
||||||
|
header['id'] = id unless id.nil?
|
||||||
|
|
||||||
|
annotations = element.at_css('.annotations')
|
||||||
|
annotations.name = 'small'
|
||||||
|
header.prepend_child(annotations)
|
||||||
|
|
||||||
|
# View source
|
||||||
|
element.css('dt').each do |dt|
|
||||||
|
next if dt.content.strip != 'Source:'
|
||||||
|
dd = dt.next_sibling
|
||||||
|
|
||||||
|
source_link = dd.at_css('a')
|
||||||
|
source_link.content = 'Source'
|
||||||
|
source_link['class'] = 'source-link'
|
||||||
|
header.prepend_child(source_link)
|
||||||
|
|
||||||
|
dt.remove
|
||||||
|
dd.remove
|
||||||
|
end
|
||||||
|
|
||||||
|
# Format attributes as a table
|
||||||
|
dl = element.at_css('.attributes')
|
||||||
|
convert_dl_to_table(dl) unless dl.nil?
|
||||||
|
|
||||||
|
# Remove the unnecessary wrapper element
|
||||||
|
element.replace(element.inner_html)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Remove deprecated sections
|
||||||
|
css('.documentableList').each do |list|
|
||||||
|
header = list.at_css('.groupHeader')
|
||||||
|
list.remove if (header.text.downcase.include? 'deprecate' rescue false)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Code blocks
|
||||||
|
css('pre > code').each do |code|
|
||||||
|
pre = code.parent
|
||||||
|
pre['data-language'] = 'scala'
|
||||||
|
pre.inner_html = code.inner_html
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Simplify the HTML structure by removing useless elements
|
||||||
|
def simplify_html
|
||||||
|
# Remove unneeded parts of the document
|
||||||
|
@doc = at_css('#content > div')
|
||||||
|
|
||||||
|
# Remove the useless elements around members
|
||||||
|
css('.documentableList > *').each do |element|
|
||||||
|
element.parent = doc
|
||||||
|
end
|
||||||
|
at_css('.membersList').remove
|
||||||
|
|
||||||
|
# Remove useless classes
|
||||||
|
css('.header, .groupHeader, .cover, .documentableName').each do |element|
|
||||||
|
element.remove_attribute('class')
|
||||||
|
end
|
||||||
|
|
||||||
|
# Remove useless attributes
|
||||||
|
css('[t]').each do |element|
|
||||||
|
element.remove_attribute('t')
|
||||||
|
end
|
||||||
|
|
||||||
|
# Remove useless wrapper elements
|
||||||
|
css('.docs, .doc, .memberDocumentation, span, div:not([class])').each do |element|
|
||||||
|
element.replace(element.children)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def convert_dl_to_table(dl)
|
||||||
|
table = Nokogiri::XML::Node.new('table', doc)
|
||||||
|
table['class'] = 'attributes'
|
||||||
|
|
||||||
|
dl.css('> dt').each do |dt|
|
||||||
|
dd = dt.next_element
|
||||||
|
has_dd = dd.name == 'dd' rescue false
|
||||||
|
|
||||||
|
tr = Nokogiri::XML::Node.new('tr', doc)
|
||||||
|
colspan = has_dd ? '' : ' colspan="2"' # handle <dt> without following <dt>
|
||||||
|
tr.add_child("<th#{colspan}>#{dt.inner_html.sub(/:$/, '')}</th>")
|
||||||
|
|
||||||
|
tr.add_child("<td>#{dd.inner_html}</td>") if has_dd
|
||||||
|
|
||||||
|
table.add_child(tr)
|
||||||
|
end
|
||||||
|
|
||||||
|
dl.replace(table)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,105 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Docs
|
||||||
|
class Scala
|
||||||
|
class EntriesV3Filter < Docs::EntriesFilter
|
||||||
|
REPLACEMENTS = {
|
||||||
|
'$eq' => '=',
|
||||||
|
'$colon' => ':',
|
||||||
|
'$less' => '<',
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_name
|
||||||
|
if is_package?
|
||||||
|
at_css('.cover-header h1').text
|
||||||
|
else
|
||||||
|
name = slug.split('/').last
|
||||||
|
|
||||||
|
# Some objects have inner objects, show ParentObject$.ChildObject$ instead of ParentObject$$ChildObject$
|
||||||
|
name = name.gsub('$$', '$.')
|
||||||
|
|
||||||
|
REPLACEMENTS.each do |key, value|
|
||||||
|
name = name.gsub(key, value)
|
||||||
|
end
|
||||||
|
|
||||||
|
# If a dollar sign is used as separator between two characters, replace it with a dot
|
||||||
|
name.gsub(/([^$.])\$([^$.])/, '\1.\2')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_type
|
||||||
|
# if this entry is for a package, we group the package under the parent package
|
||||||
|
if is_package?
|
||||||
|
parent_package
|
||||||
|
# otherwise, group it under the regular package name
|
||||||
|
else
|
||||||
|
package_name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def include_default_entry?
|
||||||
|
# Ignore package pages
|
||||||
|
at_css('.cover-header .micon.pa').nil?
|
||||||
|
end
|
||||||
|
|
||||||
|
def additional_entries
|
||||||
|
entries = []
|
||||||
|
titles = []
|
||||||
|
|
||||||
|
css(".documentableElement").each do |node|
|
||||||
|
# Ignore elements without IDs
|
||||||
|
id = node['id']
|
||||||
|
next if id.nil?
|
||||||
|
|
||||||
|
# Ignore deprecated and inherited members
|
||||||
|
next unless node.at_css('.deprecated').nil?
|
||||||
|
|
||||||
|
member_name = node.at_css('.documentableName').content
|
||||||
|
title = "#{name}.#{member_name}"
|
||||||
|
|
||||||
|
# Add () to methods that take parameters, i.e. methods who have (…)
|
||||||
|
# in their signature, ignoring occurrences of (implicit …) and (using …)
|
||||||
|
signature = node.at_css('.signature').content
|
||||||
|
title += '()' if signature =~ /\((?!implicit)(?!using ).*\)/
|
||||||
|
|
||||||
|
next if titles.include?(title) # Ignore duplicates (function overloading)
|
||||||
|
|
||||||
|
entries << [title, id]
|
||||||
|
titles.push(title)
|
||||||
|
end
|
||||||
|
|
||||||
|
entries
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
# For the package name, we use the slug rather than parsing the package
|
||||||
|
# name from the HTML because companion object classes may be broken out into
|
||||||
|
# their own entries (by the source documentation). When that happens,
|
||||||
|
# we want to group these classes (like `scala.reflect.api.Annotations.Annotation`)
|
||||||
|
# under the package name, and not the fully-qualfied name which would
|
||||||
|
# include the companion object.
|
||||||
|
def package_name
|
||||||
|
name = package_drop_last(slug_parts)
|
||||||
|
name.empty? ? 'scala' : name
|
||||||
|
end
|
||||||
|
|
||||||
|
def parent_package
|
||||||
|
parent = package_drop_last(package_name.split('.'))
|
||||||
|
parent.empty? ? 'scala' : parent
|
||||||
|
end
|
||||||
|
|
||||||
|
def package_drop_last(parts)
|
||||||
|
parts[0...-1].join('.')
|
||||||
|
end
|
||||||
|
|
||||||
|
def slug_parts
|
||||||
|
slug.split('/')
|
||||||
|
end
|
||||||
|
|
||||||
|
def is_package?
|
||||||
|
!at_css('.cover-header .micon.pa').nil?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in new issue