require 'jsduck/option_parser'
require 'jsduck/meta_tag_registry'
require 'jsduck/logger'
require 'jsduck/util/json'
require 'jsduck/util/os'
require 'jsduck/util/io'
require 'jsduck/util/parallel'
module JsDuck
# Keeps command line options
class Options
attr_accessor :input_files
attr_accessor :output_dir
attr_accessor :ignore_global
attr_accessor :external_classes
attr_accessor :ext4_events
# Customizing output
attr_accessor :title
attr_accessor :header
attr_accessor :footer
attr_accessor :head_html
attr_accessor :body_html
attr_accessor :welcome
attr_accessor :guides
attr_accessor :videos
attr_accessor :examples
attr_accessor :categories_path
attr_accessor :source
attr_accessor :images
attr_accessor :link_tpl
attr_accessor :img_tpl
attr_accessor :export
attr_accessor :seo
attr_accessor :eg_iframe
attr_accessor :examples_base_url
attr_accessor :tests
attr_accessor :comments_url
attr_accessor :comments_domain
# Debugging
attr_accessor :template_dir
attr_accessor :template_links
attr_accessor :extjs_path
attr_accessor :local_storage_db
attr_accessor :touch_examples_ui
attr_accessor :ext_namespaces
attr_accessor :imports
attr_accessor :new_since
def initialize
@input_files = []
@output_dir = nil
@ignore_global = false
@external_classes = [
# JavaScript builtins
"Object",
"String",
"Number",
"Boolean",
"RegExp",
"Function",
"Array",
"Arguments",
"Date",
"Error",
# DOM
"HTMLElement",
"XMLElement",
"NodeList",
"TextNode",
"CSSStyleSheet",
"CSSStyleRule",
"Event",
# Special anything-goes type
"Mixed",
]
@ext4_events = nil
@meta_tag_paths = []
@version = "4.4.0"
# Customizing output
@title = "Documentation - JSDuck"
@header = "Documentation JSDuck"
@footer = "Generated with JSDuck #{@version}."
@head_html = ""
@body_html = ""
@welcome = nil
@guides = nil
@videos = nil
@examples = nil
@categories_path = nil
@source = true
@images = []
@link_tpl = '%a'
# Note that we wrap image template inside
because {@img} often
# appears inline within text, but that just looks ugly in HTML
@img_tpl = '
![%a](%u)
'
@export = nil
@seo = false
@eg_iframe = nil
@examples_base_url = "extjs-build/examples/"
@tests = false
@comments_url = nil
@comments_domain = nil
# Debugging
@root_dir = File.dirname(File.dirname(File.dirname(__FILE__)))
@template_dir = @root_dir + "/template-min"
@template_links = false
@extjs_path = "extjs/ext-all.js"
@local_storage_db = "docs"
@touch_examples_ui = false
@ext_namespaces = ["Ext"]
@imports = []
@new_since = nil
# Turn multiprocessing off by default in Windows
Util::Parallel.in_processes = Util::OS::windows? ? 0 : nil
# enable all warnings except :link_auto
Logger.set_warning(:all, true)
Logger.set_warning(:link_auto, false)
end
# Make options object behave like hash.
# This allows us to substitute it with hash in unit tests.
def [](key)
send(key)
end
def parse!(argv)
create_option_parser.parse!(argv).each do |fname|
read_filenames(canonical(fname))
end
validate
reg = MetaTagRegistry.new
reg.load([:builtins] + @meta_tag_paths)
reg[:new].create_tooltip!(@imports, @new_since)
MetaTagRegistry.instance = reg
end
def create_option_parser
optparser = JsDuck::OptionParser.new do | opts |
opts.banner = "Usage: jsduck [options] files/dirs..."
opts.separator ""
opts.separator "For example:"
opts.separator ""
opts.separator " # Documentation for builtin JavaScript classes like Array and String"
opts.separator " jsduck --output output/dir --builtin-classes"
opts.separator ""
opts.separator " # Documentation for your own JavaScript"
opts.separator " jsduck --output output/dir input-file.js some/input/dir"
opts.separator ""
opts.separator "The main options:"
opts.separator ""
opts.on('-o', '--output=PATH',
"Directory to write all this documentation.",
"",
"This option is REQUIRED. When the directory exists,",
"it will be overwritten. Give dash '-' as argument",
"to write docs to STDOUT (works only with --export).") do |path|
@output_dir = path == "-" ? :stdout : canonical(path)
end
opts.on('--export=TYPE',
"Exports docs in JSON.",
"",
"TYPE is one of:",
"",
"- full - full class docs.",
"- examples - extracts inline examples from classes.") do |format|
export_type = format.to_sym
if [:full, :examples].include?(export_type)
@export = export_type
else
Logger.fatal("Unsupported export type: '#{export_type}'")
exit(1)
end
end
opts.on('--builtin-classes',
"Includes docs for JavaScript builtins.",
"",
"Docs for the following classes are included:",
"",
"- Array",
"- Boolean",
"- Date",
"- Function",
"- Number",
"- Object",
"- RegExp",
"- String") do
read_filenames(@root_dir + "/js-classes")
end
opts.on('--seo', "Enables SEO-friendly print version.",
"",
"Instead of index.html creates index.php that will serve",
"the regular docs, print-friendly docs, and search-engine-",
"friendly docs (the latter two are pretty much the same).") do
@seo = true
end
opts.on('--config=PATH',
"Loads config options from JSON file.",
"",
"An alternative to listing all options on command line.",
"",
"See also: https://github.com/senchalabs/jsduck/wiki/Config-file") do |path|
path = canonical(path)
if File.exists?(path)
config = read_json_config(path)
else
Logger.fatal("The config file #{path} doesn't exist")
exit(1)
end
# treat paths inside JSON config relative to the location of
# config file. When done, switch back to current working dir.
@working_dir = File.dirname(path)
optparser.parse!(config).each {|fname| read_filenames(canonical(fname)) }
@working_dir = nil
end
opts.on('--encoding=NAME', "Input encoding (defaults to UTF-8).") do |encoding|
JsDuck::Util::IO.encoding = encoding
end
opts.separator ""
opts.separator "Customizing output:"
opts.separator ""
opts.on('--title=TEXT',
"Custom title text for the documentation.",
"",
"Defaults to 'Documentation - JSDuck'",
"",
"The title will be used both inside and in",
"the header of the page. Inside page header the left",
"part (from ' - ' separator) will be shown in bold.") do |text|
@title = text
@header = text.sub(/^(.*?) +- +/, "\\1 ")
end
opts.on('--footer=TEXT',
"Custom footer text for the documentation.",
"",
"Defaults to: 'Generated with JSDuck {VERSION}.'",
"",
"'{VERSION}' is a placeholder that will get substituted",
"with the current version of JSDuck. See --version.") do |text|
@footer = text.gsub(/\{VERSION\}/, @version)
end
opts.on('--head-html=HTML',
"HTML for the section of index.html.",
"",
"Useful for adding extra