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.
- data/Rakefile +14 -4
- data/bin/jsduck +3 -1
- data/jsduck.gemspec +2 -2
- data/lib/jsduck/app.rb +8 -0
- data/lib/jsduck/assets.rb +3 -0
- data/lib/jsduck/batch_processor.rb +2 -0
- data/lib/jsduck/categories/class_name.rb +2 -26
- data/lib/jsduck/categories/factory.rb +5 -43
- data/lib/jsduck/columns.rb +56 -0
- data/lib/jsduck/doc/delimited_parser.rb +105 -0
- data/lib/jsduck/doc/scanner.rb +2 -1
- data/lib/jsduck/doc/standard_tag_parser.rb +37 -71
- data/lib/jsduck/guide_anchors.rb +32 -0
- data/lib/jsduck/guide_toc.rb +49 -0
- data/lib/jsduck/guides.rb +14 -32
- data/lib/jsduck/inline/video.rb +2 -8
- data/lib/jsduck/js/ast.rb +13 -305
- data/lib/jsduck/js/class.rb +245 -0
- data/lib/jsduck/js/event.rb +34 -0
- data/lib/jsduck/js/fires.rb +42 -0
- data/lib/jsduck/js/method.rb +94 -0
- data/lib/jsduck/js/method_calls.rb +40 -0
- data/lib/jsduck/js/node.rb +29 -0
- data/lib/jsduck/js/property.rb +64 -0
- data/lib/jsduck/js/{function.rb → returns.rb} +8 -3
- data/lib/jsduck/js/scoped_traverser.rb +42 -0
- data/lib/jsduck/logger.rb +13 -1
- data/lib/jsduck/merger.rb +34 -27
- data/lib/jsduck/news.rb +128 -0
- data/lib/jsduck/options.rb +59 -2
- data/lib/jsduck/params_merger.rb +47 -0
- data/lib/jsduck/process/accessors.rb +8 -2
- data/lib/jsduck/process/fires.rb +71 -0
- data/lib/jsduck/process/importer.rb +19 -1
- data/lib/jsduck/render/class.rb +11 -4
- data/lib/jsduck/render/signature_util.rb +14 -0
- data/lib/jsduck/tag/alias.rb +0 -20
- data/lib/jsduck/tag/alternate_class_names.rb +0 -5
- data/lib/jsduck/tag/cfg.rb +30 -5
- data/lib/jsduck/tag/class.rb +45 -2
- data/lib/jsduck/tag/css_mixin.rb +8 -4
- data/lib/jsduck/tag/css_var.rb +26 -5
- data/lib/jsduck/tag/default.rb +2 -8
- data/lib/jsduck/tag/enum.rb +7 -10
- data/lib/jsduck/tag/event.rb +12 -4
- data/lib/jsduck/tag/extends.rb +0 -6
- data/lib/jsduck/tag/fires.rb +53 -0
- data/lib/jsduck/tag/icons/cfg.png +0 -0
- data/lib/jsduck/tag/icons/css_mixin.png +0 -0
- data/lib/jsduck/tag/icons/css_var.png +0 -0
- data/lib/jsduck/tag/icons/event.png +0 -0
- data/lib/jsduck/tag/icons/method.png +0 -0
- data/lib/jsduck/tag/icons/property.png +0 -0
- data/lib/jsduck/tag/member_tag.rb +130 -0
- data/lib/jsduck/tag/method.rb +44 -4
- data/lib/jsduck/tag/param.rb +8 -60
- data/lib/jsduck/tag/property.rb +28 -5
- data/lib/jsduck/tag/tag.rb +3 -75
- data/lib/jsduck/tag/type.rb +1 -11
- data/lib/jsduck/tag_registry.rb +6 -48
- data/lib/jsduck/web/css.rb +8 -1
- data/lib/jsduck/web/data.rb +2 -1
- data/lib/jsduck/web/index_html.rb +1 -0
- data/lib/jsduck/web/member_icons.rb +43 -0
- data/lib/jsduck/web/search.rb +3 -2
- data/lib/jsduck/web/writer.rb +8 -0
- metadata +31 -27
- data/lib/jsduck/docs_code_comparer.rb +0 -44
- data/lib/jsduck/render/signature.rb +0 -94
- data/lib/jsduck/tag/autodetected.rb +0 -21
- 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
|