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
@@ -0,0 +1,42 @@
1
+ module JsDuck
2
+ module Inline
3
+
4
+ # Implementation of @example tag.
5
+ #
6
+ # Looks for @example tag at the beginning of code blocks. When
7
+ # found, adds an "inline-example" CSS class to the <pre> element.
8
+ #
9
+ # Unlike other Inline:: classes this doesn't implement an
10
+ # {@example} tag as could be expected. But it fits nicely along
11
+ # with other inline tags as it's processed inside DocFormatter, so
12
+ # it mostly fits here along with the others.
13
+ #
14
+ class Example
15
+ # Constructor takes opts parameter for consistency with other
16
+ # JsDuck::Inline::* classes.
17
+ def initialize(opts={})
18
+ @re = /<pre><code>\s*@example( +[^\n]*)?\s+/m
19
+ end
20
+
21
+ # Takes StringScanner instance.
22
+ #
23
+ # Looks for "<pre><code>@example" at the current scan pointer
24
+ # position, when found, moves scan pointer forward and performs
25
+ # the apporpriate replacement.
26
+ def replace(input)
27
+ if input.check(@re)
28
+ # Match possible classnames following @example and add them
29
+ # as CSS classes inside <pre> element.
30
+ input.scan(@re) =~ @re
31
+ css_classes = ($1 || "").strip
32
+
33
+ return "<pre class='inline-example #{css_classes}'><code>"
34
+ else
35
+ false
36
+ end
37
+ end
38
+
39
+ end
40
+
41
+ end
42
+ end
@@ -0,0 +1,55 @@
1
+ require 'jsduck/util/html'
2
+ require 'jsduck/logger'
3
+
4
+ module JsDuck
5
+ module Inline
6
+
7
+ # Implementation of inline tag {@img}
8
+ class Img
9
+ # Base path to prefix images from {@img} tags.
10
+ # Defaults to no prefix.
11
+ attr_accessor :base_path
12
+
13
+ # This will hold list of all image paths gathered from {@img} tags.
14
+ attr_accessor :images
15
+
16
+ def initialize(opts={})
17
+ @tpl = opts[:img_tpl] || '<img src="%u" alt="%a"/>'
18
+
19
+ @re = /\{@img\s+(\S*?)(?:\s+(.+?))?\}/m
20
+
21
+ @base_path = nil
22
+ @images = []
23
+ end
24
+
25
+ # Takes StringScanner instance.
26
+ #
27
+ # Looks for inline tag at the current scan pointer position, when
28
+ # found, moves scan pointer forward and performs the apporpriate
29
+ # replacement.
30
+ def replace(input)
31
+ if input.check(@re)
32
+ input.scan(@re).sub(@re) { apply_tpl($1, $2) }
33
+ else
34
+ false
35
+ end
36
+ end
37
+
38
+ # applies the image template
39
+ def apply_tpl(url, alt_text)
40
+ @images << url
41
+ @tpl.gsub(/(%\w)/) do
42
+ case $1
43
+ when '%u'
44
+ @base_path ? (@base_path + "/" + url) : url
45
+ when '%a'
46
+ Util::HTML.escape(alt_text||"")
47
+ else
48
+ $1
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ end
55
+ end
@@ -0,0 +1,227 @@
1
+ require 'jsduck/util/html'
2
+ require 'jsduck/logger'
3
+
4
+ module JsDuck
5
+ module Inline
6
+
7
+ # Implementation of inline tag {@link}
8
+ #
9
+ # It also takes care of the auto-detection of links in text
10
+ # through the #create_magic_links method.
11
+ class Link
12
+ # Sets up instance to work in context of particular class, so
13
+ # that when {@link #blah} is encountered it knows that
14
+ # Context#blah is meant.
15
+ attr_accessor :class_context
16
+
17
+ # Sets up instance to work in context of particular doc object.
18
+ # Used for error reporting.
19
+ attr_accessor :doc_context
20
+
21
+ # JsDuck::Relations for looking up class names.
22
+ #
23
+ # When auto-creating class links from CamelCased names found from
24
+ # text, we check the relations object to see if a class with that
25
+ # name actually exists.
26
+ attr_accessor :relations
27
+
28
+ def initialize(opts={})
29
+ @class_context = ""
30
+ @doc_context = {}
31
+ @relations = {}
32
+
33
+ # Template HTML that replaces {@link Class#member anchor text}.
34
+ # Can contain placeholders:
35
+ #
36
+ # %c - full class name (e.g. "Ext.Panel")
37
+ # %m - class member name prefixed with member type (e.g. "method-urlEncode")
38
+ # %# - inserts "#" if member name present
39
+ # %- - inserts "-" if member name present
40
+ # %a - anchor text for link
41
+ @tpl = opts[:link_tpl] || '<a href="%c%#%m">%a</a>'
42
+
43
+ @re = /\{@link\s+(\S*?)(?:\s+(.+?))?\}/m
44
+ end
45
+
46
+ # Takes StringScanner instance.
47
+ #
48
+ # Looks for inline tag at the current scan pointer position, when
49
+ # found, moves scan pointer forward and performs the apporpriate
50
+ # replacement.
51
+ def replace(input)
52
+ if input.check(@re)
53
+ input.scan(@re).sub(@re) { apply_tpl($1, $2, $&) }
54
+ else
55
+ false
56
+ end
57
+ end
58
+
59
+ # applies the link template
60
+ def apply_tpl(target, text, full_link)
61
+ if target =~ /^(.*)#(static-)?(?:(cfg|property|method|event|css_var|css_mixin)-)?(.*)$/
62
+ cls = $1.empty? ? @class_context : $1
63
+ static = $2 ? true : nil
64
+ type = $3 ? $3.intern : nil
65
+ member = $4
66
+ else
67
+ cls = target
68
+ static = nil
69
+ type = false
70
+ member = false
71
+ end
72
+
73
+ # Construct link text
74
+ if text
75
+ text = text
76
+ elsif member
77
+ text = (cls == @class_context) ? member : (cls + "." + member)
78
+ else
79
+ text = cls
80
+ end
81
+
82
+ file = @doc_context[:filename]
83
+ line = @doc_context[:linenr]
84
+ if !@relations[cls]
85
+ Logger.warn(:link, "#{full_link} links to non-existing class", file, line)
86
+ return text
87
+ elsif member
88
+ ms = find_members(cls, {:name => member, :tagname => type, :static => static})
89
+ if ms.length == 0
90
+ Logger.warn(:link, "#{full_link} links to non-existing member", file, line)
91
+ return text
92
+ end
93
+
94
+ if ms.length > 1
95
+ # When multiple public members, see if there remains just
96
+ # one when we ignore the static members. If there's more,
97
+ # report ambiguity. If there's only static members, also
98
+ # report ambiguity.
99
+ instance_ms = ms.find_all {|m| !m[:meta][:static] }
100
+ if instance_ms.length > 1
101
+ alternatives = instance_ms.map {|m| "#{m[:tagname]} in #{m[:owner]}" }.join(", ")
102
+ Logger.warn(:link_ambiguous, "#{full_link} is ambiguous: "+alternatives, file, line)
103
+ elsif instance_ms.length == 0
104
+ static_ms = ms.find_all {|m| m[:meta][:static] }
105
+ alternatives = static_ms.map {|m| "static " + m[:tagname].to_s }.join(", ")
106
+ Logger.warn(:link_ambiguous, "#{full_link} is ambiguous: "+alternatives, file, line)
107
+ end
108
+ end
109
+
110
+ return link(cls, member, text, type, static)
111
+ else
112
+ return link(cls, false, text)
113
+ end
114
+ end
115
+
116
+ # Looks input text for patterns like:
117
+ #
118
+ # My.ClassName
119
+ # MyClass#method
120
+ # #someProperty
121
+ #
122
+ # and converts them to links, as if they were surrounded with
123
+ # {@link} tag. One notable exception is that Foo is not created to
124
+ # link, even when Foo class exists, but Foo.Bar is. This is to
125
+ # avoid turning normal words into links. For example:
126
+ #
127
+ # Math involves a lot of numbers. Ext JS is a JavaScript framework.
128
+ #
129
+ # In these sentences we don't want to link "Math" and "Ext" to the
130
+ # corresponding JS classes. And that's why we auto-link only
131
+ # class names containing a dot "."
132
+ #
133
+ def create_magic_links(input)
134
+ cls_re = "([A-Z][A-Za-z0-9.]*[A-Za-z0-9])"
135
+ member_re = "(?:#([A-Za-z0-9]+))"
136
+
137
+ input.gsub(/\b#{cls_re}#{member_re}?\b|#{member_re}\b/m) do
138
+ replace_magic_link($1, $2 || $3)
139
+ end
140
+ end
141
+
142
+ def replace_magic_link(cls, member)
143
+ if cls && member
144
+ if @relations[cls] && get_matching_member(cls, {:name => member})
145
+ return link(cls, member, cls+"."+member)
146
+ else
147
+ warn_magic_link("#{cls}##{member} links to non-existing " + (@relations[cls] ? "member" : "class"))
148
+ end
149
+ elsif cls && cls =~ /\./
150
+ if @relations[cls]
151
+ return link(cls, nil, cls)
152
+ else
153
+ cls2, member2 = split_to_cls_and_member(cls)
154
+ if @relations[cls2] && get_matching_member(cls2, {:name => member2})
155
+ return link(cls2, member2, cls2+"."+member2)
156
+ elsif cls =~ /\.(js|css|html|php)\Z/
157
+ # Ignore common filenames
158
+ else
159
+ warn_magic_link("#{cls} links to non-existing class")
160
+ end
161
+ end
162
+ elsif !cls && member
163
+ if get_matching_member(@class_context, {:name => member})
164
+ return link(@class_context, member, member)
165
+ elsif member =~ /\A([A-F0-9]{3}|[A-F0-9]{6})\Z/i || member =~ /\A[0-9]/
166
+ # Ignore HEX color codes and
167
+ # member names beginning with number
168
+ else
169
+ warn_magic_link("##{member} links to non-existing member")
170
+ end
171
+ end
172
+
173
+ return "#{cls}#{member ? '#' : ''}#{member}"
174
+ end
175
+
176
+ def split_to_cls_and_member(str)
177
+ parts = str.split(/\./)
178
+ return [parts.slice(0, parts.length-1).join("."), parts.last]
179
+ end
180
+
181
+ def warn_magic_link(msg)
182
+ Logger.warn(:link_auto, msg, @doc_context[:filename], @doc_context[:linenr])
183
+ end
184
+
185
+ # applies the link template
186
+ def link(cls, member, anchor_text, type=nil, static=nil)
187
+ # Use the canonical class name for link (not some alternateClassName)
188
+ cls = @relations[cls][:name]
189
+ # prepend type name to member name
190
+ member = member && get_matching_member(cls, {:name => member, :tagname => type, :static => static})
191
+
192
+ @tpl.gsub(/(%[\w#-])/) do
193
+ case $1
194
+ when '%c'
195
+ cls
196
+ when '%m'
197
+ member ? member[:id] : ""
198
+ when '%#'
199
+ member ? "#" : ""
200
+ when '%-'
201
+ member ? "-" : ""
202
+ when '%a'
203
+ Util::HTML.escape(anchor_text||"")
204
+ else
205
+ $1
206
+ end
207
+ end
208
+ end
209
+
210
+ def get_matching_member(cls, query)
211
+ ms = find_members(cls, query).find_all {|m| !m[:private] }
212
+ if ms.length > 1
213
+ instance_ms = ms.find_all {|m| !m[:meta][:static] }
214
+ instance_ms.length > 0 ? instance_ms[0] : ms.find_all {|m| m[:meta][:static] }[0]
215
+ else
216
+ ms[0]
217
+ end
218
+ end
219
+
220
+ def find_members(cls, query)
221
+ @relations[cls] ? @relations[cls].find_members(query) : []
222
+ end
223
+
224
+ end
225
+
226
+ end
227
+ end
@@ -0,0 +1,67 @@
1
+ require 'jsduck/util/html'
2
+ require 'jsduck/logger'
3
+
4
+ module JsDuck
5
+ module Inline
6
+
7
+ # Implementation of inline tag {@video}
8
+ class Video
9
+ # Sets up instance to work in context of particular doc object.
10
+ # Used for error reporting.
11
+ attr_accessor :doc_context
12
+
13
+ def initialize(opts={})
14
+ @doc_context = {}
15
+
16
+ @templates = {
17
+ "html5" => '<video src="%u">%a</video>',
18
+ "vimeo" => [
19
+ '<p><object width="640" height="360">',
20
+ '<param name="allowfullscreen" value="true" />',
21
+ '<param name="allowscriptaccess" value="always" />',
22
+ '<param name="flashvars" value="api=1" />',
23
+ '<param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=%u&amp;server=vimeo.com&amp;color=4CC208&amp;fullscreen=1" />',
24
+ '<embed src="http://vimeo.com/moogaloop.swf?clip_id=%u&amp;server=vimeo.com&amp;color=4CC208&amp;fullscreen=1" ',
25
+ 'type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="640" height="360"></embed>',
26
+ '</object></p>',
27
+ ].join
28
+ }
29
+
30
+ @re = /\{@video\s+(\w+)\s+(\S*?)(?:\s+(.+?))?\}/m
31
+ end
32
+
33
+ # Takes StringScanner instance.
34
+ #
35
+ # Looks for inline tag at the current scan pointer position, when
36
+ # found, moves scan pointer forward and performs the apporpriate
37
+ # replacement.
38
+ def replace(input)
39
+ if input.check(@re)
40
+ input.scan(@re).sub(@re) { apply_tpl($1, $2, $3) }
41
+ else
42
+ false
43
+ end
44
+ end
45
+
46
+ # applies the video template of the specified type
47
+ def apply_tpl(type, url, alt_text)
48
+ unless @templates.has_key?(type)
49
+ ctx = @doc_context
50
+ Logger.warn(nil, "Unknown video type #{type}", ctx[:filename], ctx[:linenr])
51
+ end
52
+
53
+ @templates[type].gsub(/(%\w)/) do
54
+ case $1
55
+ when '%u'
56
+ url
57
+ when '%a'
58
+ Util::HTML.escape(alt_text||"")
59
+ else
60
+ $1
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+ end
67
+ end
@@ -1,5 +1,5 @@
1
- require 'jsduck/json_duck'
2
- require 'jsduck/html'
1
+ require 'jsduck/util/json'
2
+ require 'jsduck/util/html'
3
3
 
4
4
  module JsDuck
5
5
 
@@ -16,9 +16,9 @@ module JsDuck
16
16
  relations.each do |cls|
17
17
  extract(cls[:doc]).each_with_index do |ex, i|
18
18
  @examples << {
19
- :id => cls.full_name + "-" + i.to_s,
20
- :name => cls.full_name + " example #" + (i+1).to_s,
21
- :href => '#!/api/' + cls.full_name,
19
+ :id => cls[:name] + "-" + i.to_s,
20
+ :name => cls[:name] + " example #" + (i+1).to_s,
21
+ :href => '#!/api/' + cls[:name],
22
22
  :code => ex[:code],
23
23
  :options => ex[:options],
24
24
  }
@@ -47,7 +47,7 @@ module JsDuck
47
47
 
48
48
  # Writes all found examples to .js file
49
49
  def write(filename)
50
- JsonDuck.write_jsonp(filename, "__inline_examples__", @examples)
50
+ Util::Json.write_jsonp(filename, "__inline_examples__", @examples)
51
51
  end
52
52
 
53
53
  # Extracts inline examples from HTML
@@ -65,7 +65,7 @@ module JsDuck
65
65
  ex = s.scan_until(@end_example_re).sub(@end_example_re, '')
66
66
 
67
67
  examples << {
68
- :code => HTML.unescape(HTML.strip_tags(ex)),
68
+ :code => Util::HTML.unescape(Util::HTML.strip_tags(ex)),
69
69
  :options => options,
70
70
  }
71
71
  else
@@ -25,7 +25,7 @@ module JsDuck
25
25
  # }
26
26
  #
27
27
  def parse
28
- @ast = Esprima.instance.parse(@input)
28
+ @ast = Esprima.parse(@input)
29
29
 
30
30
  @ast["comments"] = merge_comments(@ast["comments"])
31
31
  locate_comments
@@ -62,10 +62,11 @@ module JsDuck
62
62
  end
63
63
 
64
64
  # Two comments can be merged if they are both line-comments and
65
- # they are separated only by whitespace (but no newlines)
65
+ # they are separated only by whitespace (only one newline at the
66
+ # end of the first comment is allowed)
66
67
  def mergeable?(c1, c2)
67
68
  if c1["type"] == "Line" && c2["type"] == "Line"
68
- /\A[ \t]*\Z/ =~ @input.slice((c1["range"][1])..(c2["range"][0]-1))
69
+ /\A(\r\n|\n|\r)?[ \t]*\Z/ =~ @input.slice((c1["range"][1])..(c2["range"][0]-1))
69
70
  else
70
71
  false
71
72
  end
@@ -156,7 +157,7 @@ module JsDuck
156
157
  properties = NODE_TYPES[node["type"]]
157
158
 
158
159
  unless properties
159
- Logger.instance.fatal("Unknown node type: "+node["type"])
160
+ Logger.fatal("Unknown node type: "+node["type"])
160
161
  exit(1)
161
162
  end
162
163