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

Name-based links to source files.

Instead of linking to line numbers, documentable items in source files
are now nicely marked up, and are linked by name.  This should prevent
links to source from becoming outdated too quickly.

before: Ext.html#line-86
after:  Ext.html#Ext-method-apply
parent 6adec951
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
require 'rubygems'
require 'jsduck/aggregator'
require 'jsduck/source_file'
require 'jsduck/source_formatter'
require 'jsduck/source_writer'
require 'jsduck/class'
require 'jsduck/tree'
require 'jsduck/tree_icons'
@@ -185,11 +185,11 @@ module JsDuck

    # Writes formatted HTML source code for each input file
    def write_src(path, parsed_files)
      src = SourceFormatter.new(path, @export ? :format_pre : :format_page)
      src = SourceWriter.new(path, @export ? nil : :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)
        html_filename = src.write(file.to_html, file.filename)
        puts "Writing to #{html_filename} ..." if @verbose
        file.html_filename = File.basename(html_filename)
      end
+33 −5
Original line number Diff line number Diff line
require 'jsduck/js_parser'
require 'jsduck/css_parser'
require 'jsduck/merger'
require "cgi"

module JsDuck

@@ -18,7 +19,7 @@ module JsDuck
      @contents = contents
      @filename = filename
      @html_filename = ""
      @links = []
      @links = {}

      merger = Merger.new
      @docs = parse.map do |docset|
@@ -35,9 +36,35 @@ module JsDuck
    # updating also all doc-objects linking this file
    def html_filename=(html_filename)
      @html_filename = html_filename
      @links.each do |doc|
      @links.each_value do |line|
        line.each do |doc|
          doc[:html_filename] = @html_filename
        doc[:href] = @html_filename + "#line-" + doc[:linenr].to_s
          doc[:href] = @html_filename + "#" + id(doc)
        end
      end
    end

    # Returns source code as HTML with lines starting doc-comments specially marked.
    def to_html
      linenr = 0
      return @contents.lines.map do |line|
        linenr += 1;
        line = CGI.escapeHTML(line)
        # wrap the line in as many spans as there are links to this line number.
        if @links[linenr]
          @links[linenr].each do |doc|
            line = "<span id='#{id(doc)}'>#{line}</span>"
          end
        end
        line
      end.join()
    end

    def id(doc)
      if doc[:tagname] == :class
        doc[:name].sub(/\./, '-')
      else
        doc[:member].sub(/\./, '-') + "-" + doc[:tagname].to_s + "-" + doc[:name]
      end
    end

@@ -56,7 +83,8 @@ module JsDuck
    # 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
      @links[linenr] = [] unless @links[linenr]
      @links[linenr] << doc
      doc[:filename] = @filename
      doc[:linenr] = linenr
      if doc[:tagname] == :class
+14 −27
Original line number Diff line number Diff line
require "cgi"

module JsDuck

  # Formats JavaScript source into HTML page.  Inside the HTML every
  # source code line will be marked with ID, so that it can be linked
  # from documentation.
  class SourceFormatter
  # Writes HTML JavaScript/CSS source into HTML file.
  class SourceWriter

    # Initializes SourceFormatter to the directory where
    # HTML-formatted source files will be placed.
    #
    # formatter can be either :format_page or :format_pre; with the
    # first one the whole HTML page is created, otherwise just a
    # contents of <pre> element.
    def initialize(output_dir, formatter = :format_page)
    # Wrapper can be either :page or nil; with the first one the whole
    # HTML page is created, otherwise source is left as is.
    def initialize(output_dir, wrapper = :page)
      @output_dir = output_dir
      @formatter = formatter
      @wrapper = wrapper
    end

    # Converts source to HTML and writes into file in output
    # directory.  It returns the name of the file that it wrote.
    # Writes HTML into file in output directory.  It returns the name
    # of the file that it wrote.
    def write(source, filename)
      fname = uniq_html_filename(filename)
      File.open(fname, 'w') {|f| f.write(self.send(@formatter, source)) }
      File.open(fname, 'w') do |f|
        f.write(@wrapper ? wrap_page(source) : source)
      end
      fname
    end

@@ -40,8 +37,8 @@ module JsDuck
      @output_dir + "/" + File.basename(filename, ".js") + (nr > 0 ? nr.to_s : "") + ".html"
    end

    # Returns full source for HTML page
    def format_page(source)
    # Returns source wrapped inside HTML page
    def wrap_page(source)
      return <<-EOHTML
<!DOCTYPE html>
<html>
@@ -60,22 +57,12 @@ module JsDuck
  </script>
</head>
<body onload="prettyPrint(); highlight();">
  <pre class="prettyprint lang-js">#{format_pre(source)}</pre>
  <pre class="prettyprint lang-js">#{source}</pre>
</body>
</html>
      EOHTML
    end

    # Formats the contents of <pre>, wrapping each source code line
    # inside <span>.
    def format_pre(source)
      i = 0
      return source.lines.collect do |line|
        i += 1
        "<span id='line-#{i}'>#{CGI.escapeHTML(line)}</span>"
      end.join()
    end

  end

end
+20 −0
Original line number Diff line number Diff line
require "jsduck/source_formatter"
require "jsduck/source_writer"

describe JsDuck::SourceFormatter do
describe JsDuck::SourceWriter do

  before do
    @formatter = JsDuck::SourceFormatter.new("some/dir")
  end

  describe "#format_pre" do

    it "adds line numbers" do
      out = @formatter.format_pre("foo\nbar\nbaz")
      out.should =~ /line-1.*foo/
      out.should =~ /line-2.*bar/
      out.should =~ /line-3.*baz/
    end

    it "line is closed inside <span>" do
      out = @formatter.format_pre("blah")
      out.should =~ /<span id='line-1'>blah<\/span>/
    end

    it "escapes HTML" do
      out = @formatter.format_pre("foo <br> bar &")
      out.should =~ /foo &lt;br&gt; bar &amp;/
    end

    @formatter = JsDuck::SourceWriter.new("some/dir")
  end

  describe "#html_filename" do