jsduck 3.7.0 → 3.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -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('--no-warnings',
167
- "Turns off all warnings.",
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=\"doc-resources/%u\" alt=\"%a\"></p>'", " ") do |tpl|
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
- /--no-warnings/,
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|
@@ -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 class documentation objects returns an array of
8
- # hashes describing all the members.
9
- def create(docs)
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
- docs.each do |cls|
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
- # Creates structure representing one alias
46
+ private
47
+
39
48
  def alias_node(key, name, cls)
40
49
  return {
41
- :cls => alias_display_name(key)+": "+name,
42
- :member => name,
43
- :type => :class,
44
- :icon => cls.icon,
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
- :cls => cls.full_name,
55
- :member => cls.short_name,
56
- :type => :class,
61
+ :name => cls.short_name,
62
+ :fullName => cls.full_name,
57
63
  :icon => cls.icon,
58
- :id => cls.full_name,
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
- :cls => name,
68
- :member => Class.short_name(name),
72
+ :name => Class.short_name(name),
73
+ :fullName => name,
69
74
  :type => :class,
70
- :icon => cls.icon,
71
- :id => cls.full_name,
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
- :cls => cls.full_name,
81
- :member => member[:name],
82
- :type => :member,
84
+ :name => member[:name],
85
+ :fullName => cls.full_name + "." + member[:name],
83
86
  :icon => "icon-" + member[:tagname].to_s,
84
- :id => cls.full_name + "-" + member[:id],
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)
@@ -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"
@@ -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
- # Quick summary of supported types:
7
+ # The parser supports a combination of two syntaxes:
8
8
  #
9
- # - SomeType
10
- # - Name.spaced.Type
11
- # - Number[]
12
- # - String/RegExp
13
- # - Type...
9
+ # 1. Traditional type expressions found in ExtJS code:
14
10
  #
15
- # Details are covered in spec.
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 base_type
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
- # The basic type
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
- # <ident> [ "." <ident> ]* [ "[]" ]* [ "..." ]
249
+ # <ftype-first-arg> ::= "new" ":" <type-name>
250
+ # | "this" ":" <type-name>
251
+ # | <ftype-arg>
59
252
  #
60
- # dot-separated identifiers followed by optional "[]"
61
- def base_type
62
- type = @input.scan(/[a-zA-Z0-9_]+(\.[a-zA-Z0-9_]+)*/)
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
- if !type
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[type]
67
- @out << @formatter.link(type, nil, type)
68
- elsif @relations.ignore?(type) || type == "undefined"
69
- @out << type
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
- while @input.scan(/\[\]/)
76
- @out << "[]"
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
- @out << "..." if @input.scan(/\.\.\./)
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