jsduck 3.7.0 → 3.8.0
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/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
|