jsduck 3.7.0 → 3.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +3 -1
- data/Rakefile +1 -1
- data/jsduck.gemspec +2 -2
- data/lib/jsduck/app.rb +2 -1
- data/lib/jsduck/app_data.rb +1 -1
- data/lib/jsduck/class.rb +13 -2
- data/lib/jsduck/doc_formatter.rb +30 -43
- data/lib/jsduck/doc_parser.rb +26 -5
- data/lib/jsduck/guides.rb +2 -1
- data/lib/jsduck/index_html.rb +2 -1
- data/lib/jsduck/inline_img.rb +53 -0
- data/lib/jsduck/inline_video.rb +58 -0
- data/lib/jsduck/io.rb +30 -0
- data/lib/jsduck/json_duck.rb +2 -1
- data/lib/jsduck/options.rb +6 -8
- data/lib/jsduck/search_data.rb +61 -25
- data/lib/jsduck/tag/aside.rb +0 -3
- data/lib/jsduck/type_parser.rb +305 -30
- data/lib/jsduck/welcome.rb +2 -1
- data/opt/comments-server-side/app.js +60 -45
- data/opt/comments-server-side/package.json +1 -1
- data/opt/comments-server-side/util.js +129 -54
- metadata +398 -404
data/lib/jsduck/json_duck.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'jsduck/io'
|
1
2
|
require 'json'
|
2
3
|
|
3
4
|
module JsDuck
|
@@ -33,7 +34,7 @@ module JsDuck
|
|
33
34
|
|
34
35
|
# Reads and parses JSON from file
|
35
36
|
def self.read(filename)
|
36
|
-
self.parse(IO.read(filename))
|
37
|
+
self.parse(JsDuck::IO.read(filename))
|
37
38
|
end
|
38
39
|
|
39
40
|
# Parses JSON string
|
data/lib/jsduck/options.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'optparse'
|
2
2
|
require 'jsduck/meta_tag_registry'
|
3
3
|
require 'jsduck/logger'
|
4
|
+
require 'jsduck/io'
|
4
5
|
|
5
6
|
module JsDuck
|
6
7
|
|
@@ -163,11 +164,8 @@ module JsDuck
|
|
163
164
|
@meta_tag_paths << canonical(path)
|
164
165
|
end
|
165
166
|
|
166
|
-
opts.on('--
|
167
|
-
|
168
|
-
"(Deprecated, use --warnings=-all instead.)", " ") do
|
169
|
-
Logger.instance.warn(nil, "--no-warnings is deprecated. Use --warnings=-all instead.")
|
170
|
-
Logger.instance.set_warning(:all, false)
|
167
|
+
opts.on('--encoding=NAME', "Input encoding (defaults to UTF-8).", " ") do |encoding|
|
168
|
+
JsDuck::IO.encoding = encoding
|
171
169
|
end
|
172
170
|
|
173
171
|
opts.on('-v', '--verbose', "This will fill up your console.", " ") do
|
@@ -260,7 +258,7 @@ module JsDuck
|
|
260
258
|
"Possible placeholders:",
|
261
259
|
"%u - URL from @img tag (e.g. 'some/path.png')",
|
262
260
|
"%a - alt text for image",
|
263
|
-
"Default is: '<p><img src=\"
|
261
|
+
"Default is: '<p><img src=\"%u\" alt=\"%a\"></p>'", " ") do |tpl|
|
264
262
|
@img_tpl = tpl
|
265
263
|
end
|
266
264
|
|
@@ -380,7 +378,7 @@ module JsDuck
|
|
380
378
|
main_opts = [
|
381
379
|
/--output/,
|
382
380
|
/--builtin-classes/,
|
383
|
-
/--
|
381
|
+
/--encoding/,
|
384
382
|
/--verbose/,
|
385
383
|
/--help/,
|
386
384
|
/--version/,
|
@@ -449,7 +447,7 @@ module JsDuck
|
|
449
447
|
|
450
448
|
# Extracts files of first build in jsb file
|
451
449
|
def extract_jsb_files(jsb_file)
|
452
|
-
json = JSON.parse(IO.read(jsb_file))
|
450
|
+
json = JSON.parse(JsDuck::IO.read(jsb_file))
|
453
451
|
basedir = File.dirname(jsb_file)
|
454
452
|
|
455
453
|
return json["builds"][0]["packages"].map do |package_id|
|
data/lib/jsduck/search_data.rb
CHANGED
@@ -4,11 +4,12 @@ module JsDuck
|
|
4
4
|
# Creates list of all members in all classes that is used by the
|
5
5
|
# searching feature in UI.
|
6
6
|
class SearchData
|
7
|
-
# Given list of
|
8
|
-
# hashes describing
|
9
|
-
def create(
|
7
|
+
# Given list of classes and other assets, returns an array of
|
8
|
+
# hashes describing the search data.
|
9
|
+
def create(classes, assets)
|
10
10
|
list = []
|
11
|
-
|
11
|
+
|
12
|
+
classes.each do |cls|
|
12
13
|
list << class_node(cls)
|
13
14
|
|
14
15
|
cls[:alternateClassNames].each do |name|
|
@@ -32,61 +33,96 @@ module JsDuck
|
|
32
33
|
end
|
33
34
|
end
|
34
35
|
end
|
36
|
+
|
37
|
+
assets.guides.each_item {|g| list << guide_node(g) }
|
38
|
+
|
39
|
+
assets.videos.each_item {|v| list << video_node(v) }
|
40
|
+
|
41
|
+
assets.examples.each_item {|e| list << example_node(e) }
|
42
|
+
|
35
43
|
list
|
36
44
|
end
|
37
45
|
|
38
|
-
|
46
|
+
private
|
47
|
+
|
39
48
|
def alias_node(key, name, cls)
|
40
49
|
return {
|
41
|
-
:
|
42
|
-
:
|
43
|
-
:
|
44
|
-
:
|
45
|
-
:id => cls.full_name,
|
50
|
+
:name => name,
|
51
|
+
:fullName => alias_display_name(key)+": "+name,
|
52
|
+
:icon => cls.icon + "-redirect",
|
53
|
+
:url => "#!/api/" + cls.full_name,
|
46
54
|
:meta => cls[:meta],
|
47
55
|
:sort => 0,
|
48
56
|
}
|
49
57
|
end
|
50
58
|
|
51
|
-
# Creates structure representing one class
|
52
59
|
def class_node(cls)
|
53
60
|
return {
|
54
|
-
:
|
55
|
-
:
|
56
|
-
:type => :class,
|
61
|
+
:name => cls.short_name,
|
62
|
+
:fullName => cls.full_name,
|
57
63
|
:icon => cls.icon,
|
58
|
-
:
|
64
|
+
:url => "#!/api/" + cls.full_name,
|
59
65
|
:meta => cls[:meta],
|
60
66
|
:sort => 1,
|
61
67
|
}
|
62
68
|
end
|
63
69
|
|
64
|
-
# Creates structure representing one alternate classname
|
65
70
|
def alt_node(name, cls)
|
66
71
|
return {
|
67
|
-
:
|
68
|
-
:
|
72
|
+
:name => Class.short_name(name),
|
73
|
+
:fullName => name,
|
69
74
|
:type => :class,
|
70
|
-
:icon => cls.icon,
|
71
|
-
:
|
75
|
+
:icon => cls.icon + "-redirect",
|
76
|
+
:url => "#!/api/" + cls.full_name,
|
72
77
|
:meta => cls[:meta],
|
73
78
|
:sort => 2,
|
74
79
|
}
|
75
80
|
end
|
76
81
|
|
77
|
-
# Creates structure representing one member
|
78
82
|
def member_node(member, cls)
|
79
83
|
return {
|
80
|
-
:
|
81
|
-
:
|
82
|
-
:type => :member,
|
84
|
+
:name => member[:name],
|
85
|
+
:fullName => cls.full_name + "." + member[:name],
|
83
86
|
:icon => "icon-" + member[:tagname].to_s,
|
84
|
-
:
|
87
|
+
:url => "#!/api/" + cls.full_name + "-" + member[:id],
|
85
88
|
:meta => member[:meta],
|
86
89
|
:sort => 3,
|
87
90
|
}
|
88
91
|
end
|
89
92
|
|
93
|
+
def guide_node(guide)
|
94
|
+
return {
|
95
|
+
:name => guide["title"],
|
96
|
+
:fullName => "guide: " + guide["title"],
|
97
|
+
:icon => "icon-guide",
|
98
|
+
:url => "#!/guide/" + guide["name"],
|
99
|
+
:meta => {},
|
100
|
+
:sort => 4,
|
101
|
+
}
|
102
|
+
end
|
103
|
+
|
104
|
+
def video_node(video)
|
105
|
+
return {
|
106
|
+
:name => video["title"],
|
107
|
+
:fullName => "video: " + video["title"],
|
108
|
+
:icon => "icon-video",
|
109
|
+
:url => "#!/video/" + video["name"],
|
110
|
+
:meta => {},
|
111
|
+
:sort => 4,
|
112
|
+
}
|
113
|
+
end
|
114
|
+
|
115
|
+
def example_node(example)
|
116
|
+
return {
|
117
|
+
:name => example["title"],
|
118
|
+
:fullName => "example: " + example["title"],
|
119
|
+
:icon => "icon-example",
|
120
|
+
:url => "#!/example/" + example["name"],
|
121
|
+
:meta => {},
|
122
|
+
:sort => 4,
|
123
|
+
}
|
124
|
+
end
|
125
|
+
|
90
126
|
# Some alias types are shown differently.
|
91
127
|
# e.g. instead of "widget:" we show "xtype:"
|
92
128
|
def alias_display_name(key)
|
data/lib/jsduck/tag/aside.rb
CHANGED
@@ -3,9 +3,6 @@ require "jsduck/logger"
|
|
3
3
|
|
4
4
|
module JsDuck::Tag
|
5
5
|
# Implementation of @aside tag.
|
6
|
-
#
|
7
|
-
# To document members that were present in previous version but are
|
8
|
-
# completely gone now. Other than that it behaves exactly like @deprecated.
|
9
6
|
class Aside < JsDuck::MetaTag
|
10
7
|
def initialize
|
11
8
|
@name = "aside"
|
data/lib/jsduck/type_parser.rb
CHANGED
@@ -2,17 +2,40 @@ require 'strscan'
|
|
2
2
|
|
3
3
|
module JsDuck
|
4
4
|
|
5
|
-
# Validates the syntax of type definitions
|
5
|
+
# Validates the syntax of type definitions.
|
6
6
|
#
|
7
|
-
#
|
7
|
+
# The parser supports a combination of two syntaxes:
|
8
8
|
#
|
9
|
-
#
|
10
|
-
# - Name.spaced.Type
|
11
|
-
# - Number[]
|
12
|
-
# - String/RegExp
|
13
|
-
# - Type...
|
9
|
+
# 1. Traditional type expressions found in ExtJS code:
|
14
10
|
#
|
15
|
-
#
|
11
|
+
# SomeType
|
12
|
+
# Name.spaced.Type
|
13
|
+
# Number[]
|
14
|
+
# String/RegExp
|
15
|
+
# Type...
|
16
|
+
#
|
17
|
+
# 2. Google Closure Compiler Type Expressions:
|
18
|
+
#
|
19
|
+
# boolean
|
20
|
+
# Window
|
21
|
+
# goog.ui.Menu
|
22
|
+
#
|
23
|
+
# Array.<string>
|
24
|
+
# Object.<string, number>
|
25
|
+
#
|
26
|
+
# {myNum: number, myObject}
|
27
|
+
#
|
28
|
+
# (number|boolean)
|
29
|
+
# ?number
|
30
|
+
# !Object
|
31
|
+
# ...number
|
32
|
+
# *
|
33
|
+
#
|
34
|
+
# function(string, boolean): number
|
35
|
+
# function(new:goog.ui.Menu, string)
|
36
|
+
# function(this:goog.ui.Menu, string)
|
37
|
+
# function(?string=, number=)
|
38
|
+
# function(string, ...[number])
|
16
39
|
#
|
17
40
|
class TypeParser
|
18
41
|
# Allows to check the type of error that was encountered.
|
@@ -29,22 +52,27 @@ module JsDuck
|
|
29
52
|
def initialize(relations={}, formatter={})
|
30
53
|
@relations = relations
|
31
54
|
@formatter = formatter
|
55
|
+
@primitives = {
|
56
|
+
"boolean" => "Boolean",
|
57
|
+
"number" => "Number",
|
58
|
+
"string" => "String",
|
59
|
+
"null" => "null",
|
60
|
+
"undefined" => "undefined",
|
61
|
+
"void" => "void",
|
62
|
+
}
|
32
63
|
end
|
33
64
|
|
65
|
+
# Parses the type definition
|
66
|
+
#
|
67
|
+
# <type> ::= <alteration-type>
|
68
|
+
#
|
34
69
|
def parse(str)
|
35
70
|
@input = StringScanner.new(str)
|
36
71
|
@error = :syntax
|
37
72
|
@out = []
|
38
73
|
|
39
|
-
# Return immediately if base type doesn't match
|
40
|
-
return false unless
|
41
|
-
|
42
|
-
# Go through enumeration of types, separated with "/"
|
43
|
-
while @input.check(/\//)
|
44
|
-
@out << @input.scan(/\//)
|
45
|
-
# Fail if there's no base type after "/"
|
46
|
-
return false unless base_type
|
47
|
-
end
|
74
|
+
# Return immediately if the base type doesn't match
|
75
|
+
return false unless alteration_type
|
48
76
|
|
49
77
|
# Concatenate all output
|
50
78
|
@out = @out.join
|
@@ -53,34 +81,281 @@ module JsDuck
|
|
53
81
|
return @input.eos?
|
54
82
|
end
|
55
83
|
|
56
|
-
|
84
|
+
private
|
85
|
+
|
86
|
+
#
|
87
|
+
# <alteration-type> ::= <varargs-type> [ ("/" | "|") <varargs-type> ]*
|
88
|
+
#
|
89
|
+
def alteration_type
|
90
|
+
skip_whitespace
|
91
|
+
|
92
|
+
# Return immediately if varargs-type doesn't match
|
93
|
+
return false unless varargs_type
|
94
|
+
|
95
|
+
skip_whitespace
|
96
|
+
|
97
|
+
# Go through enumeration of types, separated with "/" or "|"
|
98
|
+
while @input.check(/[\/|]/)
|
99
|
+
@out << @input.scan(/[\/|]/)
|
100
|
+
|
101
|
+
skip_whitespace
|
102
|
+
return false unless varargs_type
|
103
|
+
skip_whitespace
|
104
|
+
end
|
105
|
+
|
106
|
+
true
|
107
|
+
end
|
108
|
+
|
109
|
+
#
|
110
|
+
# <varargs-type> ::= "..." <null-type>
|
111
|
+
# | "..." "[" <null-type> "]"
|
112
|
+
# | <null-type> "..."
|
113
|
+
# | <null-type>
|
114
|
+
#
|
115
|
+
def varargs_type
|
116
|
+
if @input.scan(/\.\.\./)
|
117
|
+
varargs = true
|
118
|
+
@out << "..."
|
119
|
+
if @input.scan(/\[/)
|
120
|
+
varargs_bracketed = true
|
121
|
+
@out << "["
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
return false unless null_type
|
126
|
+
|
127
|
+
if !varargs
|
128
|
+
@out << "..." if @input.scan(/\.\.\./)
|
129
|
+
end
|
130
|
+
|
131
|
+
if varargs_bracketed
|
132
|
+
return false unless @input.scan(/\]/)
|
133
|
+
@out << "]"
|
134
|
+
end
|
135
|
+
|
136
|
+
true
|
137
|
+
end
|
138
|
+
|
139
|
+
#
|
140
|
+
# <null-type> ::= [ "?" | "!" ] <array-type>
|
141
|
+
#
|
142
|
+
# <array-type> ::= <atomic-type> [ "[]" ]*
|
143
|
+
#
|
144
|
+
# <atomic-type> ::= <union-type> | <record-type> | <function-type> | <type-name>
|
145
|
+
#
|
146
|
+
def null_type
|
147
|
+
if nullability = @input.scan(/[?!]/)
|
148
|
+
@out << nullability
|
149
|
+
end
|
150
|
+
|
151
|
+
if @input.check(/\(/)
|
152
|
+
return false unless union_type
|
153
|
+
elsif @input.check(/\{/)
|
154
|
+
return false unless record_type
|
155
|
+
elsif @input.check(/function\(/)
|
156
|
+
return false unless function_type
|
157
|
+
else
|
158
|
+
return false unless type_name
|
159
|
+
end
|
160
|
+
|
161
|
+
while @input.scan(/\[\]/)
|
162
|
+
@out << "[]"
|
163
|
+
end
|
164
|
+
|
165
|
+
true
|
166
|
+
end
|
167
|
+
|
168
|
+
#
|
169
|
+
# <union-type> ::= "(" <alteration-type> ")"
|
170
|
+
#
|
171
|
+
def union_type
|
172
|
+
@out << @input.scan(/\(/)
|
173
|
+
|
174
|
+
return false unless alteration_type
|
175
|
+
|
176
|
+
return false unless @input.scan(/\)/)
|
177
|
+
@out << ")"
|
178
|
+
|
179
|
+
true
|
180
|
+
end
|
181
|
+
|
182
|
+
#
|
183
|
+
# <record-type> ::= "{" <rtype-item> [ "," <rtype-item> ]* "}"
|
184
|
+
#
|
185
|
+
def record_type
|
186
|
+
@out << @input.scan(/\{/)
|
187
|
+
|
188
|
+
return false unless rtype_item
|
189
|
+
|
190
|
+
while @input.scan(/,/)
|
191
|
+
@out << ","
|
192
|
+
return false unless rtype_item
|
193
|
+
end
|
194
|
+
|
195
|
+
return false unless @input.scan(/\}/)
|
196
|
+
@out << "}"
|
197
|
+
|
198
|
+
true
|
199
|
+
end
|
200
|
+
|
201
|
+
#
|
202
|
+
# <rtype-item> ::= <ident> ":" <null-type>
|
203
|
+
# | <ident>
|
204
|
+
#
|
205
|
+
def rtype_item
|
206
|
+
skip_whitespace
|
207
|
+
|
208
|
+
key = @input.scan(/[a-zA-Z0-9_]+/)
|
209
|
+
return false unless key
|
210
|
+
|
211
|
+
skip_whitespace
|
212
|
+
if @input.scan(/:/)
|
213
|
+
@out << ":"
|
214
|
+
skip_whitespace
|
215
|
+
return false unless null_type
|
216
|
+
skip_whitespace
|
217
|
+
end
|
218
|
+
|
219
|
+
true
|
220
|
+
end
|
221
|
+
|
222
|
+
#
|
223
|
+
# <function-type> ::= "function(" <function-type-arguments> ")" [ ":" <null-type> ]
|
224
|
+
#
|
225
|
+
def function_type
|
226
|
+
@out << @input.scan(/function\(/)
|
227
|
+
|
228
|
+
skip_whitespace
|
229
|
+
if !@input.check(/\)/)
|
230
|
+
return false unless function_type_arguments
|
231
|
+
end
|
232
|
+
|
233
|
+
return false unless @input.scan(/\)/)
|
234
|
+
@out << ")"
|
235
|
+
|
236
|
+
skip_whitespace
|
237
|
+
if @input.scan(/:/)
|
238
|
+
@out << ":"
|
239
|
+
skip_whitespace
|
240
|
+
return false unless null_type
|
241
|
+
end
|
242
|
+
|
243
|
+
true
|
244
|
+
end
|
245
|
+
|
246
|
+
#
|
247
|
+
# <function-type-arguments> ::= <ftype-first-arg> [ "," <ftype-arg> ]*
|
57
248
|
#
|
58
|
-
# <
|
249
|
+
# <ftype-first-arg> ::= "new" ":" <type-name>
|
250
|
+
# | "this" ":" <type-name>
|
251
|
+
# | <ftype-arg>
|
59
252
|
#
|
60
|
-
|
61
|
-
|
62
|
-
|
253
|
+
def function_type_arguments
|
254
|
+
skip_whitespace
|
255
|
+
|
256
|
+
# First argument is special
|
257
|
+
if s = @input.scan(/new\s*:\s*/)
|
258
|
+
@out << s
|
259
|
+
return false unless type_name
|
260
|
+
elsif s = @input.scan(/this\s*:\s*/)
|
261
|
+
@out << s
|
262
|
+
return false unless type_name
|
263
|
+
else
|
264
|
+
return false unless ftype_arg
|
265
|
+
end
|
266
|
+
|
267
|
+
skip_whitespace
|
268
|
+
|
269
|
+
# Go through additional arguments, separated with ","
|
270
|
+
while @input.check(/,/)
|
271
|
+
@out << @input.scan(/,/)
|
272
|
+
return false unless ftype_arg
|
273
|
+
end
|
63
274
|
|
64
|
-
|
275
|
+
true
|
276
|
+
end
|
277
|
+
|
278
|
+
#
|
279
|
+
# <ftype-arg> ::= <alteration-type> [ "=" ]
|
280
|
+
#
|
281
|
+
def ftype_arg
|
282
|
+
return false unless alteration_type
|
283
|
+
|
284
|
+
# Each argument can be optional (ending with "=")
|
285
|
+
@out << "=" if @input.scan(/[=]/)
|
286
|
+
skip_whitespace
|
287
|
+
|
288
|
+
true
|
289
|
+
end
|
290
|
+
|
291
|
+
#
|
292
|
+
# <type-name> ::= <type-application> | "*"
|
293
|
+
#
|
294
|
+
# <type-application> ::= <ident-chain> [ "." "<" <type-arguments> ">" ]
|
295
|
+
#
|
296
|
+
# <type-arguments> ::= <alteration-type> [ "," <alteration-type> ]*
|
297
|
+
#
|
298
|
+
# <ident-chain> ::= <ident> [ "." <ident> ]*
|
299
|
+
#
|
300
|
+
# <ident> ::= [a-zA-Z0-9_]+
|
301
|
+
#
|
302
|
+
def type_name
|
303
|
+
name = @input.scan(/[a-zA-Z0-9_]+(\.[a-zA-Z0-9_]+)*|\*/)
|
304
|
+
|
305
|
+
if !name
|
65
306
|
return false
|
66
|
-
elsif @relations[
|
67
|
-
@out << @formatter.link(
|
68
|
-
elsif @
|
69
|
-
@
|
307
|
+
elsif @relations[name]
|
308
|
+
@out << @formatter.link(name, nil, name)
|
309
|
+
elsif @primitives[name]
|
310
|
+
if @relations[@primitives[name]]
|
311
|
+
@out << @formatter.link(@primitives[name], nil, name)
|
312
|
+
else
|
313
|
+
@out << name
|
314
|
+
end
|
315
|
+
elsif @relations.ignore?(name) || name == "*"
|
316
|
+
@out << name
|
70
317
|
else
|
71
318
|
@error = :name
|
72
319
|
return false
|
73
320
|
end
|
74
321
|
|
75
|
-
|
76
|
-
|
322
|
+
# All type names besides * can be followed by .<arguments>
|
323
|
+
if name != "*" && @input.scan(/\.</)
|
324
|
+
return false unless type_arguments
|
325
|
+
return false unless @input.scan(/>/)
|
77
326
|
end
|
78
327
|
|
79
|
-
|
328
|
+
true
|
329
|
+
end
|
330
|
+
|
331
|
+
#
|
332
|
+
# <type-arguments> ::= <alteration-type> [ "," <alteration-type> ]*
|
333
|
+
#
|
334
|
+
def type_arguments
|
335
|
+
skip_whitespace
|
336
|
+
|
337
|
+
# First argument is required
|
338
|
+
return false unless alteration_type
|
339
|
+
|
340
|
+
skip_whitespace
|
341
|
+
|
342
|
+
# Go through additional arguments, separated with ","
|
343
|
+
while @input.check(/,/)
|
344
|
+
@out << @input.scan(/,/)
|
345
|
+
|
346
|
+
skip_whitespace
|
347
|
+
return false unless alteration_type
|
348
|
+
skip_whitespace
|
349
|
+
end
|
80
350
|
|
81
351
|
true
|
82
352
|
end
|
83
353
|
|
354
|
+
def skip_whitespace
|
355
|
+
ws = @input.scan(/\s*/)
|
356
|
+
@out << ws if ws
|
357
|
+
end
|
358
|
+
|
84
359
|
end
|
85
360
|
|
86
361
|
end
|