jsduck 5.0.0.beta2 → 5.0.0.beta3

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 (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