require 'jsduck/options/helpful_parser' require 'jsduck/options/record' require 'jsduck/options/config' require 'jsduck/warning/parser' require 'jsduck/warning/warn_exception' require 'jsduck/logger' require 'jsduck/util/io' require 'jsduck/version' module JsDuck module Options # Performs parsing of JSDuck options. class Parser def initialize(file_class=File, config_class=Options::Config) @file = file_class @config = config_class @opts = Options::Record.new @defaults = {} @root_dir = @file.dirname(@file.dirname(@file.dirname(@file.dirname(__FILE__)))) @optparser = Options::HelpfulParser.new init_parser end # Parses array of command line options, returning # Options::Record object containing all the options. def parse(argv) init_defaults parse_options(argv) auto_detect_config_file unless @opts.config @opts end private def init_parser banner "Usage: jsduck [options] files/dirs..." separator "" separator "For example:" separator "" separator " # Documentation for builtin JavaScript classes like Array and String" separator " jsduck --output output/dir --builtin-classes" separator "" separator " # Documentation for your own JavaScript" separator " jsduck --output output/dir input-file.js some/input/dir" separator "" separator "The main options:" separator "" attribute :input_files, [] validator :input_files do if @opts.input_files.empty? && !@opts.welcome && !@opts.guides && !@opts.videos && !@opts.examples "Please specify some input files, otherwise there's nothing I can do :(" end end attribute :output option('-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| if path == "-" @opts.output = :stdout else @opts.output = canonical(path) @opts.cache_dir = @opts.output + "/.cache" unless @opts.cache_dir end end validator :output do if @opts.output == :stdout # No output dir needed for export if !@opts.export "Output to STDOUT only works when using --export option" end elsif !@opts.output "Please specify an output directory, where to write all this amazing documentation" elsif @file.exists?(@opts.output) && !@file.directory?(@opts.output) "The output directory is not really a directory at all :(" elsif !@file.exists?(@file.dirname(@opts.output)) "The parent directory for #{@opts.output} doesn't exist" end end attribute :export option('--export=full/examples', "Exports docs in JSON.", "", "For each JavaScript class a JSON file gets written,", "the contents of which are as follows:", "", "- full - docs and metadata for class and its members.", "- examples - inline examples from classes and guides.") do |format| @opts.export = format.to_sym end validator :export do if ![nil, :full, :examples].include?(@opts.export) "Unknown export format: #{@opts.export}" end end option('--builtin-classes', "Includes docs for JavaScript builtins.", "", "Docs for the following classes are included:", "", "- Array", "- Boolean", "- Date", "- Function", "- Number", "- Object", "- RegExp", "- String") do @opts.input_files << @root_dir + "/js-classes" end attribute :seo, false option('--[no-]seo', "Enables SEO-friendly print version. (OFF)", "", "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).", "", "Disabled by default.") do |on| @opts.seo = on end attribute :config option('--config=PATH', "Loads config options from JSON file.", "", "An alternative to listing all options on command line.", "", "When the current directory contains jsduck.json file", "then options are automatically read from there.", "", "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) parse_options(config) @working_dir = nil @opts.config = path end attribute :encoding option('--encoding=NAME', "Input encoding (defaults to UTF-8).") do |encoding| @opts.encoding = encoding end attribute :exclude, [] option('--exclude=PATH1,PATH2', Array, "Exclude input file or directory.", "", "For example to include all the subdirs of", "/app/js except /app/js/new, run JSDuck with:", "", " jsduck /app/js --exclude /app/js/new") do |paths| @opts.exclude += paths.map {|p| canonical(p) } end separator "" separator "Customizing output:" separator "" attribute :title, "Documentation - JSDuck" option('--title=TEXT', "Custom title text for the documentation.", "", "Defaults to 'Documentation - JSDuck'", "", "The title will be used both inside