Commit 0aef16ed authored by Rene Saarsoo's avatar Rene Saarsoo
Browse files

Extract Format::Subproperties from Format::Class.

The Format::Class is now much-much cleaner.

To avoid passing the Relations object explicitly around, add an
accessor to Format::Doc - so we can just pass an instance of the
formatter around and TypeParser can get the relations object
from the formatter, which it gets passed anyway and which already
includes the relations.
parent ccc0cdd9
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -49,7 +49,7 @@ module JsDuck
        doc_formatter = Format::Doc.new(relations, opts)
        doc_formatter.images = Img::DirSet.new(opts.images, "images")

        class_formatter = Format::Class.new(relations, doc_formatter)
        class_formatter = Format::Class.new(doc_formatter)
        # Don't format types when exporting
        class_formatter.include_types = !opts.export

+19 −34
Original line number Diff line number Diff line
require 'jsduck/type_parser'
require 'jsduck/logger'
require 'jsduck/tag_registry'
require 'jsduck/util/html'
require 'jsduck/format/subproperties'

module JsDuck
  module Format
@@ -12,8 +10,7 @@ module JsDuck
      # Set to false to disable HTML-formatting of type definitions.
      attr_accessor :include_types

      def initialize(relations, formatter)
        @relations = relations
      def initialize(formatter)
        @formatter = formatter
        @include_types = true
      end
@@ -21,12 +18,14 @@ module JsDuck
      # Runs the formatter on doc object of a class.
      # Accessed using Class#internal_doc
      def format(cls)
        @cls = cls
        @formatter.class_context = cls[:name]
        @formatter.doc_context = cls[:files][0]

        format_tags(cls)

        # format all members (except hidden ones)
        cls[:members] = cls[:members].map {|m| m[:hide] ? m : format_member(m)  }
        cls[:members].each {|m| format_member(m) unless m[:hide] }

        cls
      end

@@ -39,39 +38,25 @@ module JsDuck

      def format_member(m)
        @formatter.doc_context = m[:files][0]

        format_tags(m)

        # We don't validate and format CSS var and mixin type definitions
        is_css_tag = m[:tagname] == :css_var || m[:tagname] == :css_mixin
        subs = make_subproperties_formatter(m)

        m[:html_type] = (@include_types && !is_css_tag) ? format_type(m[:type]) : m[:type] if m[:type]
        m[:params] = m[:params].map {|p| format_item(p, is_css_tag) } if m[:params]
        m[:return] = format_item(m[:return], is_css_tag) if m[:return]
        m[:throws] = m[:throws].map {|t| format_item(t, is_css_tag) } if m[:throws]
        m[:properties] = m[:properties].map {|b| format_item(b, is_css_tag) } if m[:properties]
        m
        m[:html_type] = subs.format_type(m[:type]) if m[:type]
        m[:params].each {|p| subs.format(p) } if m[:params]
        subs.format(m[:return]) if m[:return]
        m[:throws].each {|t| subs.format(t) } if m[:throws]
        m[:properties].each {|p| subs.format(p) } if m[:properties]
      end

      def format_item(it, is_css_tag)
        it[:doc] = @formatter.format(it[:doc]) if it[:doc]
        it[:html_type] = (@include_types && !is_css_tag) ? format_type(it[:type]) : it[:type] if it[:type]
        it[:properties] = it[:properties].map {|s| format_item(s, is_css_tag) } if it[:properties]
        it
      end
      def make_subproperties_formatter(m)
        # We don't validate and format CSS var and mixin type definitions
        is_css_tag = m[:tagname] == :css_var || m[:tagname] == :css_mixin
        # Also don't check types when @include_types setting is explicitly turned off
        check_types = @include_types && !is_css_tag

      def format_type(type)
        tp = TypeParser.new(@relations, @formatter)
        if tp.parse(type)
          tp.out
        else
          context = @formatter.doc_context
          if tp.error == :syntax
            Logger.warn(:type_syntax, "Incorrect type syntax #{type}", context[:filename], context[:linenr])
          else
            Logger.warn(:type_name, "Unknown type #{type}", context[:filename], context[:linenr])
          end
          Util::HTML.escape(type)
        end
        return Format::Subproperties.new(@formatter, check_types)
      end

      def format_tags(context)
+5 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ module JsDuck
      # command line.  For the actual effect of the options see
      # Inline::* classes.
      def initialize(relations={}, opts={})
        @relations = relations
        @opts = opts
        @link_renderer = Inline::LinkRenderer.new(relations, opts)
        @inline_link = Inline::Link.new(@link_renderer)
@@ -29,6 +30,10 @@ module JsDuck
        @doc_context = {}
      end

      # Access to the relations object.
      # (Used by TypeParser.)
      attr_reader :relations

      # Accessors to the images attribute of Inline::Img
      def images=(images)
        @inline_img.images = images
+60 −0
Original line number Diff line number Diff line
require 'jsduck/util/html'
require 'jsduck/logger'
require 'jsduck/type_parser'

module JsDuck
  module Format

    # Helper for recursively formatting subproperties.
    class Subproperties

      def initialize(formatter, format_types=false)
        @formatter = formatter
        @format_types = format_types
      end

      # Takes a hash of param, return value, throws value or subproperty.
      #
      # - Markdown-formats the :doc field in it.
      # - Parses the :type field and saves HTML to :html_type.
      # - Recursively does the same with all items in :properties field.
      #
      def format(item)
        item[:doc] = @formatter.format(item[:doc]) if item[:doc]

        if item[:type]
          item[:html_type] = format_type(item[:type])
        end

        if item[:properties]
          item[:properties].each {|p| format(p) }
        end
      end

      # Formats the given type definition string using TypeParser.
      #
      # - On success returns HTML-version of the type definition.
      # - On failure logs error and returns the type string with only HTML escaped.
      #
      def format_type(type)
        # Skip the formatting entirely when type-parsing is turned off.
        return Util::HTML.escape(type) unless @format_types

        tp = TypeParser.new(@formatter.relations, @formatter)
        if tp.parse(type)
          tp.out
        else
          context = @formatter.doc_context
          if tp.error == :syntax
            Logger.warn(:type_syntax, "Incorrect type syntax #{type}", context[:filename], context[:linenr])
          else
            Logger.warn(:type_name, "Unknown type #{type}", context[:filename], context[:linenr])
          end
          Util::HTML.escape(type)
        end
      end

    end

  end
end