mirror of
https://github.com/google/pebble.git
synced 2025-05-31 15:33:11 +00:00
Import the pebble dev site into devsite/
This commit is contained in:
parent
3b92768480
commit
527858cf4c
1359 changed files with 265431 additions and 0 deletions
153
devsite/lib/c_docs/doc_class.rb
Normal file
153
devsite/lib/c_docs/doc_class.rb
Normal file
|
@ -0,0 +1,153 @@
|
|||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
module Pebble
|
||||
# DocClass is a special type of DocElement for structs and unions.
|
||||
# It acts like a DocGroup in that it parses an XML file, but it acts like a
|
||||
# DocMember in that it belongs to a group etc.
|
||||
class DocClass < DocElement
|
||||
attr_reader :summary, :description, :kind, :position, :id, :name
|
||||
|
||||
def initialize(root, dir, platform, kind, id, group)
|
||||
super(root, platform)
|
||||
@dir = dir
|
||||
@group = group
|
||||
@kind = kind
|
||||
@children = []
|
||||
@xml = {}
|
||||
@code = id
|
||||
@doxygen_processor = DoxygenProcessor.new(platform)
|
||||
load_xml(platform)
|
||||
end
|
||||
|
||||
def load_xml(platform)
|
||||
@xml[platform] = Nokogiri::XML(File.read("#{@dir}/#{platform}/xml/#{@kind}_#{@code}.xml"))
|
||||
@data[platform] = {}
|
||||
@name = @xml[platform].at_css('compounddef > compoundname').content.to_s
|
||||
@id = @xml[platform].at_css('compounddef')['id']
|
||||
@path = "#{@group.path}##{@name}"
|
||||
create_members(platform)
|
||||
end
|
||||
|
||||
def to_liquid
|
||||
{
|
||||
'name' => @name,
|
||||
'summary' => @summary,
|
||||
'description' => @description,
|
||||
'url' => url,
|
||||
'children' => @children,
|
||||
'data' => @data,
|
||||
'platforms' => @xml.keys,
|
||||
'uniform' => uniform?
|
||||
}
|
||||
end
|
||||
|
||||
def process(mapping)
|
||||
@xml.each do |platform, xml|
|
||||
@data[platform]['summary'] = @doxygen_processor.process_summary(
|
||||
xml.at_css('compounddef > briefdescription'), mapping
|
||||
)
|
||||
description = xml.at_css('compounddef > detaileddescription')
|
||||
process_simplesects(description, mapping, platform)
|
||||
@data[platform]['description'] = @doxygen_processor.process_description(
|
||||
description, mapping)
|
||||
process_members(mapping, platform)
|
||||
end
|
||||
@children = @children.reject { |child| child.name.match(/^@/) }
|
||||
@children.sort! { |m, n| m.position <=> n.position }
|
||||
end
|
||||
|
||||
def uniform?
|
||||
identical = @data['aplite'].to_json == @data['basalt'].to_json
|
||||
identical &&= @children.all?(&:uniform?)
|
||||
identical
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def create_members(platform)
|
||||
@xml[platform].css('memberdef').each do |child|
|
||||
variable = DocClassVariable.new(@root, child, @group, platform)
|
||||
existing = @children.select { |ex| ex.name == variable.name }.first
|
||||
if existing.nil?
|
||||
@children << variable
|
||||
else
|
||||
existing.add_platform(platform, child)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def process_members(mapping, platform)
|
||||
@children.each { |child| child.process(mapping, platform) }
|
||||
end
|
||||
end
|
||||
|
||||
# DocClassVariable is a DocElement subclass that handles the members (or
|
||||
# variables) of a struct or union.
|
||||
class DocClassVariable < DocElement
|
||||
attr_reader :name, :position
|
||||
|
||||
def initialize(root, node, group, platform)
|
||||
super(root, platform)
|
||||
@name = node.at_css('name').content.to_s
|
||||
@group = group
|
||||
@nodes = { platform => node }
|
||||
@platforms = [platform]
|
||||
@path = "#{@group.path}##{@name}"
|
||||
@position = node.at_css(' > location')['line'].to_i
|
||||
end
|
||||
|
||||
def add_platform(platform, node)
|
||||
@nodes[platform] = node
|
||||
@platforms << platform
|
||||
@data[platform] = {}
|
||||
end
|
||||
|
||||
def to_liquid
|
||||
{
|
||||
'name' => @name,
|
||||
'data' => @data,
|
||||
'url' => url,
|
||||
'type' => @type,
|
||||
'platforms' => @platforms
|
||||
}
|
||||
end
|
||||
|
||||
def uniform?
|
||||
@data['aplite'].to_json == @data['basalt'].to_json
|
||||
end
|
||||
|
||||
def process(mapping, platform)
|
||||
return unless @platforms.include? platform
|
||||
@data[platform]['summary'] = @doxygen_processor.process_summary(
|
||||
@nodes[platform].at_css('briefdescription'), mapping
|
||||
)
|
||||
description = @nodes[platform].at_css('detaileddescription')
|
||||
process_simplesects(description, mapping, platform)
|
||||
process_type(mapping, platform)
|
||||
@data[platform]['description'] = @doxygen_processor.process_description(
|
||||
description, mapping)
|
||||
end
|
||||
|
||||
def process_type(mapping, platform)
|
||||
if @nodes[platform].at_css('type > ref').nil?
|
||||
@data[platform]['type'] = @nodes[platform].at_css('type').content.to_s
|
||||
else
|
||||
type_node = @nodes[platform].at_css('type').clone()
|
||||
@doxygen_processor.process_node_ref(type_node.at_css('ref'), mapping)
|
||||
@data[platform]['type'] = type_node.to_html.to_s
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
98
devsite/lib/c_docs/doc_element.rb
Normal file
98
devsite/lib/c_docs/doc_element.rb
Normal file
|
@ -0,0 +1,98 @@
|
|||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
module Pebble
|
||||
# DocElement is an abstract C Documentation class that is subclasses for
|
||||
# each of the various items that build up a documentation page, symbol or
|
||||
# tree item.
|
||||
class DocElement
|
||||
KNOWN_SECT_TYPES = %w(return note)
|
||||
attr_reader :url
|
||||
|
||||
def initialize(root, platform)
|
||||
@root = root
|
||||
@data = {}
|
||||
@data[platform] = {}
|
||||
@doxygen_processor = DoxygenProcessor.new(platform)
|
||||
end
|
||||
|
||||
def to_symbol
|
||||
{
|
||||
name: @name,
|
||||
url: url,
|
||||
summary: default_data('summary')
|
||||
}
|
||||
end
|
||||
|
||||
def to_mapping
|
||||
{
|
||||
id: @id,
|
||||
url: url
|
||||
}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def default_data(key)
|
||||
return @data['basalt'][key] unless @data['basalt'].nil? || @data['basalt'][key].nil?
|
||||
return @data['aplite'][key] unless @data['aplite'].nil? || @data['aplite'][key].nil?
|
||||
''
|
||||
end
|
||||
|
||||
def url
|
||||
"#{@root}#{@path}"
|
||||
end
|
||||
|
||||
def add_data(type, value, platform)
|
||||
@data[platform] = {} if @data[platform].nil?
|
||||
@data[platform][type] = [] if @data[platform][type].nil?
|
||||
@data[platform][type] << value
|
||||
end
|
||||
|
||||
def process_simplesects(node, mapping, platform)
|
||||
if node.name.to_s == 'detaileddescription'
|
||||
desc = node
|
||||
else
|
||||
desc = node.at_css('detaileddescription')
|
||||
end
|
||||
return if desc.nil?
|
||||
desc.css('simplesect').each do |sect|
|
||||
if KNOWN_SECT_TYPES.include?(sect['kind'])
|
||||
process_simplesect_basic(sect, mapping, platform)
|
||||
elsif sect['kind'] == 'see'
|
||||
process_simplesect_see(sect, mapping, platform)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def process_simplesect_basic(sect, mapping, platform)
|
||||
value = @doxygen_processor.process_summary(sect.clone, mapping)
|
||||
add_data(sect['kind'], value, platform)
|
||||
sect.remove
|
||||
end
|
||||
|
||||
def process_simplesect_see(sect, mapping, platform)
|
||||
if sect.at_css('para > ref').nil?
|
||||
add_data(sect['kind'],
|
||||
@doxygen_processor.process_paragraph(sect.at_css('para'),
|
||||
mapping), platform)
|
||||
else
|
||||
see_node = sect.at_css('para > ref').clone
|
||||
@doxygen_processor.process_node_ref(see_node, mapping)
|
||||
add_data(sect['kind'], see_node.to_html.to_s, platform)
|
||||
end
|
||||
sect.remove
|
||||
end
|
||||
end
|
||||
end
|
58
devsite/lib/c_docs/doc_enum_value.rb
Normal file
58
devsite/lib/c_docs/doc_enum_value.rb
Normal file
|
@ -0,0 +1,58 @@
|
|||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
module Pebble
|
||||
# DocEnumValue is a DocElement that is one of the possible values of an enum.
|
||||
class DocEnumValue < DocElement
|
||||
attr_reader :position, :summary, :id, :platforms, :name, :data
|
||||
|
||||
def initialize(root, node, group, platform)
|
||||
super(root, platform)
|
||||
@name = node.at_css('name').content.to_s
|
||||
@id = node['id']
|
||||
@group = group
|
||||
@path = "#{@group.path}##{@name}"
|
||||
@nodes = { platform => node }
|
||||
@platforms = [platform]
|
||||
@doxygen_processor = DoxygenProcessor.new(platform)
|
||||
end
|
||||
|
||||
def add_platform(node, platform)
|
||||
@nodes[platform] = node
|
||||
@platforms << platform
|
||||
@data[platform] = {}
|
||||
end
|
||||
|
||||
def process(mapping, platform)
|
||||
return unless @platforms.include? platform
|
||||
process_simplesects(@nodes[platform], mapping, platform)
|
||||
@data[platform]['summary'] = @doxygen_processor.process_summary(
|
||||
@nodes[platform].at_css('briefdescription'), mapping
|
||||
)
|
||||
end
|
||||
|
||||
def uniform?
|
||||
data['aplite'].to_json == data['basalt'].to_json
|
||||
end
|
||||
|
||||
def to_liquid
|
||||
{
|
||||
'name' => @name,
|
||||
'data' => @data,
|
||||
'url' => url,
|
||||
'platforms' => @platforms
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
178
devsite/lib/c_docs/doc_group.rb
Normal file
178
devsite/lib/c_docs/doc_group.rb
Normal file
|
@ -0,0 +1,178 @@
|
|||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
require_relative 'doc_element.rb'
|
||||
require_relative 'doc_member.rb'
|
||||
require_relative 'doc_class.rb'
|
||||
require_relative 'doxygen_processor.rb'
|
||||
|
||||
module Pebble
|
||||
# A DocGroup is a a collection of members, structs and subgroups that will
|
||||
# become a page in the C documentation.
|
||||
class DocGroup < DocElement
|
||||
attr_accessor :groups, :members, :name, :path, :menu_path, :classes, :id
|
||||
|
||||
def initialize(root, dir, platform, id, menu_path = [])
|
||||
super(root, platform)
|
||||
@dir = dir
|
||||
@menu_path = Array.new(menu_path)
|
||||
@xml = {}
|
||||
@groups = []
|
||||
@members = []
|
||||
@classes = []
|
||||
@group_id = id
|
||||
@doxygen_processor = DoxygenProcessor.new(platform)
|
||||
@root = root
|
||||
load_xml(platform)
|
||||
end
|
||||
|
||||
def load_xml(platform)
|
||||
@xml[platform] = Nokogiri::XML(File.read("#{@dir}/#{platform}/xml/group___#{@group_id}.xml"))
|
||||
@id = @xml[platform].at_css('compounddef')['id']
|
||||
@name = @xml[platform].at_css('compounddef > title').content.to_s
|
||||
@menu_path << @name if @path.nil?
|
||||
@path = @menu_path.join('/').gsub(' ', '_') + '/'
|
||||
create_descendents(platform)
|
||||
end
|
||||
|
||||
def process(mapping, platform)
|
||||
return if @xml[platform].nil?
|
||||
@data[platform] = {} if @data[platform].nil?
|
||||
@data[platform]['summary'] = @doxygen_processor.process_summary(
|
||||
@xml[platform].at_css('compounddef > briefdescription'), mapping)
|
||||
description = @xml[platform].at_css('compounddef > detaileddescription')
|
||||
process_simplesects(description, mapping, platform)
|
||||
@data[platform]['description'] = @doxygen_processor.process_description(
|
||||
description, mapping)
|
||||
process_descendents(mapping, platform)
|
||||
end
|
||||
|
||||
def to_page(site)
|
||||
PageDocC.new(site, @root, site.source, "#{@path}index.html", self)
|
||||
end
|
||||
|
||||
def to_branch
|
||||
{
|
||||
'name' => @name,
|
||||
'url' => url,
|
||||
'children' => @groups.map(&:to_branch),
|
||||
'summary' => default_data('summary')
|
||||
}
|
||||
end
|
||||
|
||||
def mapping_array
|
||||
mapping = [to_mapping]
|
||||
@groups.each { |group| mapping += group.mapping_array }
|
||||
@members.each { |member| mapping << member.to_mapping }
|
||||
@classes.each { |cls| mapping << cls.to_mapping }
|
||||
mapping
|
||||
end
|
||||
|
||||
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
||||
def to_liquid
|
||||
{
|
||||
'name' => @name,
|
||||
'url' => url,
|
||||
'path' => @menu_path,
|
||||
'groups' => @groups,
|
||||
'members' => @members,
|
||||
'functions' => @members.select { |member| member.kind == 'function' },
|
||||
'enums' => @members.select { |member| member.kind == 'enum' },
|
||||
'defines' => @members.select { |member| member.kind == 'define' },
|
||||
'typedefs' => @members.select { |member| member.kind == 'typedef' },
|
||||
'structs' => @classes.select { |member| member.kind == 'struct' },
|
||||
'unions' => @classes.select { |member| member.kind == 'union' },
|
||||
'data' => @data,
|
||||
'basalt_only' => !@xml.key?('aplite'),
|
||||
'summary' => default_data('summary'),
|
||||
'description' => default_data('description')
|
||||
}
|
||||
end
|
||||
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
||||
|
||||
private
|
||||
|
||||
def create_descendents(platform)
|
||||
create_inner_groups(platform)
|
||||
create_members(platform)
|
||||
create_inner_classes(platform)
|
||||
@members.sort! { |m, n| m.position <=> n.position }
|
||||
end
|
||||
|
||||
def create_inner_groups(platform)
|
||||
@xml[platform].css('innergroup').each do |child|
|
||||
id = child['refid'].sub(/^group___/, '')
|
||||
new_group = DocGroup.new(@root, @dir, platform, id, @menu_path)
|
||||
group = @groups.select { |grp| new_group.name == grp.name }.first
|
||||
if group.nil?
|
||||
@groups << new_group
|
||||
else
|
||||
group.load_xml(platform)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def create_members(platform)
|
||||
@xml[platform].css('memberdef').map do |child|
|
||||
new_member = DocMember.new(@root, child, self, platform)
|
||||
member = @members.select { |mem| mem.name == new_member.name }.first
|
||||
if member.nil?
|
||||
@members << new_member
|
||||
else
|
||||
member.add_platform(platform, child)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def create_inner_classes(platform)
|
||||
@xml[platform].css('innerclass').map do |child|
|
||||
next if child.content.to_s.match(/__unnamed__/)
|
||||
next if child.content.to_s.match(/\./)
|
||||
if child['refid'].match(/^struct_/)
|
||||
create_struct(child, platform)
|
||||
elsif child['refid'].match(/^union_/)
|
||||
create_union(child, platform)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def create_struct(node, platform)
|
||||
id = node['refid'].sub(/^struct_/, '')
|
||||
new_struct = DocClass.new(@root, @dir, platform, 'struct', id, self)
|
||||
struct = @classes.select { |str| new_struct.name == str.name }.first
|
||||
if struct.nil?
|
||||
@classes << new_struct
|
||||
else
|
||||
struct.load_xml(platform)
|
||||
end
|
||||
end
|
||||
|
||||
def create_union(node, platform)
|
||||
id = node['refid'].sub(/^union_/, '')
|
||||
new_union = DocClass.new(@root, @dir, platform, 'union', id, self)
|
||||
union = @classes.select { |un| un.name == new_union.name }.first
|
||||
if union.nil?
|
||||
@classes << new_union
|
||||
else
|
||||
union.load_xml(platform)
|
||||
end
|
||||
end
|
||||
|
||||
def process_descendents(mapping, platform)
|
||||
@groups.each { |group| group.process(mapping, platform) }
|
||||
@members.each { |member| member.process(mapping, platform) }
|
||||
@classes.each { |member| member.process(mapping) }
|
||||
end
|
||||
end
|
||||
end
|
165
devsite/lib/c_docs/doc_member.rb
Normal file
165
devsite/lib/c_docs/doc_member.rb
Normal file
|
@ -0,0 +1,165 @@
|
|||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
require_relative 'doc_enum_value.rb'
|
||||
|
||||
module Pebble
|
||||
# A DocMember is a function, enum, typedef that will become a symbol
|
||||
# and be a part of a documentation page. Belongs to a DocGroup.
|
||||
class DocMember < DocElement
|
||||
attr_accessor :children, :kind, :name, :summary, :children, :position, :data, :id
|
||||
|
||||
def initialize(root, node, group, platform)
|
||||
super(root, platform)
|
||||
@group = group
|
||||
@children = []
|
||||
@platforms = [platform]
|
||||
@nodes = { platform => node }
|
||||
@name = node.at_css('name').content.to_s
|
||||
@kind = node['kind']
|
||||
@id = node['id']
|
||||
@path = "#{@group.path}##{@name}"
|
||||
@position = node.at_css(' > location')['line'].to_i
|
||||
@doxygen_processor = DoxygenProcessor.new(platform)
|
||||
create_enum_values(node, platform) if @kind == 'enum'
|
||||
end
|
||||
|
||||
def add_platform(platform, node)
|
||||
@platforms << platform
|
||||
@nodes[platform] = node
|
||||
@data[platform] = {}
|
||||
create_enum_values(node, platform) if @kind == 'enum'
|
||||
end
|
||||
|
||||
def to_liquid
|
||||
{
|
||||
'name' => @name,
|
||||
'url' => url,
|
||||
'children' => @children,
|
||||
'position' => @position,
|
||||
'data' => @data,
|
||||
'uniform' => uniform?,
|
||||
'platforms' => @platforms
|
||||
}
|
||||
end
|
||||
|
||||
def process(mapping, platform)
|
||||
return unless @platforms.include? platform
|
||||
@data[platform]['summary'] = @doxygen_processor.process_summary(
|
||||
@nodes[platform].at_css(' > briefdescription'), mapping
|
||||
)
|
||||
process_data(@nodes[platform], mapping, platform)
|
||||
@data[platform]['description'] = @doxygen_processor.process_description(
|
||||
@nodes[platform].at_css(' > detaileddescription'), mapping
|
||||
)
|
||||
@children.each { |child| child.process(mapping, platform) }
|
||||
end
|
||||
|
||||
def uniform?
|
||||
identical = data['aplite'].to_json == data['basalt'].to_json
|
||||
identical &&= children.all?(&:uniform?) if @kind == 'enum'
|
||||
identical
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def create_enum_values(node, platform)
|
||||
node.css('enumvalue').each do |value|
|
||||
enum_value = DocEnumValue.new(@root, value, @group, platform)
|
||||
existing_value = @children.select { |ev| ev.name == enum_value.name }.first
|
||||
if existing_value.nil?
|
||||
@children << enum_value
|
||||
else
|
||||
existing_value.add_platform(value, platform)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def process_data(node, mapping, platform)
|
||||
process_typedef(node, mapping, platform) if @kind == 'typedef'
|
||||
process_function(node, mapping, platform) if @kind == 'function'
|
||||
process_define(node, mapping, platform) if @kind == 'define'
|
||||
process_simplesects(node, mapping, platform)
|
||||
end
|
||||
|
||||
def process_typedef(node, mapping, platform)
|
||||
process_return_type(node, mapping, platform)
|
||||
@data[platform]['argsstring'] = node.at_css('argsstring').content.to_s
|
||||
process_parameter_list(node, mapping, platform)
|
||||
end
|
||||
|
||||
def process_function(node, mapping, platform)
|
||||
process_return_type(node, mapping, platform)
|
||||
process_params(node, mapping, platform) unless node.css('param').nil?
|
||||
process_parameter_list(node, mapping, platform)
|
||||
end
|
||||
|
||||
def process_define(node, mapping, platform)
|
||||
unless node.at_css('initializer').nil?
|
||||
@data[platform]['initializer'] = process_to_html(
|
||||
node.at_css('initializer'), mapping
|
||||
)
|
||||
end
|
||||
process_return_type(node, mapping, platform)
|
||||
process_parameter_list(node, mapping, platform)
|
||||
process_params(node, mapping, platform) unless node.css('param').nil?
|
||||
end
|
||||
|
||||
def process_return_type(node, mapping, platform)
|
||||
@data[platform]['type'] = process_to_html(node.at_css('> type'), mapping)
|
||||
end
|
||||
|
||||
def process_params(node, mapping, platform)
|
||||
@data[platform]['params'] = node.css('param').map do |elem|
|
||||
params = {}
|
||||
unless elem.at_css('declname').nil?
|
||||
params['name'] = elem.at_css('declname').content.to_s
|
||||
end
|
||||
unless elem.at_css('type').nil?
|
||||
params['type'] = process_to_html(elem.at_css('type'), mapping)
|
||||
end
|
||||
unless elem.at_css('defname').nil?
|
||||
params['name'] = elem.at_css('defname').content.to_s
|
||||
end
|
||||
params
|
||||
end
|
||||
end
|
||||
|
||||
def process_to_html(node, mapping)
|
||||
return '' if node.nil?
|
||||
node.css('ref').each do |ref|
|
||||
@doxygen_processor.process_node_ref(ref, mapping)
|
||||
end
|
||||
node.inner_html.to_s
|
||||
end
|
||||
|
||||
def process_parameter_list(node, mapping, platform)
|
||||
return if node.at_css('parameterlist').nil?
|
||||
parameter_list = node.at_css('parameterlist').clone
|
||||
node.at_css('parameterlist').remove
|
||||
@data[platform]['parameters'] = parameter_list.css('parameteritem').map do |item|
|
||||
{
|
||||
'name' => get_parameter_name(item),
|
||||
'summary' => @doxygen_processor.process_summary(item.at_css('parameterdescription'), mapping)
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def get_parameter_name(item)
|
||||
name = item.at_css('parameternamelist > parametername')
|
||||
direction = name.attr('direction').to_s
|
||||
direction.nil? || direction == '' ? name.content.to_s : "#{name.content.to_s} (#{direction})"
|
||||
end
|
||||
end
|
||||
end
|
154
devsite/lib/c_docs/doxygen_processor.rb
Normal file
154
devsite/lib/c_docs/doxygen_processor.rb
Normal file
|
@ -0,0 +1,154 @@
|
|||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
module Pebble
|
||||
# Class of methods for processing Doxygen XML into 'sane' HTML.
|
||||
# rubocop:disable Metrics/ClassLength
|
||||
class DoxygenProcessor
|
||||
def initialize(platform)
|
||||
@platform = platform
|
||||
end
|
||||
|
||||
def process_summary(node, mapping)
|
||||
process_description(node, mapping)
|
||||
end
|
||||
|
||||
def process_description(node, mapping)
|
||||
return '' if node.nil?
|
||||
node.children.map { |para| process_paragraph(para, mapping) }.join("\n").strip
|
||||
end
|
||||
|
||||
# rubocop:disable Metrics/MethodLength, Methods/CyclomaticComplexity
|
||||
# rubocop:disable Methods/AbcSize
|
||||
def process_paragraph(node, mapping)
|
||||
return '' if node.nil?
|
||||
node.name = 'p'
|
||||
node.children.each do |child|
|
||||
case child.name
|
||||
when 'ref'
|
||||
process_node_ref(child, mapping)
|
||||
when 'programlisting'
|
||||
process_code(child)
|
||||
when 'simplesect'
|
||||
# puts node.content.to_s
|
||||
# process_blockquote(child)
|
||||
when 'heading'
|
||||
process_node_heading(child)
|
||||
when 'htmlonly'
|
||||
process_node_htmlonly(child)
|
||||
when 'itemizedlist'
|
||||
process_list(child, mapping)
|
||||
when 'image'
|
||||
process_image(child)
|
||||
when 'computeroutput'
|
||||
process_computer_output(child)
|
||||
when 'emphasis'
|
||||
child.name = 'em'
|
||||
when 'bold'
|
||||
child.name = 'strong'
|
||||
when 'linebreak'
|
||||
child.name = 'br'
|
||||
when 'preformatted'
|
||||
child.name = 'pre'
|
||||
when 'ndash'
|
||||
child.name = 'span'
|
||||
child.content = '-'
|
||||
when 'ulink'
|
||||
child.name = 'a'
|
||||
child['href'] = child['url'].sub(%r{^https?://developer.pebble.com/}, '/')
|
||||
child.remove_attribute('url')
|
||||
when 'text'
|
||||
# SKIP!
|
||||
else
|
||||
# puts child.name, node.content.to_s
|
||||
end
|
||||
end
|
||||
node.to_html.to_s.strip
|
||||
end
|
||||
# rubocop:enable Metrics/MethodLength, Methods/CyclomaticComplexity
|
||||
# rubocop:enable Methods/AbcSize
|
||||
|
||||
def process_code(node)
|
||||
xml = node.to_xml.gsub('<sp/>', ' ')
|
||||
doc = Nokogiri::XML(xml)
|
||||
highlight = Pygments.highlight(doc.content.to_s.strip, lexer: 'c')
|
||||
node.content = ''
|
||||
node << Nokogiri::XML(highlight).at_css('pre')
|
||||
node.name = 'div'
|
||||
node['class'] = 'highlight'
|
||||
end
|
||||
|
||||
def process_node_ref(child, mapping)
|
||||
child.name = 'a'
|
||||
map = mapping.select { |m| m[:id] == child['refid'] }.first
|
||||
child['href'] = map[:url] unless map.nil?
|
||||
end
|
||||
|
||||
def process_node_heading(node)
|
||||
node.name = 'h' + node['level']
|
||||
end
|
||||
|
||||
def process_node_htmlonly(node)
|
||||
decoder = HTMLEntities.new
|
||||
xml = Nokogiri::XML('<root>' + decoder.decode(node.content) + '</root>')
|
||||
node_count = xml.root.children.size
|
||||
process_node_htmlonly_simple(node, xml) if node_count == 2
|
||||
process_node_htmlonly_complex(node, xml) if node_count > 2
|
||||
end
|
||||
|
||||
def process_node_htmlonly_simple(node, xml)
|
||||
child = xml.at_css('root').children[0]
|
||||
node.name = child.name
|
||||
child.attributes.each { |key, value| node[key] = value }
|
||||
node.content = child.content
|
||||
end
|
||||
|
||||
def process_node_htmlonly_complex(node, xml)
|
||||
node.name = 'div'
|
||||
node.content = ''
|
||||
node << xml.root.children
|
||||
end
|
||||
|
||||
def process_blockquote(node)
|
||||
node.name = 'blockquote'
|
||||
node['class'] = 'blockquote--' + node['kind']
|
||||
process_paragraph(node.children[0]) if node.children[0].name == 'para'
|
||||
node.to_html.to_s
|
||||
end
|
||||
|
||||
def process_list(node, mapping)
|
||||
node.name = 'ul'
|
||||
node.children.each do |child|
|
||||
process_list_item(child, mapping)
|
||||
end
|
||||
end
|
||||
|
||||
def process_list_item(node, mapping)
|
||||
node.name = 'li'
|
||||
node.children.each do |child|
|
||||
process_paragraph(child, mapping) if child.name == 'para'
|
||||
end
|
||||
end
|
||||
|
||||
def process_image(node)
|
||||
node.name = 'img'
|
||||
node['src'] = "/assets/images/docs/c/#{@platform}/#{node['name']}"
|
||||
end
|
||||
|
||||
def process_computer_output(node)
|
||||
node.name = 'code'
|
||||
end
|
||||
end
|
||||
# rubocop:enable Metrics/ClassLength
|
||||
end
|
49
devsite/lib/pebble_documentation.rb
Normal file
49
devsite/lib/pebble_documentation.rb
Normal file
|
@ -0,0 +1,49 @@
|
|||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
module Pebble
|
||||
class Documentation
|
||||
LANGUAGE = ''
|
||||
def initialize(site)
|
||||
@site = site
|
||||
@symbols = []
|
||||
@pages = []
|
||||
@tree = []
|
||||
end
|
||||
|
||||
def load_symbols(symbols)
|
||||
symbols.concat(@symbols)
|
||||
end
|
||||
|
||||
def create_pages(pages)
|
||||
pages.concat(@pages)
|
||||
end
|
||||
|
||||
def build_tree(tree)
|
||||
tree.concat(@tree)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def add_symbol(symbol)
|
||||
symbol[:language] = language
|
||||
symbol[:summary] = symbol[:summary].strip unless symbol[:summary].nil?
|
||||
@symbols << symbol
|
||||
end
|
||||
|
||||
def language
|
||||
LANGUAGE
|
||||
end
|
||||
end
|
||||
end
|
189
devsite/lib/pebble_documentation_c.rb
Normal file
189
devsite/lib/pebble_documentation_c.rb
Normal file
|
@ -0,0 +1,189 @@
|
|||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
require 'pygments'
|
||||
require 'zip'
|
||||
require 'nokogiri'
|
||||
require 'htmlentities'
|
||||
require_relative 'c_docs/doc_group.rb'
|
||||
|
||||
module Pebble
|
||||
# Pebble C documentation processing class.
|
||||
class DocumentationC < Documentation
|
||||
MASTER_GROUP_IDS = %w(foundation graphics u_i smartstrap worker standard_c)
|
||||
|
||||
def initialize(site, source, root, language='c')
|
||||
super(site)
|
||||
@site = site
|
||||
@url_root = root
|
||||
@source = source
|
||||
@tmp_dir = 'tmp/docs/c'
|
||||
@groups = []
|
||||
@language = language
|
||||
run
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def language
|
||||
@language
|
||||
end
|
||||
|
||||
def run
|
||||
cleanup
|
||||
download_and_extract(@source, @tmp_dir)
|
||||
hack_smartstraps
|
||||
process
|
||||
add_images
|
||||
end
|
||||
|
||||
def cleanup
|
||||
FileUtils.rmtree @tmp_dir
|
||||
end
|
||||
|
||||
def download_and_extract(zip, folder)
|
||||
open(zip) do | zf |
|
||||
Zip::File.open(zf.path) do | zipfile |
|
||||
zipfile.each do | entry |
|
||||
path = File.join(folder, entry.name).sub('/doxygen_sdk/', '/')
|
||||
FileUtils.mkdir_p(File.dirname(path))
|
||||
zipfile.extract(entry, path) unless File.exist?(path)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# This is a hack to get around a limitation with the documentation generator.
|
||||
# At present, it cannot handle the situation where a top level doc group exists on
|
||||
# Basalt but not Aplite.
|
||||
# Smartstraps is the only group that fits this pattern at the moment.
|
||||
# This hack copies the XML doc from the Basalt folder to the Aplite folder and removes
|
||||
# all of its contents.
|
||||
def hack_smartstraps
|
||||
basalt_xml = Nokogiri::XML(File.read("#{@tmp_dir}/basalt/xml/group___smartstrap.xml"))
|
||||
basalt_xml.search('.//memberdef').remove
|
||||
basalt_xml.search('.//innerclass').remove
|
||||
basalt_xml.search('.//sectiondef').remove
|
||||
File.open("#{@tmp_dir}/aplite/xml/group___smartstrap.xml", 'w') do |file|
|
||||
file.write(basalt_xml.to_xml)
|
||||
end
|
||||
end
|
||||
|
||||
def process
|
||||
DocumentationC::MASTER_GROUP_IDS.each do |id|
|
||||
@groups << DocGroup.new(@url_root, @tmp_dir, 'aplite', id)
|
||||
end
|
||||
@groups.each { |group| group.load_xml('basalt') }
|
||||
|
||||
mapping = []
|
||||
@groups.each { |group| mapping += group.mapping_array }
|
||||
@groups.each do |group|
|
||||
group.process(mapping, 'aplite')
|
||||
group.process(mapping, 'basalt')
|
||||
end
|
||||
|
||||
add_symbols(@groups)
|
||||
@groups.each { |group| @tree << group.to_branch }
|
||||
add_pages(@groups)
|
||||
add_redirects(mapping)
|
||||
end
|
||||
|
||||
def add_images
|
||||
move_images('aplite')
|
||||
move_images('basalt')
|
||||
images = Dir.glob("#{@tmp_dir}/assets/images/**/*.png")
|
||||
images.each do |img|
|
||||
source = File.join(@site.source, '../tmp/docs/c/')
|
||||
if File.exists?(img)
|
||||
img.sub!('tmp/docs/c', '')
|
||||
@site.static_files << Jekyll::StaticFile.new(@site, source, '', img)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def move_images(platform)
|
||||
images = Dir.glob("#{@tmp_dir}/#{platform}/**/*.png")
|
||||
dir = File.join(@tmp_dir, 'assets', 'images', 'docs', 'c', platform)
|
||||
FileUtils.mkdir_p(dir)
|
||||
images.each do |img|
|
||||
FileUtils.cp(img, File.join(dir, File.basename(img)))
|
||||
end
|
||||
end
|
||||
|
||||
# TODO: Make the groups handle their own subgroups and members etc
|
||||
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
||||
def add_symbols(groups)
|
||||
groups.each do |group|
|
||||
add_symbol(group.to_symbol)
|
||||
group.members.each do |member|
|
||||
add_symbol(member.to_symbol)
|
||||
member.children.each do |child|
|
||||
add_symbol(child.to_symbol)
|
||||
end
|
||||
end
|
||||
group.classes.each do |child|
|
||||
add_symbol(child.to_symbol)
|
||||
# OPINION: I don't think we want to have struct members as symbols.
|
||||
# struct.children.each do |child|
|
||||
# add_symbol(child.to_symbol)
|
||||
# end
|
||||
end
|
||||
add_symbols(group.groups)
|
||||
end
|
||||
end
|
||||
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
||||
|
||||
def add_pages(groups)
|
||||
groups.each do |group|
|
||||
page = group.to_page(@site)
|
||||
page.set_language(@language)
|
||||
@pages << page
|
||||
add_pages(group.groups)
|
||||
end
|
||||
end
|
||||
|
||||
def add_redirects(mapping)
|
||||
mapping.each do |map|
|
||||
next if map[:id].match(/_1/)
|
||||
@site.pages << Jekyll::RedirectPage.new(@site, @site.source, @url_root, map[:id] + '.html', map[:url])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Jekyll Page subclass for rendering the C documentation pages.
|
||||
class PageDocC < Jekyll::Page
|
||||
attr_reader :group
|
||||
|
||||
def initialize(site, root, base, dir, group)
|
||||
@site = site
|
||||
@base = base
|
||||
@dir = root
|
||||
@name = dir
|
||||
@group = group
|
||||
process(@name)
|
||||
read_yaml(File.join(base, '_layouts', 'docs'), 'c.html')
|
||||
data['title'] = @group.name
|
||||
data['platforms'] = %w(aplite basalt)
|
||||
|
||||
end
|
||||
|
||||
def set_language(language)
|
||||
data['docs_language'] = language
|
||||
end
|
||||
|
||||
def to_liquid(attrs = ATTRIBUTES_FOR_LIQUID)
|
||||
super(attrs + %w(group))
|
||||
end
|
||||
end
|
||||
end
|
120
devsite/lib/pebble_documentation_js.rb
Normal file
120
devsite/lib/pebble_documentation_js.rb
Normal file
|
@ -0,0 +1,120 @@
|
|||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
require 'zip'
|
||||
|
||||
module Pebble
|
||||
# Rock.js documentation processing class.
|
||||
class DocumentationJs < Documentation
|
||||
|
||||
def initialize(site, source, root, language, preview = false)
|
||||
super(site)
|
||||
@url_root = root
|
||||
@language = language
|
||||
@preview = preview
|
||||
json = site.data[source]
|
||||
json.each { |js_module| process_module(js_module) }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def process_module(js_module)
|
||||
js_module[:path] = js_module['name']
|
||||
js_module[:url] = module_url(js_module)
|
||||
js_module[:processed_functions] = []
|
||||
js_module[:processed_members] = []
|
||||
js_module[:processed_typedefs] = []
|
||||
js_module[:children] = []
|
||||
|
||||
process_members(js_module)
|
||||
add_to_tree(js_module)
|
||||
|
||||
# Create and add the page
|
||||
page = PageDocJS.new(@site, module_url(js_module), js_module)
|
||||
page.set_data(@language, @preview)
|
||||
@pages << page
|
||||
end
|
||||
|
||||
def process_members(js_module)
|
||||
js_module['members'].each do |type, members|
|
||||
members.each do |member|
|
||||
|
||||
kind = member.key?('kind') ? member['kind'] : 'member'
|
||||
processed_type = 'processed_' + kind + 's'
|
||||
url = child_url(js_module, member)
|
||||
|
||||
symbol = {
|
||||
:name => member['name'],
|
||||
:description => member['description'],
|
||||
:type => member['type'],
|
||||
:returns => member['returns'],
|
||||
:params => member['params'],
|
||||
:properties => member['properties'],
|
||||
:url => url,
|
||||
:kind => kind,
|
||||
:summary => member['summary']
|
||||
}
|
||||
add_symbol(symbol)
|
||||
js_module[:children].push(symbol)
|
||||
js_module[processed_type.to_sym].push(symbol)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def add_to_tree(js_module)
|
||||
@tree << js_module
|
||||
end
|
||||
|
||||
def module_url(js_module)
|
||||
"#{@url_root}#{js_module['name']}/"
|
||||
end
|
||||
|
||||
def child_url(js_module, child)
|
||||
"#{module_url(js_module)}##{child['name']}"
|
||||
end
|
||||
|
||||
def child_path(js_module, child)
|
||||
[js_module['name'], child['name']].join('.')
|
||||
end
|
||||
|
||||
def language
|
||||
@language
|
||||
end
|
||||
end
|
||||
|
||||
# Jekyll Page subclass for rendering the JS documentation pages.
|
||||
class PageDocJS < Jekyll::Page
|
||||
attr_reader :js_module
|
||||
|
||||
def initialize(site, url, js_module)
|
||||
@site = site
|
||||
@base = site.source
|
||||
@dir = url
|
||||
@name = 'index.html'
|
||||
@js_module = JSON.parse(js_module.to_json)
|
||||
process(@name)
|
||||
read_yaml(File.join(@base, '_layouts', 'docs'), 'js.html')
|
||||
data['title'] = js_module['name']
|
||||
end
|
||||
|
||||
def set_data(language, preview)
|
||||
data['docs_language'] = language
|
||||
data['preview'] = preview
|
||||
end
|
||||
|
||||
def to_liquid(attrs = ATTRIBUTES_FOR_LIQUID)
|
||||
super(attrs + %w(js_module))
|
||||
end
|
||||
end
|
||||
end
|
203
devsite/lib/pebble_documentation_pebblekit_android.rb
Normal file
203
devsite/lib/pebble_documentation_pebblekit_android.rb
Normal file
|
@ -0,0 +1,203 @@
|
|||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
require 'zip'
|
||||
require 'nokogiri'
|
||||
require_relative 'pebble_documentation'
|
||||
|
||||
# TODO: Error handling.
|
||||
# TODO: Introduce some DRY
|
||||
# TODO: Fix the internal links!
|
||||
# TODO: Bring back the summarys which I broke.
|
||||
# TODO: Android Index Page
|
||||
|
||||
module Pebble
|
||||
class DocumentationPebbleKitAndroid < Documentation
|
||||
def initialize(site, source)
|
||||
super(site)
|
||||
@path = '/docs/pebblekit-android/'
|
||||
open(source) do | zf |
|
||||
Zip::File.open(zf.path) do | zipfile |
|
||||
entry = zipfile.glob('javadoc/overview-summary.html').first
|
||||
summary = Nokogiri::HTML(entry.get_input_stream.read)
|
||||
process_summary(zipfile, summary)
|
||||
|
||||
@pages << PageDocPebbleKitAndroid.new(@site, @site.source, 'docs/pebblekit-android/com/constant-values/', 'Constant Values', process_html(Nokogiri::HTML(zipfile.glob('javadoc/constant-values.html').first.get_input_stream.read).at_css('.constantValuesContainer').to_html, '/docs/pebblekit-android/'), nil)
|
||||
@pages << PageDocPebbleKitAndroid.new(@site, @site.source, 'docs/pebblekit-android/com/serialized-form/', 'Serialized Form', process_html(Nokogiri::HTML(zipfile.glob('javadoc/serialized-form.html').first.get_input_stream.read).at_css('.serializedFormContainer').to_html, '/docs/pebblekit-android/'), nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def language
|
||||
'pebblekit_android'
|
||||
end
|
||||
|
||||
def process_summary(zipfile, summary)
|
||||
summary.css('tbody tr').each do | row |
|
||||
name = row.at_css('td.colFirst').content
|
||||
package = {
|
||||
name: name,
|
||||
url: "#{@path}#{name_to_url(name)}/",
|
||||
children: [],
|
||||
methods: [],
|
||||
enums: [],
|
||||
exceptions: [],
|
||||
path: [name]
|
||||
}
|
||||
add_symbol(name: name, url: "#{@path}#{name_to_url(name)}/")
|
||||
@tree << package
|
||||
end
|
||||
|
||||
@tree.each do | package |
|
||||
entry = zipfile.glob("javadoc/#{name_to_url(package[:name])}/package-summary.html").first
|
||||
summary = Nokogiri::HTML(entry.get_input_stream.read)
|
||||
process_package(zipfile, package, summary)
|
||||
end
|
||||
end
|
||||
|
||||
def process_package(zipfile, package, summary)
|
||||
url = "#{@path}#{name_to_url(package[:name])}"
|
||||
|
||||
html = summary.at_css('.contentContainer').to_html
|
||||
html = process_html(html, url)
|
||||
|
||||
@pages << PageDocPebbleKitAndroid.new(@site, @site.source, url, package[:name], html, package)
|
||||
|
||||
class_table = summary.css('table[summary~="Class Summary"]')
|
||||
class_table.css('tbody tr').each do | row |
|
||||
name = row.at_css('td.colFirst').content
|
||||
package[:children] << {
|
||||
name: name,
|
||||
summary: row.at_css('.colLast').content,
|
||||
url: "#{url}/#{name}",
|
||||
path: package[:path].clone << name,
|
||||
type: 'class',
|
||||
children: [],
|
||||
methods: [],
|
||||
enums: [],
|
||||
exceptions: []
|
||||
}
|
||||
add_symbol(name: "#{package[:name]}.#{name}", url: "#{url}/#{name}")
|
||||
end
|
||||
|
||||
enum_table = summary.css('table[summary~="Enum Summary"]')
|
||||
enum_table.css('tbody tr').each do | row |
|
||||
name = row.at_css('.colFirst').content
|
||||
package[:children] << {
|
||||
name: name,
|
||||
summary: row.at_css('.colLast').content,
|
||||
path: package[:path].clone << name,
|
||||
url: "#{url}/#{name}",
|
||||
type: 'enum',
|
||||
children: [],
|
||||
methods: [],
|
||||
enums: [],
|
||||
exceptions: []
|
||||
}
|
||||
add_symbol(name: "#{package[:name]}.#{name}", url: "#{url}/#{name}")
|
||||
end
|
||||
|
||||
summary.css('table[summary~="Exception Summary"]').css('tbody tr').each do | row |
|
||||
name = row.at_css('td.colFirst').content
|
||||
package[:children] << {
|
||||
name: name,
|
||||
summary: row.at_css('.colLast').content,
|
||||
path: package[:path].clone << name,
|
||||
url: "#{url}/#{name}",
|
||||
type: 'exception',
|
||||
children: [],
|
||||
methods: [],
|
||||
enums: [],
|
||||
exceptions: []
|
||||
}
|
||||
add_symbol(name: "#{package[:name]}.#{name}", url: "#{url}/#{name}")
|
||||
end
|
||||
|
||||
package[:children].each do | child |
|
||||
filename = "javadoc/#{name_to_url(package[:name])}/#{child[:name]}.html"
|
||||
child_url = '/docs/pebblekit-android/' + package[:name].split('.').join('/') + '/' + child[:name] + '/'
|
||||
|
||||
entry = zipfile.glob(filename).first
|
||||
summary = Nokogiri::HTML(entry.get_input_stream.read)
|
||||
|
||||
method_table = summary.css('table[summary~="Method Summary"]')
|
||||
method_table.css('tr').each do | row |
|
||||
next unless row.at_css('.memberNameLink')
|
||||
name = row.at_css('.memberNameLink').content
|
||||
child[:methods] << {
|
||||
name: name,
|
||||
summary: row.at_css('.block') ? row.at_css('.block').content : '',
|
||||
url: child_url + '#' + name,
|
||||
type: 'method'
|
||||
}
|
||||
add_symbol(name: [package[:name], child[:name], name].join('.'), url: child_url + '#' + name)
|
||||
end
|
||||
html = summary.at_css('.contentContainer').to_html
|
||||
html = process_html(html, child_url)
|
||||
@pages << PageDocPebbleKitAndroid.new(@site, @site.source, child_url, child[:name], html, child)
|
||||
end
|
||||
end
|
||||
|
||||
def name_to_url(name)
|
||||
name.split('.').join('/')
|
||||
end
|
||||
|
||||
def process_html(html, root)
|
||||
contents = Nokogiri::HTML(html)
|
||||
contents.css('a').each do | link |
|
||||
next if link['href'].nil?
|
||||
href = File.expand_path(link['href'], root)
|
||||
href = href.sub('/com/com/', '/com/')
|
||||
href = href.sub('.html', '/')
|
||||
link['href'] = href
|
||||
end
|
||||
contents.css('.memberSummary caption').remove
|
||||
contents.to_html
|
||||
end
|
||||
end
|
||||
|
||||
class PageDocPebbleKitAndroid < Jekyll::Page
|
||||
def initialize(site, base, dir, title, contents, group)
|
||||
@site = site
|
||||
@base = base
|
||||
@dir = dir
|
||||
@name = 'index.html'
|
||||
@contents = contents
|
||||
@group = group
|
||||
|
||||
process(@name)
|
||||
read_yaml(File.join(base, '_layouts', 'docs'), 'pebblekit-android.html')
|
||||
data['title'] = title.to_s
|
||||
end
|
||||
|
||||
def to_liquid(attrs = ATTRIBUTES_FOR_LIQUID)
|
||||
super(attrs + %w(
|
||||
contents
|
||||
group
|
||||
))
|
||||
end
|
||||
|
||||
attr_reader :contents
|
||||
|
||||
def group
|
||||
if @group.nil?
|
||||
{}
|
||||
else
|
||||
JSON.parse(JSON.dump(@group))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
240
devsite/lib/pebble_documentation_pebblekit_ios.rb
Normal file
240
devsite/lib/pebble_documentation_pebblekit_ios.rb
Normal file
|
@ -0,0 +1,240 @@
|
|||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
require 'zip'
|
||||
require 'nokogiri'
|
||||
require 'slugize'
|
||||
require 'open-uri'
|
||||
|
||||
module Pebble
|
||||
# PebbleKit iOS documentation processing class.
|
||||
class DocumentationPebbleKitIos < Documentation
|
||||
def initialize(site, source, root)
|
||||
super(site)
|
||||
@site = site
|
||||
@url_root = root
|
||||
open(source) do |zf|
|
||||
Zip::File.open(zf.path) do |zipfile|
|
||||
zipfile.each { |entry| process_entry(entry) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def language
|
||||
'pebblekit_ios'
|
||||
end
|
||||
|
||||
def process_entry(entry)
|
||||
return unless File.extname(entry.name) == '.html'
|
||||
doc = Nokogiri::HTML(entry.get_input_stream.read)
|
||||
process_index(doc) if File.basename(entry.name) == 'index.html'
|
||||
process_normal_entry(doc, entry)
|
||||
end
|
||||
|
||||
def process_normal_entry(doc, entry)
|
||||
doc_entry = DocEntryPebbleKitIos.new(entry, doc, @url_root)
|
||||
add_symbol(doc_entry.to_symbol)
|
||||
doc_entry.anchor_symbols.map { |symbol| add_symbol(symbol) }
|
||||
@pages << doc_entry.create_page(@site)
|
||||
end
|
||||
|
||||
def process_index(doc)
|
||||
headers = doc.at_css('#content').css('h2').map(&:content)
|
||||
lists = doc.at_css('#content').css('ul').map { | list | list.css('li') }
|
||||
headers.each_with_index do |header, index|
|
||||
process_index_header(header, index, lists)
|
||||
end
|
||||
end
|
||||
|
||||
def process_index_header(header, index, lists)
|
||||
tree_item = {
|
||||
name: header,
|
||||
url: "#{@url_root}##{header.slugize}",
|
||||
children: []
|
||||
}
|
||||
lists[index].each { |item| process_index_header_item(tree_item, item) }
|
||||
@tree << tree_item
|
||||
end
|
||||
|
||||
def process_index_header_item(tree_item, item)
|
||||
tree_item[:children] << {
|
||||
name: item.content,
|
||||
url: "#{@url_root}#{item.at_css('a')['href'].sub('.html', '/').gsub('+', '%2B')}",
|
||||
path: [item.content],
|
||||
children: []
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
# DocEntryIos is an iOS documentation class used to process a single page
|
||||
# of the iOS documentation.
|
||||
class DocEntryPebbleKitIos
|
||||
def initialize(entry, doc, url_root)
|
||||
@entry = entry
|
||||
@doc = doc
|
||||
@url_root = url_root
|
||||
end
|
||||
|
||||
def to_symbol
|
||||
{ name: name, url: url.gsub('+', '%2B') }
|
||||
end
|
||||
|
||||
def anchor_symbols
|
||||
@doc.css('a[name^="//api"][title]').map do |anchor|
|
||||
anchor_to_symbol(anchor)
|
||||
end
|
||||
end
|
||||
|
||||
def create_page(site)
|
||||
return nil if @doc.at_css('#content').nil?
|
||||
contents = @doc.at_css('#content')
|
||||
title = @doc.at_css('.title').content
|
||||
group = { 'path' => [File.basename(path)] }
|
||||
PageDocPebbleKitIos.new(site, url, title, contents, group)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def name
|
||||
File.basename(@entry.name).sub('.html', '')
|
||||
end
|
||||
|
||||
def url
|
||||
@url_root + path
|
||||
end
|
||||
|
||||
def path
|
||||
@entry.name.sub('.html', '/')
|
||||
end
|
||||
|
||||
def anchor_to_symbol(anchor)
|
||||
summary = @doc.at_css("a[name=\"#{anchor['name']}\"] + h3 + div")
|
||||
{
|
||||
name: anchor['title'],
|
||||
url: (url + '#' + anchor['name']).gsub('+', '%2B'),
|
||||
summary: summary.content
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
# Jekyll Page subclass for rendering the iOS documentation pages.
|
||||
class PageDocPebbleKitIos < Jekyll::Page
|
||||
attr_reader :group
|
||||
|
||||
def initialize(site, dir, title, contents, group)
|
||||
@site = site
|
||||
@base = site.source
|
||||
@dir = dir
|
||||
@name = 'index.html'
|
||||
@contents = contents
|
||||
@group = group
|
||||
process(@name)
|
||||
process_contents
|
||||
read_yaml(File.join(@base, '_layouts', 'docs'), 'pebblekit-ios.html')
|
||||
data['title'] = title
|
||||
end
|
||||
|
||||
def to_liquid(attrs = ATTRIBUTES_FOR_LIQUID)
|
||||
super(attrs + %w(
|
||||
contents
|
||||
group
|
||||
))
|
||||
end
|
||||
|
||||
def contents
|
||||
@contents.to_html
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def process_contents
|
||||
# Clean up links
|
||||
@contents.css('a').each { |link| process_page_link(link) }
|
||||
|
||||
remove_duplicated_title
|
||||
switch_specification_section_table_headers_to_normal_cells
|
||||
clean_up_method_titles
|
||||
switch_parameter_tables_into_definition_lists
|
||||
remove_footer
|
||||
end
|
||||
|
||||
def process_page_link(link)
|
||||
process_page_link_class(link) unless link['name'].nil?
|
||||
process_page_link_href(link) unless link['href'].nil?
|
||||
end
|
||||
|
||||
def process_page_link_class(link)
|
||||
link['class'] = '' if link['class'].nil?
|
||||
link['class'] << ' anchor'
|
||||
end
|
||||
|
||||
def process_page_link_href(link)
|
||||
link['href'] = link['href'].gsub('../', '../../')
|
||||
link['href'] = link['href'].gsub('.html', '/')
|
||||
link['href'] = link['href'].gsub('+', '%2B')
|
||||
end
|
||||
|
||||
def remove_duplicated_title
|
||||
@contents.css('h1').each(&:remove)
|
||||
end
|
||||
|
||||
def switch_specification_section_table_headers_to_normal_cells
|
||||
@contents.css('.section-specification th').each do |n|
|
||||
n.node_name = 'td'
|
||||
n['class'] = 'specification-title'
|
||||
end
|
||||
end
|
||||
|
||||
def clean_up_method_titles
|
||||
# Remove the <code><a> tags inside h3.method-title nodes, strip nbsp and
|
||||
# add the subsubtitle class.
|
||||
@contents.css('h3.method-title').each do |n|
|
||||
method_title = n.at_css('code a')
|
||||
n.content = method_title.content.gsub(/\A\u00A0+/, '') if method_title
|
||||
n['class'] = 'subsubtitle method-title'
|
||||
end
|
||||
end
|
||||
|
||||
def switch_parameter_tables_into_definition_lists
|
||||
# Change the table node into a definition list
|
||||
# For each row recover the parameter name and the description, and add
|
||||
# them to the list as term and definition.
|
||||
@contents.css('table.argument-def').each do |table|
|
||||
table.node_name = 'dl'
|
||||
|
||||
parameters = table.css('tr').map do |row|
|
||||
parameter = row.at_css('th.argument-name code')
|
||||
parameter.node_name = 'em'
|
||||
dt = Nokogiri::XML::Element.new('dt', table.document)
|
||||
dt.add_child parameter
|
||||
|
||||
definition = row.at_css('td:not(.argument-name)').content
|
||||
dd = Nokogiri::XML::Element.new('dd', table.document)
|
||||
dd.children = definition
|
||||
|
||||
[dt, dd]
|
||||
end.flatten(1)
|
||||
|
||||
table.children.unlink
|
||||
parameters.each { |p| table.add_child p }
|
||||
end
|
||||
end
|
||||
|
||||
def remove_footer
|
||||
@contents.css('footer').each(&:remove)
|
||||
end
|
||||
end
|
||||
end
|
140
devsite/lib/search_markdown.rb
Normal file
140
devsite/lib/search_markdown.rb
Normal file
|
@ -0,0 +1,140 @@
|
|||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
module Pebble
|
||||
|
||||
class SearchMarkdown < Redcarpet::Render::HTML
|
||||
|
||||
def initialize()
|
||||
@contents = Array.new
|
||||
@sections = []
|
||||
@section = {
|
||||
:title => nil,
|
||||
:contents => []
|
||||
}
|
||||
super()
|
||||
end
|
||||
|
||||
def get_contents()
|
||||
@contents.join(" \n ")
|
||||
end
|
||||
|
||||
def get_sections()
|
||||
unless @section.nil?
|
||||
@sections << @section
|
||||
end
|
||||
@sections.map do | section |
|
||||
section[:contents] = section[:contents].join("\n")
|
||||
section
|
||||
end
|
||||
@sections
|
||||
end
|
||||
|
||||
def block_code(code, language)
|
||||
""
|
||||
end
|
||||
|
||||
def header(text, header_level)
|
||||
unless @section.nil?
|
||||
@sections << @section
|
||||
end
|
||||
@section = {
|
||||
:title => text,
|
||||
:contents => []
|
||||
}
|
||||
@contents << text
|
||||
""
|
||||
end
|
||||
|
||||
def paragraph(text)
|
||||
@contents << text
|
||||
@section[:contents] << text
|
||||
""
|
||||
end
|
||||
|
||||
def codespan(text)
|
||||
text
|
||||
end
|
||||
|
||||
def image(link, title, alt_text)
|
||||
""
|
||||
end
|
||||
|
||||
def link(link, title, content)
|
||||
content
|
||||
end
|
||||
|
||||
def list(contents, type)
|
||||
@contents << contents
|
||||
@section[:contents] << contents
|
||||
""
|
||||
end
|
||||
|
||||
def list_item(text, list_type)
|
||||
@contents << text
|
||||
@section[:contents] << text
|
||||
""
|
||||
end
|
||||
|
||||
def autolink(link, link_type)
|
||||
link
|
||||
end
|
||||
|
||||
def double_emphasis(text)
|
||||
text
|
||||
end
|
||||
|
||||
def emphasis(text)
|
||||
text
|
||||
end
|
||||
|
||||
def linebreak()
|
||||
""
|
||||
end
|
||||
|
||||
def raw_html(raw_html)
|
||||
""
|
||||
end
|
||||
|
||||
def triple_emphasis(text)
|
||||
text
|
||||
end
|
||||
|
||||
def strikethrough(text)
|
||||
text
|
||||
end
|
||||
|
||||
def superscript(text)
|
||||
text
|
||||
end
|
||||
|
||||
def underline(text)
|
||||
text
|
||||
end
|
||||
|
||||
def highlight(text)
|
||||
text
|
||||
end
|
||||
|
||||
def quote(text)
|
||||
text
|
||||
end
|
||||
|
||||
def footnote_ref(number)
|
||||
""
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
81
devsite/lib/toc_generator.rb
Normal file
81
devsite/lib/toc_generator.rb
Normal file
|
@ -0,0 +1,81 @@
|
|||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
require 'redcarpet'
|
||||
require 'nokogiri'
|
||||
|
||||
module Pebble
|
||||
|
||||
class TocGenerator
|
||||
|
||||
def initialize(max_depth=-1)
|
||||
@max_depth = max_depth
|
||||
@markdown = TocMarkdown.new()
|
||||
@redcarpet = Redcarpet::Markdown.new(@markdown,
|
||||
fenced_code_blocks: true,
|
||||
autolink: true,
|
||||
tables: true,
|
||||
no_intra_emphasis: true,
|
||||
strikethrough: true,
|
||||
highlight: true)
|
||||
end
|
||||
|
||||
def generate(content)
|
||||
@redcarpet.render(content)
|
||||
page_toc = @markdown.get_toc
|
||||
toc_array(toc_normalised(page_toc))
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Convert the ToC array of hashes into an array of array so that it can
|
||||
# be used in the Liquid template.
|
||||
def toc_array(array)
|
||||
array.map { |entry| [ entry[:id], entry[:title], entry[:level] ] }
|
||||
end
|
||||
|
||||
# Normalised the ToC array by ensuring that the smallest level number is 1.
|
||||
def toc_normalised(array)
|
||||
min_level = 100
|
||||
array.each { |entry| min_level = [ min_level, entry[:level] ].min }
|
||||
level_offset = min_level - 1
|
||||
array.map { |entry| entry[:level] -= level_offset; entry }.select do |entry|
|
||||
@max_depth == -1 || entry[:level] <= @max_depth
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class TocMarkdown < Redcarpet::Render::HTML
|
||||
|
||||
def initialize()
|
||||
@toc = Array.new
|
||||
@depth = 0
|
||||
super()
|
||||
end
|
||||
|
||||
def get_toc()
|
||||
@toc
|
||||
end
|
||||
|
||||
def header(text, header_level)
|
||||
text = Nokogiri::HTML(text).text if text.include?('<')
|
||||
entry = { title: text, id: text.slugize, level: header_level }
|
||||
@toc << entry
|
||||
""
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
Loading…
Add table
Add a link
Reference in a new issue