jsduck 4.0.1 → 4.1.1

Sign up to get free protection for your applications and to get access to all the features.
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