Commit 50c263a1 authored by Rene Saarsoo's avatar Rene Saarsoo
Browse files

Created SourceFile class.

All parsing and merging now happens inside that class.
Consequently the Agggregator is now a lot simpler, as
it takes for input just instance of SourceFile.

SourceFile instances contain all the input: filename, source, and
parsed doc-objects.

The output of HTML source files now happens after all the
parsing and aggregating, similarly to all other output.
For now the links to source code are still line-nr based,
but this will now be easy to change.
parent eb8631d3
Loading
Loading
Loading
Loading
+9 −41
Original line number Diff line number Diff line
require 'jsduck/merger'

module JsDuck

  # Combines JavaScript Parser, DocParser and Merger.
@@ -10,44 +8,17 @@ module JsDuck
      @classes = {}
      @orphans = []
      @current_class = nil
      @merger = Merger.new
    end

    # Combines chunk of parsed JavaScript together with previously
    # added chunks.  The resulting documentation is accumulated inside
    # this class and can be later accessed through #result method.
    #
    # - input  parse result from JsDuck::Parser
    # - filename  name of the JS file where it came from
    # - html_filename  name of the HTML file where the source was saved.
    # - file  SoureFile class instance
    #
    def aggregate(input, filename="", html_filename="")
    def aggregate(file)
      @current_class = nil
      input.each do |docset|
        doc = @merger.merge(docset[:comment], docset[:code])

        add_source_data(doc, {
          :filename => filename,
          :html_filename => html_filename,
          :linenr => docset[:linenr],
        })

        register(doc)
      end
    end

    # Links doc-object to source code where it came from.
    def add_source_data(doc, src)
      doc[:href] = src[:html_filename] + "#line-" + src[:linenr].to_s
      doc[:filename] = src[:filename]
      doc[:linenr] = src[:linenr]
      # class-level doc-comment can contain constructor and config
      # options, link those to the same location in source.
      if doc[:tagname] == :class
        doc[:cfg].each {|cfg| add_source_data(cfg, src) }
        doc[:method].each {|method| add_source_data(method, src) }
      end
      doc
      file.each {|doc| register(doc) }
    end

    # Registers documentation node either as class or as member of
@@ -153,10 +124,10 @@ module JsDuck
    end

    def add_empty_class(name, doc = "")
      cls = {
      add_class({
        :tagname => :class,
        :name => name,
        :doc => "",
        :doc => doc,
        :mixins => [],
        :alternateClassNames => [],
        :cfg => [],
@@ -165,13 +136,10 @@ module JsDuck
        :event => [],
        :css_var => [],
        :css_mixin => [],
      }
      add_source_data(cls, {
        :filename => "",
        :html_filename => "",
        :linenr => 0,
      })
      add_class(cls)
    end

    def result
+18 −11
Original line number Diff line number Diff line
require 'rubygems'
require 'jsduck/js_parser'
require 'jsduck/css_parser'
require 'jsduck/aggregator'
require 'jsduck/source_file'
require 'jsduck/source_formatter'
require 'jsduck/class'
require 'jsduck/tree'
@@ -63,8 +62,10 @@ module JsDuck
      warn_unnamed(relations)

      if @export == :json
        @timer.time(:generating) { write_src(@output_dir+"/source", parsed_files) }
        @timer.time(:generating) { write_json(@output_dir+"/output", relations) }
      else
        @timer.time(:generating) { write_src(@output_dir+"/source", parsed_files) }
        @timer.time(:generating) { write_tree(@output_dir+"/output/tree.js", relations) }
        @timer.time(:generating) { write_members(@output_dir+"/output/members.js", relations) }
        @timer.time(:generating) { write_pages(@output_dir+"/output", relations) }
@@ -75,15 +76,9 @@ module JsDuck

    # Parses the files in parallel using as many processes as available CPU-s
    def parallel_parse(filenames)
      src = SourceFormatter.new(@output_dir + "/source", @export ? :format_pre : :format_page)
      @parallel.map(filenames) do |fname|
        puts "Parsing #{fname} ..." if @verbose
        code = IO.read(fname)
        {
          :filename => fname,
          :html_filename => File.basename(src.write(code, fname)),
          :data => fname =~ /\.s?css$/ ? CssParser.new(code).parse : JsParser.new(code).parse,
        }
        SourceFile.new(IO.read(fname), fname)
      end
    end

@@ -91,8 +86,8 @@ module JsDuck
    def aggregate(parsed_files)
      agr = Aggregator.new
      parsed_files.each do |file|
        puts "Aggregating #{file[:filename]} ..." if @verbose
        agr.aggregate(file[:data], file[:filename], file[:html_filename])
        puts "Aggregating #{file.filename} ..." if @verbose
        agr.aggregate(file)
      end
      agr.classify_orphans
      agr.create_global_class
@@ -192,6 +187,18 @@ module JsDuck
      end
    end

    # Writes formatted HTML source code for each input file
    def write_src(path, parsed_files)
      src = SourceFormatter.new(path, @export ? :format_pre : :format_page)
      # Can't be done in parallel, because file.html_filename= method
      # updates all the doc-objects related to the file
      parsed_files.each do |file|
        html_filename = src.write(file.contents, file.filename)
        puts "Writing to #{html_filename} ..." if @verbose
        file.html_filename = File.basename(html_filename)
      end
    end

    def copy_template(template_dir, dir)
      puts "Copying template files to #{dir}..." if @verbose
      FileUtils.cp_r(template_dir, dir)
+71 −0
Original line number Diff line number Diff line
require 'jsduck/js_parser'
require 'jsduck/css_parser'
require 'jsduck/merger'

module JsDuck

  # Represents one JavaScript or CSS source file.
  #
  # The filename parameter determines whether it's parsed as
  # JavaScript (the default) or CSS.
  class SourceFile
    attr_reader :filename
    attr_reader :contents
    attr_reader :docs
    attr_reader :html_filename

    def initialize(contents, filename="")
      @contents = contents
      @filename = filename
      @html_filename = ""
      @links = []

      merger = Merger.new
      @docs = parse.map do |docset|
        link(docset[:linenr], merger.merge(docset[:comment], docset[:code]))
      end
    end

    # loops through each doc-object in file
    def each(&block)
      @docs.each(&block)
    end

    # Sets the html filename of this file,
    # updating also all doc-objects linking this file
    def html_filename=(html_filename)
      @html_filename = html_filename
      @links.each do |doc|
        doc[:html_filename] = @html_filename
        doc[:href] = @html_filename + "#line-" + doc[:linenr].to_s
      end
    end

    private

    # Parses the file depending on filename as JS or CSS
    def parse
      if @filename =~ /\.s?css$/
        CssParser.new(@contents).parse
      else
        JsParser.new(@contents).parse
      end
    end

    # Creates two-way link between sourcefile and doc-object.
    # If doc-object is class, links also the contained cfgs and constructor.
    # Returns the modified doc-object after done.
    def link(linenr, doc)
      @links << doc
      doc[:filename] = @filename
      doc[:linenr] = linenr
      if doc[:tagname] == :class
        doc[:cfg].each {|cfg| link(linenr, cfg) }
        doc[:method].each {|method| link(linenr, method) }
      end
      doc
    end

  end

end
+2 −2
Original line number Diff line number Diff line
require "jsduck/aggregator"
require "jsduck/js_parser"
require "jsduck/source_file"

describe JsDuck::Aggregator do

  def parse(string)
    agr = JsDuck::Aggregator.new
    agr.aggregate(JsDuck::JsParser.new(string).parse)
    agr.aggregate(JsDuck::SourceFile.new(string))
    agr.result
  end

+2 −2
Original line number Diff line number Diff line
require "jsduck/aggregator"
require "jsduck/js_parser"
require "jsduck/source_file"

describe JsDuck::Aggregator do

  def parse(string)
    agr = JsDuck::Aggregator.new
    agr.aggregate(JsDuck::JsParser.new(string).parse)
    agr.aggregate(JsDuck::SourceFile.new(string))
    agr.result
  end

Loading