jsduck 5.0.0.beta2 → 5.0.0.beta3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. data/Rakefile +14 -4
  2. data/bin/jsduck +3 -1
  3. data/jsduck.gemspec +2 -2
  4. data/lib/jsduck/app.rb +8 -0
  5. data/lib/jsduck/assets.rb +3 -0
  6. data/lib/jsduck/batch_processor.rb +2 -0
  7. data/lib/jsduck/categories/class_name.rb +2 -26
  8. data/lib/jsduck/categories/factory.rb +5 -43
  9. data/lib/jsduck/columns.rb +56 -0
  10. data/lib/jsduck/doc/delimited_parser.rb +105 -0
  11. data/lib/jsduck/doc/scanner.rb +2 -1
  12. data/lib/jsduck/doc/standard_tag_parser.rb +37 -71
  13. data/lib/jsduck/guide_anchors.rb +32 -0
  14. data/lib/jsduck/guide_toc.rb +49 -0
  15. data/lib/jsduck/guides.rb +14 -32
  16. data/lib/jsduck/inline/video.rb +2 -8
  17. data/lib/jsduck/js/ast.rb +13 -305
  18. data/lib/jsduck/js/class.rb +245 -0
  19. data/lib/jsduck/js/event.rb +34 -0
  20. data/lib/jsduck/js/fires.rb +42 -0
  21. data/lib/jsduck/js/method.rb +94 -0
  22. data/lib/jsduck/js/method_calls.rb +40 -0
  23. data/lib/jsduck/js/node.rb +29 -0
  24. data/lib/jsduck/js/property.rb +64 -0
  25. data/lib/jsduck/js/{function.rb → returns.rb} +8 -3
  26. data/lib/jsduck/js/scoped_traverser.rb +42 -0
  27. data/lib/jsduck/logger.rb +13 -1
  28. data/lib/jsduck/merger.rb +34 -27
  29. data/lib/jsduck/news.rb +128 -0
  30. data/lib/jsduck/options.rb +59 -2
  31. data/lib/jsduck/params_merger.rb +47 -0
  32. data/lib/jsduck/process/accessors.rb +8 -2
  33. data/lib/jsduck/process/fires.rb +71 -0
  34. data/lib/jsduck/process/importer.rb +19 -1
  35. data/lib/jsduck/render/class.rb +11 -4
  36. data/lib/jsduck/render/signature_util.rb +14 -0
  37. data/lib/jsduck/tag/alias.rb +0 -20
  38. data/lib/jsduck/tag/alternate_class_names.rb +0 -5
  39. data/lib/jsduck/tag/cfg.rb +30 -5
  40. data/lib/jsduck/tag/class.rb +45 -2
  41. data/lib/jsduck/tag/css_mixin.rb +8 -4
  42. data/lib/jsduck/tag/css_var.rb +26 -5
  43. data/lib/jsduck/tag/default.rb +2 -8
  44. data/lib/jsduck/tag/enum.rb +7 -10
  45. data/lib/jsduck/tag/event.rb +12 -4
  46. data/lib/jsduck/tag/extends.rb +0 -6
  47. data/lib/jsduck/tag/fires.rb +53 -0
  48. data/lib/jsduck/tag/icons/cfg.png +0 -0
  49. data/lib/jsduck/tag/icons/css_mixin.png +0 -0
  50. data/lib/jsduck/tag/icons/css_var.png +0 -0
  51. data/lib/jsduck/tag/icons/event.png +0 -0
  52. data/lib/jsduck/tag/icons/method.png +0 -0
  53. data/lib/jsduck/tag/icons/property.png +0 -0
  54. data/lib/jsduck/tag/member_tag.rb +130 -0
  55. data/lib/jsduck/tag/method.rb +44 -4
  56. data/lib/jsduck/tag/param.rb +8 -60
  57. data/lib/jsduck/tag/property.rb +28 -5
  58. data/lib/jsduck/tag/tag.rb +3 -75
  59. data/lib/jsduck/tag/type.rb +1 -11
  60. data/lib/jsduck/tag_registry.rb +6 -48
  61. data/lib/jsduck/web/css.rb +8 -1
  62. data/lib/jsduck/web/data.rb +2 -1
  63. data/lib/jsduck/web/index_html.rb +1 -0
  64. data/lib/jsduck/web/member_icons.rb +43 -0
  65. data/lib/jsduck/web/search.rb +3 -2
  66. data/lib/jsduck/web/writer.rb +8 -0
  67. metadata +31 -27
  68. data/lib/jsduck/docs_code_comparer.rb +0 -44
  69. data/lib/jsduck/render/signature.rb +0 -94
  70. data/lib/jsduck/tag/autodetected.rb +0 -21
  71. data/lib/jsduck/tag/name.rb +0 -36
@@ -0,0 +1,245 @@
1
+ require "jsduck/util/singleton"
2
+ require "jsduck/tag_registry"
3
+ require "jsduck/js/method"
4
+ require "jsduck/js/property"
5
+
6
+ module JsDuck
7
+ module Js
8
+
9
+ # Auto-detection of classes.
10
+ class Class
11
+ include Util::Singleton
12
+
13
+ # Checks if AST node is a class, and if so, returns doc-hash
14
+ # with clas name and various auto-detected attributes.
15
+ # When not a class returns nil.
16
+ def detect(ast, docs)
17
+ @docs = docs
18
+
19
+ exp = ast.expression_statement? ? ast["expression"] : nil
20
+ var = ast.variable_declaration? ? ast["declarations"][0] : nil
21
+
22
+ # Ext.define("Class", {})
23
+ if exp && exp.ext_define?
24
+ make(exp["arguments"][0].to_value, exp)
25
+
26
+ # Ext.override(Class, {})
27
+ elsif exp && exp.ext_override?
28
+ make("", exp)
29
+
30
+ # foo = Ext.extend(Parent, {})
31
+ elsif exp && exp.assignment_expression? && exp["right"].ext_extend?
32
+ make(exp["left"].to_s, exp["right"])
33
+
34
+ # Foo = ...
35
+ elsif exp && exp.assignment_expression? && class_name?(exp["left"].to_s)
36
+ make(exp["left"].to_s, exp["right"])
37
+
38
+ # var foo = Ext.extend(Parent, {})
39
+ elsif var && var["init"].ext_extend?
40
+ make(var["id"].to_s, var["init"])
41
+
42
+ # var Foo = ...
43
+ elsif var && class_name?(var["id"].to_s)
44
+ make(var["id"].to_s, var["right"])
45
+
46
+ # function Foo() {}
47
+ elsif ast.function? && class_name?(ast["id"].to_s || "")
48
+ make(ast["id"].to_s)
49
+
50
+ # { ... }
51
+ elsif ast.object_expression?
52
+ make("", ast)
53
+
54
+ else
55
+ nil
56
+ end
57
+ end
58
+
59
+ # Produces a doc-hash for a class.
60
+ def make(name, ast=nil)
61
+ cls = {
62
+ :tagname => :class,
63
+ :name => name,
64
+ }
65
+
66
+ # apply information from Ext.extend, Ext.define, or {}
67
+ if ast
68
+ if ast.ext_define?
69
+ detect_ext_define(cls, ast)
70
+ elsif ast.ext_extend?
71
+ detect_ext_something(:extends, cls, ast)
72
+ elsif ast.ext_override?
73
+ detect_ext_something(:override, cls, ast)
74
+ elsif ast.object_expression?
75
+ detect_class_members_from_object(cls, ast)
76
+ elsif ast.array_expression?
77
+ detect_class_members_from_array(cls, ast)
78
+ end
79
+ end
80
+
81
+ return cls
82
+ end
83
+
84
+ private
85
+
86
+ # Class name begins with upcase char
87
+ def class_name?(name)
88
+ return name.split(/\./).last =~ /\A[A-Z]/
89
+ end
90
+
91
+ # Detection of Ext.extend() or Ext.override().
92
+ # The type parameter must be correspondingly either :extend or :override.
93
+ def detect_ext_something(type, cls, ast)
94
+ args = ast["arguments"]
95
+ cls[type] = args[0].to_s
96
+ if args.length == 2 && args[1].object_expression?
97
+ detect_class_members_from_object(cls, args[1])
98
+ end
99
+ end
100
+
101
+ # Inspects Ext.define() and copies detected properties over to the
102
+ # given cls Hash
103
+ def detect_ext_define(cls, ast)
104
+ # defaults
105
+ cls.merge!(TagRegistry.ext_define_defaults)
106
+ cls[:members] = []
107
+ cls[:code_type] = :ext_define
108
+
109
+ ast["arguments"][1].each_property do |key, value, pair|
110
+ if tag = TagRegistry.get_by_ext_define_pattern(key)
111
+ tag.parse_ext_define(cls, value)
112
+ else
113
+ case key
114
+ when "config"
115
+ cls[:members] += make_configs(value, {:accessor => true})
116
+ when "cachedConfig"
117
+ cls[:members] += make_configs(value, {:accessor => true})
118
+ when "eventedConfig"
119
+ cls[:members] += make_configs(value, {:accessor => true, :evented => true})
120
+ when "statics"
121
+ cls[:members] += make_statics(value)
122
+ when "inheritableStatics"
123
+ cls[:members] += make_statics(value, {:inheritable => true})
124
+ else
125
+ detect_method_or_property(cls, key, value, pair)
126
+ end
127
+ end
128
+ end
129
+ end
130
+
131
+ # Detects class members from object literal
132
+ def detect_class_members_from_object(cls, ast)
133
+ cls[:members] = []
134
+ ast.each_property do |key, value, pair|
135
+ detect_method_or_property(cls, key, value, pair)
136
+ end
137
+ end
138
+
139
+ # Detects class members from array literal
140
+ def detect_class_members_from_array(cls, ast)
141
+ cls[:members] = []
142
+
143
+ # This will most likely be an @enum class, in which case the
144
+ # enum will be for documentation purposes only.
145
+ cls[:enum] = {:doc_only => true}
146
+
147
+ ast["elements"].each do |el|
148
+ detect_method_or_property(cls, el.key_value, el, el)
149
+ end
150
+ end
151
+
152
+ # Detects item in object literal either as method or property
153
+ def detect_method_or_property(cls, key, value, pair)
154
+ if value.function?
155
+ m = make_method(key, value)
156
+ cls[:members] << m if apply_autodetected(m, pair)
157
+ else
158
+ p = make_property(key, value)
159
+ cls[:members] << p if apply_autodetected(p, pair)
160
+ end
161
+ end
162
+
163
+ def make_configs(ast, defaults={})
164
+ configs = []
165
+
166
+ ast.each_property do |name, value, pair|
167
+ cfg = make_property(name, value)
168
+ cfg[:tagname] = :cfg
169
+ cfg.merge!(defaults)
170
+ configs << cfg if apply_autodetected(cfg, pair)
171
+ end
172
+
173
+ configs
174
+ end
175
+
176
+ def make_statics(ast, defaults={})
177
+ statics = []
178
+
179
+ ast.each_property do |name, value, pair|
180
+ if value.function?
181
+ s = make_method(name, value)
182
+ else
183
+ s = make_property(name, value)
184
+ end
185
+
186
+ s[:static] = true
187
+ s.merge!(defaults)
188
+
189
+ statics << s if apply_autodetected(s, pair, defaults[:inheritable])
190
+ end
191
+
192
+ statics
193
+ end
194
+
195
+ # Sets auto-detection related properties :autodetected and
196
+ # :inheritdoc on the given member Hash.
197
+ #
198
+ # When member has a comment, adds code to the related docset and
199
+ # returns false.
200
+ #
201
+ # Otherwise detects the line number of member and returns true.
202
+ def apply_autodetected(m, ast, inheritable=true)
203
+ docset = find_docset(ast.raw)
204
+
205
+ if !docset || docset[:type] != :doc_comment
206
+ if inheritable
207
+ m[:inheritdoc] = {}
208
+ else
209
+ m[:private] = true
210
+ end
211
+ m[:autodetected] = {:tagname => m[:tagname]}
212
+ end
213
+
214
+ if docset
215
+ docset[:code] = m
216
+ return false
217
+ else
218
+ m[:linenr] = ast.linenr
219
+ return true
220
+ end
221
+ end
222
+
223
+ # Looks up docset associated with given AST node.
224
+ # A dead-stupid and -slow implementation, but works.
225
+ #
226
+ # The comparison needs to be done between raw AST nodes - multiple
227
+ # Node instances can be created to wrap a single raw AST node,
228
+ # and they will then not be equal.
229
+ def find_docset(raw_ast)
230
+ @docs.find do |docset|
231
+ docset[:code] == raw_ast
232
+ end
233
+ end
234
+
235
+ def make_method(name, ast)
236
+ Js::Method.make(name, ast)
237
+ end
238
+
239
+ def make_property(name=nil, ast=nil)
240
+ Js::Property.make(name, ast)
241
+ end
242
+
243
+ end
244
+ end
245
+ end
@@ -0,0 +1,34 @@
1
+ require "jsduck/util/singleton"
2
+
3
+ module JsDuck
4
+ module Js
5
+
6
+ # Auto-detection of events.
7
+ class Event
8
+ include Util::Singleton
9
+
10
+ # Checks if AST node is an event, and if so, returns doc-hash
11
+ # with event name and various auto-detected properties.
12
+ # When not an event returns nil.
13
+ def detect(ast)
14
+ exp = ast.expression_statement? ? ast["expression"] : nil
15
+
16
+ # this.fireEvent("foo", ...)
17
+ if exp && exp.fire_event?
18
+ make(exp["arguments"][0].to_value)
19
+ else
20
+ nil
21
+ end
22
+ end
23
+
24
+ # Produces a doc-hash for an event.
25
+ def make(name)
26
+ return {
27
+ :tagname => :event,
28
+ :name => name,
29
+ }
30
+ end
31
+
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,42 @@
1
+ require "jsduck/util/singleton"
2
+ require "jsduck/js/scoped_traverser"
3
+
4
+ module JsDuck
5
+ module Js
6
+
7
+ # Looks the AST of a FunctionDeclaration or FunctionExpression for
8
+ # uses of this.fireEvent().
9
+ class Fires
10
+ include Util::Singleton
11
+
12
+ # Returns array of event names fired by the given function.
13
+ # When no events fired, empty array is returned.
14
+ def detect(function_node)
15
+ @traverser = Js::ScopedTraverser.new
16
+
17
+ events = []
18
+ @traverser.traverse(function_node["body"]) do |node|
19
+ if fire_event?(node)
20
+ events << node["arguments"][0].to_value
21
+ end
22
+ end
23
+
24
+ events.sort.uniq
25
+ end
26
+
27
+ private
28
+
29
+ # True when node is this.fireEvent("name") call.
30
+ # Also true for me.fireEvent() when me == this.
31
+ def fire_event?(node)
32
+ node.call_expression? &&
33
+ node["callee"].member_expression? &&
34
+ @traverser.this?(node["callee"]["object"].to_s) &&
35
+ node["callee"]["property"].to_s == "fireEvent" &&
36
+ node["arguments"].length > 0 &&
37
+ node["arguments"][0].value_type == "String"
38
+ end
39
+
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,94 @@
1
+ require "jsduck/util/singleton"
2
+ require "jsduck/js/returns"
3
+ require "jsduck/js/fires"
4
+ require "jsduck/js/method_calls"
5
+
6
+ module JsDuck
7
+ module Js
8
+
9
+ # Auto-detection of methods.
10
+ class Method
11
+ include Util::Singleton
12
+
13
+ # Checks if AST node is a method, and if so, returns doc-hash
14
+ # with method name and various auto-detected properties.
15
+ # When not a method returns nil.
16
+ def detect(ast)
17
+ exp = ast.expression_statement? ? ast["expression"] : nil
18
+ var = ast.variable_declaration? ? ast["declarations"][0] : nil
19
+
20
+ # function foo() {}
21
+ if ast.function?
22
+ make(ast["id"].to_s || "", ast)
23
+
24
+ # foo = function() {}
25
+ elsif exp && exp.assignment_expression? && exp["right"].function?
26
+ make(exp["left"].to_s, exp["right"])
27
+
28
+ # var foo = function() {}
29
+ elsif var && var["init"] && var["init"].function?
30
+ make(var["id"].to_s, var["init"])
31
+
32
+ # (function() {})
33
+ elsif exp && exp.function?
34
+ make(exp["id"].to_s || "", exp)
35
+
36
+ # foo: function() {}
37
+ elsif ast.property? && ast["value"].function?
38
+ make(ast["key"].key_value, ast["value"])
39
+
40
+ else
41
+ nil
42
+ end
43
+ end
44
+
45
+ # Performs the auto-detection on function AST node and produces
46
+ # a doc-hash.
47
+ def make(name, ast)
48
+ if proper_function?(ast)
49
+ return {
50
+ :tagname => :method,
51
+ :name => name,
52
+ :params => arr_to_nil(params(ast)),
53
+ :chainable => chainable?(ast) && name != "constructor",
54
+ :fires => arr_to_nil(fires(ast)),
55
+ :method_calls => arr_to_nil(method_calls(ast)),
56
+ }
57
+ else
58
+ return {
59
+ :tagname => :method,
60
+ :name => name,
61
+ }
62
+ end
63
+ end
64
+
65
+ private
66
+
67
+ def proper_function?(ast)
68
+ ast.function? && !ast.ext_empty_fn?
69
+ end
70
+
71
+ # replaces empty array with nil
72
+ def arr_to_nil(arr)
73
+ arr.length == 0 ? nil : arr
74
+ end
75
+
76
+ def params(ast)
77
+ ast["params"].map {|p| {:name => p.to_s} }
78
+ end
79
+
80
+ def chainable?(ast)
81
+ Js::Returns.chainable?(ast.raw)
82
+ end
83
+
84
+ def fires(ast)
85
+ Js::Fires.detect(ast)
86
+ end
87
+
88
+ def method_calls(ast)
89
+ Js::MethodCalls.detect(ast)
90
+ end
91
+
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,40 @@
1
+ require "jsduck/util/singleton"
2
+ require "jsduck/js/scoped_traverser"
3
+
4
+ module JsDuck
5
+ module Js
6
+
7
+ # Looks the AST of a FunctionDeclaration or FunctionExpression for
8
+ # calls to methods of the owner class.
9
+ class MethodCalls
10
+ include Util::Singleton
11
+
12
+ # Returns array of method names called by the given function.
13
+ # When no methods called, empty array is returned.
14
+ def detect(function_node)
15
+ @traverser = Js::ScopedTraverser.new
16
+
17
+ methods = []
18
+ @traverser.traverse(function_node["body"]) do |node|
19
+ if method_call?(node)
20
+ methods << node["callee"]["property"].to_s
21
+ end
22
+ end
23
+
24
+ methods.sort.uniq
25
+ end
26
+
27
+ private
28
+
29
+ # True when node is this.someMethod() call.
30
+ # Also true for me.someMethod() when me == this.
31
+ def method_call?(node)
32
+ node.call_expression? &&
33
+ node["callee"].member_expression? &&
34
+ node["callee"].raw["computed"] == false &&
35
+ @traverser.this?(node["callee"]["object"].to_s)
36
+ end
37
+
38
+ end
39
+ end
40
+ end