jsduck 4.10.4 → 5.0.0.beta01

Sign up to get free protection for your applications and to get access to all the features.
Files changed (183) hide show
  1. data/.travis.yml +0 -1
  2. data/README.md +32 -6
  3. data/Rakefile +10 -18
  4. data/bin/compare +5 -5
  5. data/bin/jsduck +2 -3
  6. data/jsduck.gemspec +3 -4
  7. data/lib/jsduck/aggregator.rb +21 -80
  8. data/lib/jsduck/app.rb +7 -14
  9. data/lib/jsduck/app_data.rb +4 -5
  10. data/lib/jsduck/assets.rb +4 -7
  11. data/lib/jsduck/base_type.rb +53 -0
  12. data/lib/jsduck/batch_parser.rb +8 -87
  13. data/lib/jsduck/batch_processor.rb +77 -0
  14. data/lib/jsduck/categories/auto.rb +83 -0
  15. data/lib/jsduck/categories/class_name.rb +63 -0
  16. data/lib/jsduck/categories/factory.rb +113 -0
  17. data/lib/jsduck/categories/file.rb +75 -0
  18. data/lib/jsduck/class.rb +3 -9
  19. data/lib/jsduck/class_doc_expander.rb +1 -1
  20. data/lib/jsduck/css/lexer.rb +203 -0
  21. data/lib/jsduck/css/parser.rb +121 -0
  22. data/lib/jsduck/doc/comment.rb +40 -0
  23. data/lib/jsduck/doc/map.rb +23 -0
  24. data/lib/jsduck/doc/parser.rb +128 -0
  25. data/lib/jsduck/doc/processor.rb +52 -0
  26. data/lib/jsduck/doc/scanner.rb +76 -0
  27. data/lib/jsduck/doc/standard_tag_parser.rb +154 -0
  28. data/lib/jsduck/doc/subproperties.rb +64 -0
  29. data/lib/jsduck/docs_code_comparer.rb +31 -0
  30. data/lib/jsduck/export_writer.rb +2 -2
  31. data/lib/jsduck/exporter/app.rb +16 -4
  32. data/lib/jsduck/exporter/full.rb +2 -2
  33. data/lib/jsduck/format/batch.rb +58 -0
  34. data/lib/jsduck/format/class.rb +62 -0
  35. data/lib/jsduck/format/doc.rb +172 -0
  36. data/lib/jsduck/format/html_stack.rb +109 -0
  37. data/lib/jsduck/format/shortener.rb +55 -0
  38. data/lib/jsduck/format/subproperties.rb +64 -0
  39. data/lib/jsduck/guides.rb +32 -14
  40. data/lib/jsduck/index_html.rb +3 -1
  41. data/lib/jsduck/inline/auto_link.rb +2 -2
  42. data/lib/jsduck/inline/link.rb +4 -3
  43. data/lib/jsduck/inline/link_renderer.rb +2 -2
  44. data/lib/jsduck/inline/video.rb +8 -2
  45. data/lib/jsduck/js/ast.rb +361 -0
  46. data/lib/jsduck/js/esprima.rb +39 -0
  47. data/lib/jsduck/{esprima → js/esprima}/esprima.js +0 -0
  48. data/lib/jsduck/js/evaluator.rb +70 -0
  49. data/lib/jsduck/js/ext_patterns.rb +70 -0
  50. data/lib/jsduck/js/function.rb +206 -0
  51. data/lib/jsduck/js/node.rb +194 -0
  52. data/lib/jsduck/js/node_array.rb +36 -0
  53. data/lib/jsduck/js/parser.rb +223 -0
  54. data/lib/jsduck/js/serializer.rb +263 -0
  55. data/lib/jsduck/js/utils.rb +21 -0
  56. data/lib/jsduck/logger.rb +3 -13
  57. data/lib/jsduck/members_index.rb +3 -4
  58. data/lib/jsduck/merger.rb +25 -145
  59. data/lib/jsduck/options.rb +29 -132
  60. data/lib/jsduck/parser.rb +76 -0
  61. data/lib/jsduck/process/accessors.rb +133 -0
  62. data/lib/jsduck/process/circular_deps.rb +58 -0
  63. data/lib/jsduck/process/enums.rb +91 -0
  64. data/lib/jsduck/process/ext4_events.rb +43 -0
  65. data/lib/jsduck/process/global_members.rb +36 -0
  66. data/lib/jsduck/process/ignored_classes.rb +16 -0
  67. data/lib/jsduck/process/importer.rb +58 -0
  68. data/lib/jsduck/process/inherit_doc.rb +197 -0
  69. data/lib/jsduck/process/lint.rb +135 -0
  70. data/lib/jsduck/process/overrides.rb +99 -0
  71. data/lib/jsduck/process/return_values.rb +72 -0
  72. data/lib/jsduck/process/versions.rb +102 -0
  73. data/lib/jsduck/relations.rb +5 -0
  74. data/lib/jsduck/render/class.rb +144 -0
  75. data/lib/jsduck/render/sidebar.rb +97 -0
  76. data/lib/jsduck/render/signature.rb +94 -0
  77. data/lib/jsduck/render/subproperties.rb +99 -0
  78. data/lib/jsduck/render/tags.rb +38 -0
  79. data/lib/jsduck/search_data.rb +19 -13
  80. data/lib/jsduck/source/file.rb +8 -17
  81. data/lib/jsduck/tag/abstract.rb +4 -7
  82. data/lib/jsduck/tag/accessor.rb +10 -0
  83. data/lib/jsduck/tag/alias.rb +61 -0
  84. data/lib/jsduck/tag/alternate_class_names.rb +17 -0
  85. data/lib/jsduck/tag/aside.rb +28 -31
  86. data/lib/jsduck/tag/author.rb +9 -5
  87. data/lib/jsduck/tag/boolean_tag.rb +24 -0
  88. data/lib/jsduck/tag/cfg.rb +45 -0
  89. data/lib/jsduck/tag/chainable.rb +5 -7
  90. data/lib/jsduck/tag/class.rb +28 -0
  91. data/lib/jsduck/tag/class_list_tag.rb +40 -0
  92. data/lib/jsduck/tag/constructor.rb +24 -0
  93. data/lib/jsduck/tag/css_mixin.rb +17 -0
  94. data/lib/jsduck/tag/css_var.rb +29 -0
  95. data/lib/jsduck/tag/default.rb +31 -0
  96. data/lib/jsduck/tag/deprecated.rb +13 -27
  97. data/lib/jsduck/tag/deprecated_tag.rb +58 -0
  98. data/lib/jsduck/tag/doc.rb +32 -0
  99. data/lib/jsduck/tag/docauthor.rb +4 -5
  100. data/lib/jsduck/tag/enum.rb +70 -0
  101. data/lib/jsduck/tag/event.rb +28 -0
  102. data/lib/jsduck/tag/evented.rb +10 -0
  103. data/lib/jsduck/tag/extends.rb +45 -0
  104. data/lib/jsduck/tag/ftype.rb +18 -0
  105. data/lib/jsduck/tag/hide.rb +4 -11
  106. data/lib/jsduck/tag/ignore.rb +6 -7
  107. data/lib/jsduck/tag/inheritable.rb +10 -0
  108. data/lib/jsduck/tag/inheritdoc.rb +48 -0
  109. data/lib/jsduck/tag/markdown.rb +8 -6
  110. data/lib/jsduck/tag/member.rb +24 -0
  111. data/lib/jsduck/tag/method.rb +35 -0
  112. data/lib/jsduck/tag/mixins.rb +26 -0
  113. data/lib/jsduck/tag/name.rb +36 -0
  114. data/lib/jsduck/tag/new.rb +13 -27
  115. data/lib/jsduck/tag/override.rb +37 -0
  116. data/lib/jsduck/tag/overrides.rb +29 -0
  117. data/lib/jsduck/tag/param.rb +87 -0
  118. data/lib/jsduck/tag/preventable.rb +19 -10
  119. data/lib/jsduck/tag/private.rb +28 -13
  120. data/lib/jsduck/tag/property.rb +39 -0
  121. data/lib/jsduck/tag/protected.rb +5 -7
  122. data/lib/jsduck/tag/ptype.rb +18 -0
  123. data/lib/jsduck/tag/readonly.rb +4 -7
  124. data/lib/jsduck/tag/removed.rb +21 -29
  125. data/lib/jsduck/tag/required.rb +11 -9
  126. data/lib/jsduck/tag/requires.rb +12 -0
  127. data/lib/jsduck/tag/return.rb +47 -0
  128. data/lib/jsduck/tag/since.rb +19 -11
  129. data/lib/jsduck/tag/singleton.rb +15 -0
  130. data/lib/jsduck/tag/static.rb +5 -7
  131. data/lib/jsduck/tag/subproperties.rb +23 -0
  132. data/lib/jsduck/tag/tag.rb +208 -0
  133. data/lib/jsduck/tag/template.rb +14 -9
  134. data/lib/jsduck/tag/throws.rb +38 -0
  135. data/lib/jsduck/tag/type.rb +48 -0
  136. data/lib/jsduck/tag/uses.rb +12 -0
  137. data/lib/jsduck/tag/xtype.rb +30 -0
  138. data/lib/jsduck/tag_loader.rb +39 -0
  139. data/lib/jsduck/tag_registry.rb +189 -0
  140. data/lib/jsduck/type_parser.rb +3 -3
  141. data/lib/jsduck/web_writer.rb +2 -2
  142. data/lib/jsduck/welcome.rb +1 -1
  143. metadata +578 -538
  144. data/lib/jsduck/accessors.rb +0 -136
  145. data/lib/jsduck/ast.rb +0 -524
  146. data/lib/jsduck/auto_categories.rb +0 -80
  147. data/lib/jsduck/batch_formatter.rb +0 -60
  148. data/lib/jsduck/categories.rb +0 -73
  149. data/lib/jsduck/categories_class_name.rb +0 -37
  150. data/lib/jsduck/circular_deps.rb +0 -56
  151. data/lib/jsduck/class_formatter.rb +0 -102
  152. data/lib/jsduck/columns.rb +0 -56
  153. data/lib/jsduck/css_lexer.rb +0 -201
  154. data/lib/jsduck/css_parser.rb +0 -119
  155. data/lib/jsduck/doc_ast.rb +0 -319
  156. data/lib/jsduck/doc_formatter.rb +0 -142
  157. data/lib/jsduck/doc_parser.rb +0 -611
  158. data/lib/jsduck/doc_type.rb +0 -59
  159. data/lib/jsduck/enum.rb +0 -73
  160. data/lib/jsduck/esprima.rb +0 -51
  161. data/lib/jsduck/evaluator.rb +0 -69
  162. data/lib/jsduck/ext_patterns.rb +0 -58
  163. data/lib/jsduck/file_categories.rb +0 -76
  164. data/lib/jsduck/function_ast.rb +0 -206
  165. data/lib/jsduck/guide_anchors.rb +0 -32
  166. data/lib/jsduck/guide_toc.rb +0 -49
  167. data/lib/jsduck/html_stack.rb +0 -105
  168. data/lib/jsduck/importer.rb +0 -121
  169. data/lib/jsduck/inherit_doc.rb +0 -193
  170. data/lib/jsduck/js_parser.rb +0 -221
  171. data/lib/jsduck/lint.rb +0 -133
  172. data/lib/jsduck/meta_tag.rb +0 -88
  173. data/lib/jsduck/meta_tag_loader.rb +0 -67
  174. data/lib/jsduck/meta_tag_registry.rb +0 -111
  175. data/lib/jsduck/meta_tag_renderer.rb +0 -34
  176. data/lib/jsduck/news.rb +0 -128
  177. data/lib/jsduck/override.rb +0 -87
  178. data/lib/jsduck/renderer.rb +0 -361
  179. data/lib/jsduck/return_values.rb +0 -72
  180. data/lib/jsduck/serializer.rb +0 -262
  181. data/lib/jsduck/shortener.rb +0 -58
  182. data/lib/jsduck/signature_renderer.rb +0 -91
  183. data/lib/jsduck/source/file_parser.rb +0 -72
@@ -0,0 +1,31 @@
1
+ require 'jsduck/util/singleton'
2
+
3
+ module JsDuck
4
+
5
+ # Compares documentation and code hashes.
6
+ # Provides an utility method to help with merging.
7
+ class DocsCodeComparer
8
+ include Util::Singleton
9
+
10
+ # When docs has the key, returns value from there.
11
+ # When code has the key and matches with docs, gets value from there.
12
+ # Otherwise returns nil.
13
+ def merge_if_matches(key, docs, code)
14
+ if docs[key]
15
+ docs[key]
16
+ elsif code[key] && matches?(docs, code)
17
+ code[key]
18
+ else
19
+ nil
20
+ end
21
+ end
22
+
23
+ # True if the name detected from code matches with explicitly
24
+ # documented name. Also true when no explicit name documented.
25
+ def matches?(docs, code)
26
+ return docs[:name] == nil || docs[:name] == code[:name]
27
+ end
28
+
29
+ end
30
+
31
+ end
@@ -1,7 +1,7 @@
1
1
  require 'jsduck/util/stdout'
2
2
  require 'jsduck/exporter/full'
3
3
  require 'jsduck/exporter/examples'
4
- require 'jsduck/batch_formatter'
4
+ require 'jsduck/format/batch'
5
5
  require 'jsduck/class_writer'
6
6
  require 'jsduck/guide_writer'
7
7
  require 'fileutils'
@@ -54,7 +54,7 @@ module JsDuck
54
54
  end
55
55
 
56
56
  def format_classes
57
- BatchFormatter.format_all!(@relations, @assets, @opts)
57
+ Format::Batch.format_all!(@relations, @assets, @opts)
58
58
  end
59
59
 
60
60
  end
@@ -1,6 +1,6 @@
1
- require 'jsduck/renderer'
2
- require 'jsduck/doc_formatter'
1
+ require 'jsduck/render/class'
3
2
  require 'jsduck/exporter/full'
3
+ require 'jsduck/tag_registry'
4
4
 
5
5
  module JsDuck
6
6
  module Exporter
@@ -9,7 +9,7 @@ module JsDuck
9
9
  class App < Full
10
10
  def initialize(relations, opts)
11
11
  super(relations, opts)
12
- @renderer = Renderer.new(opts)
12
+ @renderer = Render::Class.new(opts)
13
13
  end
14
14
 
15
15
  # Returns compacted class data hash which contains an additional
@@ -28,6 +28,7 @@ module JsDuck
28
28
  cls[:members] = compact_members_group(cls[:members])
29
29
  cls[:statics] = compact_members_group(cls[:statics])
30
30
  cls[:files] = compact_files(cls[:files])
31
+ cls[:meta] = combine_meta(cls)
31
32
  cls
32
33
  end
33
34
 
@@ -41,12 +42,23 @@ module JsDuck
41
42
 
42
43
  def compact_member(m)
43
44
  m_copy = {}
44
- [:name, :tagname, :owner, :meta, :id].each do |key|
45
+ [:name, :tagname, :owner, :id].each do |key|
45
46
  m_copy[key] = m[key]
46
47
  end
48
+ m_copy[:meta] = combine_meta(m)
47
49
  m_copy
48
50
  end
49
51
 
52
+ # Add data for builtin tags with signatures to :meta field.
53
+ def combine_meta(m)
54
+ meta = {}
55
+ TagRegistry.signatures.each do |s|
56
+ name = s[:tagname]
57
+ meta[name] = m[name] if m[name]
58
+ end
59
+ meta
60
+ end
61
+
50
62
  # Remove full path from filename for privacy considerations as the
51
63
  # path can reveal information about the system where JSDuck was
52
64
  # run. The docs app doesn't need to have this information.
@@ -1,4 +1,4 @@
1
- require 'jsduck/class'
1
+ require 'jsduck/tag_registry'
2
2
 
3
3
  module JsDuck
4
4
  module Exporter
@@ -18,7 +18,7 @@ module JsDuck
18
18
 
19
19
  h[:members] = {}
20
20
  h[:statics] = {}
21
- Class.each_member_type do |tagname|
21
+ TagRegistry.member_type_names.each do |tagname|
22
22
  h[:members][tagname] = export_members(cls, {:tagname => tagname, :static => false})
23
23
  h[:statics][tagname] = export_members(cls, {:tagname => tagname, :static => true})
24
24
  end
@@ -0,0 +1,58 @@
1
+ require 'jsduck/util/parallel'
2
+ require 'jsduck/format/class'
3
+ require 'jsduck/format/doc'
4
+ require 'jsduck/img/dir_set'
5
+ require 'jsduck/logger'
6
+
7
+ module JsDuck
8
+ module Format
9
+
10
+ # Performs the formatting of the doc-object of all classes.
11
+ class Batch
12
+
13
+ # Formats all classes.
14
+ # Also registers found images in assets.
15
+ def self.format_all!(relations, assets, opts)
16
+ # Format all doc-objects in parallel
17
+ formatted_classes = Util::Parallel.map(relations.classes) do |cls|
18
+
19
+ files = cls[:files].map {|f| f[:filename] }.join(" ")
20
+ Logger.log("Markdown formatting #{cls[:name]}", files)
21
+
22
+ formatter = create_class_formatter(relations, opts)
23
+ begin
24
+ {
25
+ :doc => formatter.format(cls.internal_doc),
26
+ :images => formatter.images.all_used
27
+ }
28
+ rescue
29
+ Logger.fatal_backtrace("Error while formatting #{cls[:name]} #{files}", $!)
30
+ exit(1)
31
+ end
32
+ end
33
+
34
+ # Then merge the data back to classes sequentially
35
+ formatted_classes.each do |cls|
36
+ relations[cls[:doc][:name]].internal_doc = cls[:doc]
37
+ # Perform lookup of all the images again. We're really doing
38
+ # this work twice now, but as we usually don't have excessive
39
+ # amounts of images, the performance penalty should be minimal.
40
+ cls[:images].each {|img| assets.images.get(img[:filename]) }
41
+ end
42
+
43
+ # Print warnings for unused images
44
+ assets.images.report_unused
45
+ end
46
+
47
+ # Factory method to create new Format::Class instances.
48
+ def self.create_class_formatter(relations, opts)
49
+ doc_formatter = Format::Doc.new(relations, opts)
50
+ doc_formatter.images = Img::DirSet.new(opts.images, "images")
51
+
52
+ return Format::Class.new(doc_formatter)
53
+ end
54
+
55
+ end
56
+
57
+ end
58
+ end
@@ -0,0 +1,62 @@
1
+ require 'jsduck/tag_registry'
2
+
3
+ module JsDuck
4
+ module Format
5
+
6
+ # Performs documentation formatting of a class and all of its
7
+ # members.
8
+ #
9
+ # The actual work is delegated to the #format methods of Tag
10
+ # classes, to which we pass the Format::Doc instance which they
11
+ # can use to perform the formatting.
12
+ #
13
+ # The formatting done by #format methods usually consists of
14
+ # turning :doc properties of class from markdown to HTML,
15
+ # resolving @links, and converting type definitions to HTML.
16
+ class Class
17
+ def initialize(formatter)
18
+ @formatter = formatter
19
+ end
20
+
21
+ # Runs the formatter on doc object of a class.
22
+ # Accessed using Class#internal_doc
23
+ def format(cls)
24
+ @formatter.class_context = cls[:name]
25
+ @formatter.doc_context = cls[:files][0]
26
+
27
+ format_tags(cls)
28
+
29
+ # format all members (except hidden ones)
30
+ cls[:members].each {|m| format_member(m) unless m[:hide] }
31
+
32
+ cls
33
+ end
34
+
35
+ # Access to the Img::DirSet object inside doc-formatter
36
+ def images
37
+ @formatter.images
38
+ end
39
+
40
+ private
41
+
42
+ def format_member(m)
43
+ @formatter.doc_context = m[:files][0]
44
+
45
+ # Turn off type parsing for CSS vars and mixins
46
+ @formatter.skip_type_parsing = [:css_var, :css_mixin].include?(m[:tagname])
47
+
48
+ format_tags(m)
49
+ end
50
+
51
+ def format_tags(context)
52
+ TagRegistry.html_renderers.each do |tag|
53
+ if context[tag.tagname]
54
+ tag.format(context, @formatter)
55
+ end
56
+ end
57
+ end
58
+
59
+ end
60
+
61
+ end
62
+ end
@@ -0,0 +1,172 @@
1
+ require 'rubygems'
2
+ require 'strscan'
3
+ require 'rdiscount'
4
+ require 'jsduck/format/html_stack'
5
+ require 'jsduck/format/subproperties'
6
+ require 'jsduck/inline/link'
7
+ require 'jsduck/inline/auto_link'
8
+ require 'jsduck/inline/link_renderer'
9
+ require 'jsduck/inline/img'
10
+ require 'jsduck/inline/video'
11
+ require 'jsduck/inline/example'
12
+
13
+ module JsDuck
14
+ module Format
15
+
16
+ # Formats doc-comments
17
+ class Doc
18
+
19
+ # Creates a formatter configured with options originating from
20
+ # command line. For the actual effect of the options see
21
+ # Inline::* classes.
22
+ def initialize(relations={}, opts={})
23
+ @relations = relations
24
+ @opts = opts
25
+ @subproperties = Format::Subproperties.new(self)
26
+ @link_renderer = Inline::LinkRenderer.new(relations, opts)
27
+ @inline_link = Inline::Link.new(@link_renderer)
28
+ @auto_link = Inline::AutoLink.new(@link_renderer)
29
+ @inline_img = Inline::Img.new(opts)
30
+ @inline_video = Inline::Video.new(opts)
31
+ @inline_example = Inline::Example.new(opts)
32
+ @doc_context = {}
33
+ end
34
+
35
+ # Access to the relations object.
36
+ # (Used by TypeParser.)
37
+ attr_reader :relations
38
+
39
+ # Accessors to the images attribute of Inline::Img
40
+ def images=(images)
41
+ @inline_img.images = images
42
+ end
43
+ def images
44
+ @inline_img.images
45
+ end
46
+
47
+ # Sets up instance to work in context of particular class, so
48
+ # that when {@link #blah} is encountered it knows that
49
+ # Context#blah is meant.
50
+ def class_context=(cls)
51
+ @inline_link.class_context = cls
52
+ @auto_link.class_context = cls
53
+ end
54
+
55
+ # Sets up instance to work in context of particular doc object.
56
+ # Used for error reporting.
57
+ def doc_context=(doc)
58
+ @doc_context = doc
59
+ @inline_video.doc_context = doc
60
+ @inline_link.doc_context = doc
61
+ @auto_link.doc_context = doc
62
+ @inline_img.doc_context = doc
63
+ end
64
+
65
+ # Returns the current documentation context
66
+ def doc_context
67
+ @doc_context
68
+ end
69
+
70
+ # Formats doc-comment for placement into HTML.
71
+ # Renders it with Markdown-formatter and replaces @link-s.
72
+ def format(input)
73
+ # In ExtJS source "<pre>" is often at the end of paragraph, not
74
+ # on its own line. But in that case RDiscount doesn't recognize
75
+ # it as the beginning of <pre>-block and goes on parsing it as
76
+ # normal Markdown, which often causes nested <pre>-blocks.
77
+ #
78
+ # To prevent this, we always add extra newline before <pre>.
79
+ input.gsub!(/([^\n])<pre>/, "\\1\n<pre>")
80
+
81
+ # But we remove trailing newline after <pre> to prevent
82
+ # code-blocks beginning with empty line.
83
+ input.gsub!(/<pre>(<code>)?\n?/, "<pre>\\1")
84
+
85
+ replace(RDiscount.new(input).to_html)
86
+ end
87
+
88
+ # Replaces {@link} and {@img} tags, auto-generates links for
89
+ # recognized classnames.
90
+ #
91
+ # Replaces {@link Class#member link text} in given string with
92
+ # HTML from @link_tpl.
93
+ #
94
+ # Replaces {@img path/to/image.jpg Alt text} with HTML from @img_tpl.
95
+ #
96
+ # Adds 'inline-example' class to code examples beginning with @example.
97
+ #
98
+ # Additionally replaces strings recognized as ClassNames or
99
+ # #members with links to these classes or members. So one doesn't
100
+ # even need to use the @link tag to create a link.
101
+ def replace(input)
102
+ s = StringScanner.new(input)
103
+ out = ""
104
+
105
+ # Keep track of open HTML tags. We're not auto-detecting class
106
+ # names when inside <a>. Also we want to close down the unclosed
107
+ # tags.
108
+ tags = Format::HtmlStack.new(@opts[:ignore_html] || {}, @doc_context)
109
+
110
+ while !s.eos? do
111
+ if substitute = @inline_link.replace(s)
112
+ out += substitute
113
+ elsif substitute = @inline_img.replace(s)
114
+ out += substitute
115
+ elsif substitute = @inline_video.replace(s)
116
+ out += substitute
117
+ elsif s.check(/[{]/)
118
+ # There might still be "{" that doesn't begin {@link} or {@img} - ignore it
119
+ out += s.scan(/[{]/)
120
+ elsif substitute = @inline_example.replace(s)
121
+ tags.push_tag("pre")
122
+ tags.push_tag("code")
123
+ out += substitute
124
+ elsif s.check(/<\w/)
125
+ # Open HTML tag
126
+ out += tags.open(s)
127
+ elsif s.check(/<\/\w+>/)
128
+ # Close HTML tag
129
+ out += tags.close(s)
130
+ elsif s.check(/</)
131
+ # Ignore plain '<' char.
132
+ out += s.scan(/</)
133
+ else
134
+ # Replace class names in the following text up to next "<" or "{"
135
+ # but only when we're not inside <a>...</a>
136
+ text = s.scan(/[^{<]+/)
137
+ out += tags.open?("a") ? text : @auto_link.replace(text)
138
+ end
139
+ end
140
+
141
+ out
142
+ end
143
+
144
+ # Creates a link based on the link template.
145
+ def link(cls, member, anchor_text, type=nil, static=nil)
146
+ @link_renderer.link(cls, member, anchor_text, type, static)
147
+ end
148
+
149
+ # Turns type parsing on or off.
150
+ #
151
+ # Used to skipping parsing of CSS var and mixin types.
152
+ def skip_type_parsing=(skip)
153
+ @subproperties.skip_type_parsing = skip
154
+ end
155
+
156
+ # Recursively formats a subproperty.
157
+ # See Format::Subproperties#format for details.
158
+ def format_subproperty(item)
159
+ @subproperties.format(item)
160
+ end
161
+
162
+ # Parses and formats type definition.
163
+ # Returns HTML-rendering of the type.
164
+ # See Format::Subproperties#format_type for details.
165
+ def format_type(type)
166
+ @subproperties.format_type(type)
167
+ end
168
+
169
+ end
170
+
171
+ end
172
+ end
@@ -0,0 +1,109 @@
1
+ require 'jsduck/logger'
2
+
3
+ module JsDuck
4
+ module Format
5
+
6
+ # Tracks opening and closing of HTML tags, with the purpose of
7
+ # closing down the unfinished tags.
8
+ #
9
+ # See Format::Doc#replace for the use of this class.
10
+ class HtmlStack
11
+
12
+ # Initializes the stack with two optional parameters:
13
+ #
14
+ # @param ignore_html A hash of additional HTML tags that don't need closing.
15
+ # @param doc_context Filename and linenr of the current doc-comment.
16
+ def initialize(ignore_html={}, doc_context={})
17
+ @ignore_html = ignore_html
18
+ @doc_context = doc_context
19
+ @open_tags = []
20
+ end
21
+
22
+ # Scans an opening tag in HTML using the passed in StringScanner.
23
+ def open(s)
24
+ s.scan(/</) + push_tag(s.scan(/\w+/)) + s.scan_until(/>|\Z/)
25
+ end
26
+
27
+ # Scans a closing tag in HTML using the passed in StringScanner.
28
+ def close(s)
29
+ s.scan(/<\//)
30
+ tag = s.scan(/\w+/)
31
+ s.scan(/>/)
32
+
33
+ pop_tags(tag).map {|t| "</#{t}>" }.join
34
+ end
35
+
36
+ # Registers opening of a tag. Returns the tag.
37
+ def push_tag(tag)
38
+ @open_tags.push(tag) unless void?(tag)
39
+ tag
40
+ end
41
+
42
+ # True when the tag is currently open.
43
+ def open?(tag)
44
+ @open_tags.include?(tag)
45
+ end
46
+
47
+ private
48
+
49
+ # Registers closing of a tag. Returns all the tags that need to
50
+ # be closed at that point.
51
+ def pop_tags(tag)
52
+ if !@open_tags.include?(tag)
53
+ if @ignore_html[tag]
54
+ return [tag]
55
+ else
56
+ warn_unopened(tag)
57
+ return []
58
+ end
59
+ end
60
+
61
+ popped = []
62
+ begin
63
+ popped << t = @open_tags.pop
64
+ if t != tag
65
+ warn_unclosed(t)
66
+ end
67
+ end until t == tag
68
+
69
+ popped
70
+ end
71
+
72
+ def warn_unopened(*tags)
73
+ warn("Unopened HTML tag", tags)
74
+ end
75
+
76
+ def warn_unclosed(*tags)
77
+ warn("Unclosed HTML tag", tags)
78
+ end
79
+
80
+ def warn(msg, tags)
81
+ ctx = @doc_context
82
+ tag_list = tags.map {|tag| "<#{tag}>" }.join(", ")
83
+ Logger.warn(:html, "#{msg}: #{tag_list}", ctx[:filename], ctx[:linenr])
84
+ end
85
+
86
+ def void?(tag)
87
+ VOID_TAGS[tag] || @ignore_html[tag]
88
+ end
89
+
90
+ # Tags that don't require closing
91
+ VOID_TAGS = {
92
+ "base" => true,
93
+ "link" => true,
94
+ "meta" => true,
95
+ "hr" => true,
96
+ "br" => true,
97
+ "wbr" => true,
98
+ "area" => true,
99
+ "img" => true,
100
+ "param" => true,
101
+ "input" => true,
102
+ "isindex" => true,
103
+ "option" => true,
104
+ }
105
+
106
+ end
107
+
108
+ end
109
+ end