jsduck 4.0.1 → 4.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. data/Rakefile +14 -0
  2. data/esprima/esprima.js +210 -85
  3. data/jsduck.gemspec +3 -3
  4. data/lib/jsduck/accessors.rb +10 -8
  5. data/lib/jsduck/aggregator.rb +7 -7
  6. data/lib/jsduck/app.rb +24 -164
  7. data/lib/jsduck/app_data.rb +2 -4
  8. data/lib/jsduck/assets.rb +5 -2
  9. data/lib/jsduck/ast.rb +9 -4
  10. data/lib/jsduck/batch_formatter.rb +54 -0
  11. data/lib/jsduck/batch_parser.rb +106 -0
  12. data/lib/jsduck/categories.rb +5 -6
  13. data/lib/jsduck/class.rb +77 -239
  14. data/lib/jsduck/class_doc_expander.rb +0 -5
  15. data/lib/jsduck/class_formatter.rb +14 -10
  16. data/lib/jsduck/class_name.rb +23 -0
  17. data/lib/jsduck/class_writer.rb +9 -8
  18. data/lib/jsduck/doc_ast.rb +5 -6
  19. data/lib/jsduck/doc_formatter.rb +61 -272
  20. data/lib/jsduck/enum.rb +4 -4
  21. data/lib/jsduck/esprima.rb +10 -4
  22. data/lib/jsduck/examples.rb +5 -5
  23. data/lib/jsduck/export_writer.rb +62 -0
  24. data/lib/jsduck/exporter/app.rb +62 -0
  25. data/lib/jsduck/exporter/examples.rb +58 -0
  26. data/lib/jsduck/exporter/full.rb +60 -0
  27. data/lib/jsduck/file_categories.rb +7 -4
  28. data/lib/jsduck/function_ast.rb +99 -0
  29. data/lib/jsduck/grouped_asset.rb +27 -16
  30. data/lib/jsduck/guide_writer.rb +8 -7
  31. data/lib/jsduck/guides.rb +31 -29
  32. data/lib/jsduck/icons.rb +12 -1
  33. data/lib/jsduck/images.rb +3 -3
  34. data/lib/jsduck/importer.rb +7 -7
  35. data/lib/jsduck/index_html.rb +20 -6
  36. data/lib/jsduck/inherit_doc.rb +9 -12
  37. data/lib/jsduck/inline/example.rb +42 -0
  38. data/lib/jsduck/inline/img.rb +55 -0
  39. data/lib/jsduck/inline/link.rb +227 -0
  40. data/lib/jsduck/inline/video.rb +67 -0
  41. data/lib/jsduck/inline_examples.rb +7 -7
  42. data/lib/jsduck/js_parser.rb +5 -4
  43. data/lib/jsduck/lint.rb +14 -2
  44. data/lib/jsduck/logger.rb +5 -6
  45. data/lib/jsduck/members_index.rb +132 -0
  46. data/lib/jsduck/merger.rb +3 -9
  47. data/lib/jsduck/options.rb +39 -41
  48. data/lib/jsduck/override.rb +3 -7
  49. data/lib/jsduck/relations.rb +9 -9
  50. data/lib/jsduck/renderer.rb +3 -3
  51. data/lib/jsduck/return_values.rb +72 -0
  52. data/lib/jsduck/search_data.rb +16 -20
  53. data/lib/jsduck/shortener.rb +58 -0
  54. data/lib/jsduck/signature_renderer.rb +1 -2
  55. data/lib/jsduck/source/file.rb +98 -0
  56. data/lib/jsduck/source/file_parser.rb +72 -0
  57. data/lib/jsduck/source/writer.rb +89 -0
  58. data/lib/jsduck/tag/aside.rb +1 -1
  59. data/lib/jsduck/tag/since.rb +1 -1
  60. data/lib/jsduck/template_dir.rb +2 -2
  61. data/lib/jsduck/util/html.rb +27 -0
  62. data/lib/jsduck/util/io.rb +32 -0
  63. data/lib/jsduck/util/json.rb +60 -0
  64. data/lib/jsduck/util/null_object.rb +23 -0
  65. data/lib/jsduck/util/os.rb +14 -0
  66. data/lib/jsduck/util/parallel.rb +34 -0
  67. data/lib/jsduck/util/singleton.rb +35 -0
  68. data/lib/jsduck/util/stdout.rb +33 -0
  69. data/lib/jsduck/videos.rb +5 -5
  70. data/lib/jsduck/web_writer.rb +79 -0
  71. data/lib/jsduck/welcome.rb +6 -6
  72. data/spec/class_factory.rb +20 -0
  73. metadata +32 -20
  74. data/lib/jsduck/api_exporter.rb +0 -48
  75. data/lib/jsduck/app_exporter.rb +0 -60
  76. data/lib/jsduck/examples_exporter.rb +0 -56
  77. data/lib/jsduck/full_exporter.rb +0 -35
  78. data/lib/jsduck/html.rb +0 -25
  79. data/lib/jsduck/inline_img.rb +0 -53
  80. data/lib/jsduck/inline_video.rb +0 -58
  81. data/lib/jsduck/io.rb +0 -30
  82. data/lib/jsduck/json_duck.rb +0 -52
  83. data/lib/jsduck/lexer.rb +0 -251
  84. data/lib/jsduck/null_object.rb +0 -19
  85. data/lib/jsduck/os.rb +0 -11
  86. data/lib/jsduck/parallel_wrap.rb +0 -32
  87. data/lib/jsduck/source_file.rb +0 -97
  88. data/lib/jsduck/source_file_parser.rb +0 -70
  89. data/lib/jsduck/source_writer.rb +0 -87
  90. data/lib/jsduck/stats.rb +0 -103
  91. data/lib/jsduck/stdout.rb +0 -31
@@ -27,7 +27,7 @@ module JsDuck
27
27
  target = @classes_hash[override[:override]]
28
28
  unless target
29
29
  ctx = override[:files][0]
30
- return Logger.instance.warn(:extend, "Class #{override[:override]} not found", ctx[:filename], ctx[:linenr])
30
+ return Logger.warn(:extend, "Class #{override[:override]} not found", ctx[:filename], ctx[:linenr])
31
31
  end
32
32
 
33
33
  # Combine comments of classes
@@ -64,15 +64,11 @@ module JsDuck
64
64
  # helpers
65
65
 
66
66
  def each_member(cls)
67
- [:members, :statics].each do |category|
68
- cls[category].each_pair do |key, members|
69
- members.each {|m| yield m }
70
- end
71
- end
67
+ cls[:members].each {|m| yield m }
72
68
  end
73
69
 
74
70
  def add_member(cls, m)
75
- cls[m[:static] ? :statics : :members][m[:tagname]] << m
71
+ cls[:members] << m
76
72
  end
77
73
 
78
74
  def add_doc(m, doc)
@@ -20,7 +20,7 @@ module JsDuck
20
20
  # mixins and subclasses will depend on that.
21
21
  @lookup = {}
22
22
  @classes.each do |cls|
23
- @lookup[cls.full_name] = cls
23
+ @lookup[cls[:name]] = cls
24
24
  (cls[:alternateClassNames] || []).each do |alt_name|
25
25
  @lookup[alt_name] = cls
26
26
  end
@@ -58,31 +58,31 @@ module JsDuck
58
58
  def reg_subclasses(cls)
59
59
  if !cls.parent
60
60
  # do nothing
61
- elsif @subs[cls.parent.full_name]
62
- @subs[cls.parent.full_name] << cls
61
+ elsif @subs[cls.parent[:name]]
62
+ @subs[cls.parent[:name]] << cls
63
63
  else
64
- @subs[cls.parent.full_name] = [cls]
64
+ @subs[cls.parent[:name]] = [cls]
65
65
  end
66
66
  end
67
67
 
68
68
  # Returns subclasses of particular class, empty array if none
69
69
  def subclasses(cls)
70
- @subs[cls.full_name] || []
70
+ @subs[cls[:name]] || []
71
71
  end
72
72
 
73
73
  def reg_mixed_into(cls)
74
74
  cls.mixins.each do |mix|
75
- if @mixes[mix.full_name]
76
- @mixes[mix.full_name] << cls
75
+ if @mixes[mix[:name]]
76
+ @mixes[mix[:name]] << cls
77
77
  else
78
- @mixes[mix.full_name] = [cls]
78
+ @mixes[mix[:name]] = [cls]
79
79
  end
80
80
  end
81
81
  end
82
82
 
83
83
  # Returns classes having particular mixin, empty array if none
84
84
  def mixed_into(cls)
85
- @mixes[cls.full_name] || []
85
+ @mixes[cls[:name]] || []
86
86
  end
87
87
  end
88
88
 
@@ -1,4 +1,4 @@
1
- require 'jsduck/html'
1
+ require 'jsduck/util/html'
2
2
  require 'jsduck/meta_tag_renderer'
3
3
  require 'jsduck/signature_renderer'
4
4
 
@@ -252,7 +252,7 @@ module JsDuck
252
252
  doc << m[:doc]
253
253
 
254
254
  if m[:default] && m[:default] != "undefined"
255
- doc << "<p>Defaults to: <code>" + HTML.escape(m[:default]) + "</code></p>"
255
+ doc << "<p>Defaults to: <code>" + Util::HTML.escape(m[:default]) + "</code></p>"
256
256
  end
257
257
 
258
258
  doc << render_meta_data(m[:html_meta], :bottom)
@@ -318,7 +318,7 @@ module JsDuck
318
318
  p[:optional] ? " (optional)" : "",
319
319
  "<div class='sub-desc'>",
320
320
  p[:doc],
321
- p[:default] ? "<p>Defaults to: <code>#{HTML.escape(p[:default])}</code></p>" : "",
321
+ p[:default] ? "<p>Defaults to: <code>#{Util::HTML.escape(p[:default])}</code></p>" : "",
322
322
  p[:properties] && p[:properties].length > 0 ? render_params_and_return(p) : "",
323
323
  "</div>",
324
324
  "</li>",
@@ -0,0 +1,72 @@
1
+ module JsDuck
2
+
3
+ # Auto-detector return values and @chainable tags.
4
+ #
5
+ # Adds @chainable tag when doc-comment contains @return {OwnerClass}
6
+ # this. Also the other way around: when @chainable found, adds
7
+ # appropriate @return.
8
+ class ReturnValues
9
+ # Only this static method of this class should be called.
10
+ def self.auto_detect(relations)
11
+ ReturnValues.new(relations).process_all!
12
+ end
13
+
14
+ def initialize(relations)
15
+ @relations = relations
16
+ @cls = nil
17
+ end
18
+
19
+ def process_all!
20
+ @relations.each do |cls|
21
+ @cls = cls
22
+ cls.find_members(:tagname => :method, :local => true, :static => false).each do |m|
23
+ process(m)
24
+ end
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def process(m)
31
+ if constructor?(m)
32
+ add_return_new(m)
33
+ elsif chainable?(m)
34
+ add_return_this(m)
35
+ elsif returns_this?(m)
36
+ add_chainable(m)
37
+ end
38
+ end
39
+
40
+ def constructor?(m)
41
+ m[:name] == "constructor"
42
+ end
43
+
44
+ def chainable?(m)
45
+ m[:meta][:chainable]
46
+ end
47
+
48
+ def returns_this?(m)
49
+ m[:return] && m[:return][:type] == @cls[:name] && m[:return][:doc] =~ /\Athis\b/
50
+ end
51
+
52
+ def add_chainable(m)
53
+ m[:meta][:chainable] = true
54
+ end
55
+
56
+ def add_return_this(m)
57
+ if m[:return][:type] == "undefined" && m[:return][:doc] == ""
58
+ m[:return] = {:type => @cls[:name], :doc => "this"}
59
+ end
60
+ end
61
+
62
+ def add_return_new(m)
63
+ if m[:return][:type] == "undefined"
64
+ # Create a whole new :return hash.
65
+ # If we were to just change the :type field it would modify
66
+ # the type of all the inherited constructor docs.
67
+ m[:return] = {:type => @cls[:name], :doc => m[:return][:doc]}
68
+ end
69
+ end
70
+ end
71
+
72
+ end
@@ -1,3 +1,5 @@
1
+ require 'jsduck/icons'
2
+ require 'jsduck/class_name'
1
3
 
2
4
  module JsDuck
3
5
 
@@ -22,15 +24,9 @@ module JsDuck
22
24
  end
23
25
  end
24
26
 
25
- [:members, :statics].each do |group|
26
- cls[group].each_key do |type|
27
- cls.members(type, group).each do |m|
28
- # skip inherited items and constructors
29
- if m[:owner] == cls.full_name && m[:name] != cls.short_name
30
- list << member_node(m, cls)
31
- end
32
- end
33
- end
27
+ # add all local members, but skip constructors
28
+ cls[:members].each do |m|
29
+ list << member_node(m, cls) unless m[:name] == ClassName.short(cls[:name])
34
30
  end
35
31
  end
36
32
 
@@ -49,8 +45,8 @@ module JsDuck
49
45
  return {
50
46
  :name => name,
51
47
  :fullName => alias_display_name(key)+": "+name,
52
- :icon => cls.icon + "-redirect",
53
- :url => "#!/api/" + cls.full_name,
48
+ :icon => Icons::class_icon(cls) + "-redirect",
49
+ :url => "#!/api/" + cls[:name],
54
50
  :meta => cls[:meta],
55
51
  :sort => 0,
56
52
  }
@@ -58,10 +54,10 @@ module JsDuck
58
54
 
59
55
  def class_node(cls)
60
56
  return {
61
- :name => cls.short_name,
62
- :fullName => cls.full_name,
63
- :icon => cls.icon,
64
- :url => "#!/api/" + cls.full_name,
57
+ :name => ClassName.short(cls[:name]),
58
+ :fullName => cls[:name],
59
+ :icon => Icons::class_icon(cls),
60
+ :url => "#!/api/" + cls[:name],
65
61
  :meta => cls[:meta],
66
62
  :sort => 1,
67
63
  }
@@ -69,11 +65,11 @@ module JsDuck
69
65
 
70
66
  def alt_node(name, cls)
71
67
  return {
72
- :name => Class.short_name(name),
68
+ :name => ClassName.short(name),
73
69
  :fullName => name,
74
70
  :type => :class,
75
- :icon => cls.icon + "-redirect",
76
- :url => "#!/api/" + cls.full_name,
71
+ :icon => Icons::class_icon(cls) + "-redirect",
72
+ :url => "#!/api/" + cls[:name],
77
73
  :meta => cls[:meta],
78
74
  :sort => 2,
79
75
  }
@@ -82,9 +78,9 @@ module JsDuck
82
78
  def member_node(member, cls)
83
79
  return {
84
80
  :name => member[:name],
85
- :fullName => cls.full_name + "." + member[:name],
81
+ :fullName => cls[:name] + "." + member[:name],
86
82
  :icon => "icon-" + member[:tagname].to_s,
87
- :url => "#!/api/" + cls.full_name + "-" + member[:id],
83
+ :url => "#!/api/" + cls[:name] + "-" + member[:id],
88
84
  :meta => member[:meta],
89
85
  :sort => 3,
90
86
  }
@@ -0,0 +1,58 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'jsduck/util/html'
3
+ require 'jsduck/util/singleton'
4
+
5
+ module JsDuck
6
+
7
+ # Little helper for shortening text
8
+ class Shortener
9
+ include Util::Singleton
10
+
11
+ # Maximum length for text that doesn't get shortened.
12
+ # The accessor is used for testing purposes only.
13
+ attr_accessor :max_length
14
+
15
+ def initialize
16
+ @max_length = 120
17
+ end
18
+
19
+ # Shortens text
20
+ #
21
+ # 116 chars is also where ext-doc makes its cut, but unlike
22
+ # ext-doc we only make the cut when there's more than 120 chars.
23
+ #
24
+ # This way we don't get stupid expansions like:
25
+ #
26
+ # Blah blah blah some text...
27
+ #
28
+ # expanding to:
29
+ #
30
+ # Blah blah blah some text.
31
+ #
32
+ def shorten(input)
33
+ sent = first_sentence(Util::HTML.strip_tags(input).strip)
34
+ # Use u-modifier to correctly count multi-byte characters
35
+ chars = sent.scan(/./mu)
36
+ if chars.length > @max_length
37
+ chars[0..(@max_length-4)].join + "..."
38
+ else
39
+ sent + " ..."
40
+ end
41
+ end
42
+
43
+ # Returns the first sentence inside a string.
44
+ def first_sentence(str)
45
+ str.sub(/\A(.+?(\.|。))\s.*\Z/mu, "\\1")
46
+ end
47
+
48
+ # Returns true when input should get shortened.
49
+ def too_long?(input)
50
+ stripped = Util::HTML.strip_tags(input).strip
51
+ # for sentence v/s full - compare byte length
52
+ # for full v/s max - compare char length
53
+ first_sentence(stripped).length < stripped.length || stripped.scan(/./mu).length > @max_length
54
+ end
55
+
56
+ end
57
+
58
+ end
@@ -71,8 +71,7 @@ module JsDuck
71
71
  end
72
72
 
73
73
  def render_single_param(param)
74
- p = param[:html_type] + " " + param[:name]
75
- param[:optional] ? "["+p+"]" : p
74
+ param[:optional] ? "["+param[:name]+"]" : param[:name]
76
75
  end
77
76
 
78
77
  def render_return
@@ -0,0 +1,98 @@
1
+ require 'jsduck/source/file_parser'
2
+ require 'jsduck/util/html'
3
+
4
+ module JsDuck
5
+ module Source
6
+
7
+ # Represents one JavaScript or CSS source file.
8
+ #
9
+ # The filename parameter determines whether it's parsed as
10
+ # JavaScript (the default) or CSS.
11
+ class File
12
+ attr_reader :filename
13
+ attr_reader :contents
14
+ attr_reader :docs
15
+ attr_reader :html_filename
16
+
17
+ def initialize(contents, filename="", options={})
18
+ @contents = contents
19
+ @filename = filename
20
+ @html_filename = ""
21
+ @links = {}
22
+
23
+ @docs = Source::FileParser.new.parse(@contents, @filename, options)
24
+
25
+ @docs.map do |docset|
26
+ link(docset[:linenr], docset)
27
+ end
28
+ end
29
+
30
+ # loops through each doc-object in file
31
+ def each(&block)
32
+ @docs.each(&block)
33
+ end
34
+
35
+ # Sets the html filename of this file,
36
+ # updating also all doc-objects linking this file
37
+ def html_filename=(html_filename)
38
+ @html_filename = html_filename
39
+ @links.each_value do |line|
40
+ line.each do |link|
41
+ link[:file][:html_filename] = @html_filename
42
+ link[:file][:href] = @html_filename + "#" + id(link[:doc])
43
+ end
44
+ end
45
+ end
46
+
47
+ # Returns source code as HTML with lines starting doc-comments specially marked.
48
+ def to_html
49
+ linenr = 0
50
+ lines = []
51
+ # Use #each_line instead of #lines to support Ruby 1.6
52
+ @contents.each_line do |line|
53
+ linenr += 1;
54
+ line = Util::HTML.escape(line)
55
+ # wrap the line in as many spans as there are links to this line number.
56
+ if @links[linenr]
57
+ @links[linenr].each do |link|
58
+ line = "<span id='#{id(link[:doc])}'>#{line}</span>"
59
+ end
60
+ end
61
+ lines << line
62
+ end
63
+ lines.join()
64
+ end
65
+
66
+ def id(doc)
67
+ if doc[:tagname] == :class
68
+ doc[:name].gsub(/\./, '-')
69
+ else
70
+ # when creation of global class is skipped,
71
+ # this owner property can be nil.
72
+ (doc[:owner] || "global").gsub(/\./, '-') + "-" + doc[:id]
73
+ end
74
+ end
75
+
76
+ private
77
+
78
+ # Creates two-way link between sourcefile and doc-object.
79
+ # If doc-object is class, links also the contained cfgs and constructor.
80
+ # Returns the modified doc-object after done.
81
+ def link(linenr, doc)
82
+ @links[linenr] = [] unless @links[linenr]
83
+ file = {
84
+ :filename => @filename,
85
+ :linenr => linenr,
86
+ }
87
+ @links[linenr] << {:doc => doc, :file => file}
88
+ doc[:files] = [file]
89
+ if doc[:tagname] == :class
90
+ doc[:members].each {|m| link(linenr, m) }
91
+ end
92
+ doc
93
+ end
94
+
95
+ end
96
+
97
+ end
98
+ end
@@ -0,0 +1,72 @@
1
+ require 'jsduck/js_parser'
2
+ require 'jsduck/css_parser'
3
+ require 'jsduck/doc_parser'
4
+ require 'jsduck/merger'
5
+ require 'jsduck/ast'
6
+ require 'jsduck/doc_type'
7
+ require 'jsduck/doc_ast'
8
+ require 'jsduck/class_doc_expander'
9
+
10
+ module JsDuck
11
+ module Source
12
+
13
+ # Performs the actual parsing of CSS or JS source.
14
+ #
15
+ # This is the class that brings together all the different steps of
16
+ # parsing the source.
17
+ class FileParser
18
+
19
+ def initialize
20
+ @doc_type = DocType.new
21
+ @doc_parser = DocParser.new
22
+ @class_doc_expander = ClassDocExpander.new
23
+ @doc_ast = DocAst.new
24
+ @merger = Merger.new
25
+ end
26
+
27
+ # Parses file into final docset that can be fed into Aggregator
28
+ def parse(contents, filename="", options={})
29
+ @doc_ast.filename = filename
30
+
31
+ parse_js_or_css(contents, filename, options).map do |docset|
32
+ expand(docset)
33
+ end.flatten.map do |docset|
34
+ merge(docset)
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ # Parses the file depending on filename as JS or CSS
41
+ def parse_js_or_css(contents, filename, options)
42
+ if filename =~ /\.s?css$/
43
+ docs = CssParser.new(contents, options).parse
44
+ else
45
+ docs = JsParser.new(contents, options).parse
46
+ docs = Ast.new(docs, options).detect_all!
47
+ end
48
+ end
49
+
50
+ # Parses the docs, detects tagname and expands class docset
51
+ def expand(docset)
52
+ docset[:comment] = @doc_parser.parse(docset[:comment])
53
+ docset[:tagname] = @doc_type.detect(docset[:comment], docset[:code])
54
+
55
+ if docset[:tagname] == :class
56
+ @class_doc_expander.expand(docset)
57
+ else
58
+ docset
59
+ end
60
+ end
61
+
62
+ # Merges comment and code parts of docset
63
+ def merge(docset)
64
+ @doc_ast.linenr = docset[:linenr]
65
+ docset[:comment] = @doc_ast.detect(docset[:tagname], docset[:comment])
66
+
67
+ @merger.merge(docset)
68
+ end
69
+ end
70
+
71
+ end
72
+ end