Commit db4a9f5f authored by Rene Saarsoo's avatar Rene Saarsoo
Browse files

Create SourceFileParser class.

The parsing logic is now encapsulated inside this separate class,
keeping the SourceFile class simpler and more to the point.  The
SourceFileParser is a singleton, so we no more create new merger,
doc-parser, etc for every single file we parse.

Also moved error handling out of SourceFile class up to App.  This way
the catching of parse errors no more interferes with unit tests.
parent 40486f38
Loading
Loading
Loading
Loading
+9 −1
Original line number Diff line number Diff line
@@ -82,7 +82,15 @@ module JsDuck
    def parallel_parse(filenames)
      @parallel.map(filenames) do |fname|
        Logger.instance.log("Parsing", fname)
        begin
          SourceFile.new(JsDuck::IO.read(fname), fname, @opts)
        rescue
          puts "Error while parsing #{fname}: #{$!}"
          puts
          puts "Here's a full backtrace:"
          puts $!.backtrace
          exit(1)
        end
      end
    end

+4 −46
Original line number Diff line number Diff line
require 'jsduck/esprima_parser'
require 'jsduck/css_parser'
require 'jsduck/doc_parser'
require 'jsduck/merger'
require 'jsduck/ast'
require 'jsduck/doc_type'
require 'jsduck/class_doc_expander'
require 'jsduck/source_file_parser'
require "cgi"

module JsDuck
@@ -22,19 +16,13 @@ module JsDuck
    def initialize(contents, filename="", options={})
      @contents = contents
      @filename = filename
      @options = options
      @html_filename = ""
      @links = {}
      @doc_type = DocType.new
      @doc_parser = DocParser.new
      @doc_expander = ClassDocExpander.new

      merger = Merger.new
      merger.filename = @filename
      @docs = SourceFileParser.instance.parse(@contents, @filename, options)

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

@@ -86,36 +74,6 @@ module JsDuck

    private

    # Parses the file depending on filename as JS or CSS
    def parse
      begin
        if @filename =~ /\.s?css$/
          docs = CssParser.new(@contents, @options).parse
        else
          docs = EsprimaParser.new(@contents, @options).parse
          docs = Ast.new(docs).detect_all!
        end

        docs.map do |docset|
          docset[:comment] = @doc_parser.parse(docset[:comment])
          docset[:tagname] = @doc_type.detect(docset[:comment], docset[:code])

          if docset[:tagname] == :class
            @doc_expander.expand(docset)
          else
            docset
          end
        end.flatten

      rescue
        puts "Error while parsing #{@filename}: #{$!}"
        puts
        puts "Here's a full backtrace:"
        puts $!.backtrace
        exit(1)
      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.
+67 −0
Original line number Diff line number Diff line
require 'singleton'
require 'jsduck/esprima_parser'
require 'jsduck/css_parser'
require 'jsduck/doc_parser'
require 'jsduck/merger'
require 'jsduck/ast'
require 'jsduck/doc_type'
require 'jsduck/class_doc_expander'

module JsDuck

  # Performs the actual parsing of CSS or JS source.
  #
  # This is the class that brings together all the different steps of
  # parsing the source.
  class SourceFileParser
    include Singleton

    def initialize
      @doc_type = DocType.new
      @doc_parser = DocParser.new
      @class_doc_expander = ClassDocExpander.new
      @merger = Merger.new
    end

    # Parses file into final docset that can be fed into Aggregator
    def parse(contents, filename="", options={})
      @merger.filename = filename

      parse_js_or_css(contents, filename, options)
        .map {|docset| expand(docset) }
        .flatten
        .map {|docset| merge(docset) }
    end

    private

    # Parses the file depending on filename as JS or CSS
    def parse_js_or_css(contents, filename, options)
      if filename =~ /\.s?css$/
        docs = CssParser.new(contents, options).parse
      else
        docs = EsprimaParser.new(contents, options).parse
        docs = Ast.new(docs).detect_all!
      end
    end

    # Parses the docs, detects tagname and expands class docset
    def expand(docset)
      docset[:comment] = @doc_parser.parse(docset[:comment])
      docset[:tagname] = @doc_type.detect(docset[:comment], docset[:code])

      if docset[:tagname] == :class
        @class_doc_expander.expand(docset)
      else
        docset
      end
    end

    # Merges comment and code parst of docset
    def merge(docset)
      @merger.linenr = docset[:linenr]
      @merger.merge(docset)
    end
  end

end