jsduck 3.10.5 → 3.11.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 CHANGED
@@ -1,9 +1,9 @@
1
- JsDuck
1
+ JSDuck
2
2
  ======
3
3
 
4
4
  API documentation generator for Sencha JavaScript frameworks.
5
5
 
6
- JsDuck aims to be a better documentation generator for [Ext JS][] than
6
+ JSDuck aims to be a better documentation generator for [Ext JS][] than
7
7
  the old [ext-doc][] was. It is used by Sencha to document [Ext JS
8
8
  4][ext4-docs], [Sencha Touch][touch2-docs] and [several other][other-docs]
9
9
  products.
@@ -108,13 +108,26 @@ Hacking it
108
108
  See [Hacking guide](https://github.com/senchalabs/jsduck/wiki/Hacking) in wiki.
109
109
 
110
110
 
111
+ Who's using JSDuck?
112
+ -------------------
113
+
114
+ - Appcelerator [Titanium SDK](http://docs.appcelerator.com/titanium/2.0/index.html)
115
+ - AT&T [API Platform SDK for HTML5](https://code-api-att.com/SenchaSdk20Drop23Docs/)
116
+ - Bryntum [Siesta unit testing framework](http://www.bryntum.com/products/siesta/docs/)
117
+ - [GeoExt 2](https://github.com/geoext/geoext2)
118
+ - Rally Software [Rally App SDK](https://rally1.rallydev.com/apps/2.0p/doc/)
119
+ - [Sencha](http://docs.sencha.com) - obviously :)
120
+
121
+ These are some that we know of. Want your project listed here? Drop us a line.
122
+
123
+
111
124
  Copying
112
125
  -------
113
126
 
114
- JsDuck is distributed under the terms of the GNU General Public
127
+ JSDuck is distributed under the terms of the GNU General Public
115
128
  License version 3.
116
129
 
117
- JsDuck was developed by [Rene Saarsoo](http://triin.net),
130
+ JSDuck was developed by [Rene Saarsoo](http://triin.net),
118
131
  with many contributions from [Nick Poulden](https://github.com/nick).
119
132
 
120
133
  Thanks to [Ondřej Jirman](https://github.com/megous),
@@ -136,3 +149,12 @@ Changelog
136
149
  ---------
137
150
 
138
151
  See [Changelog](https://github.com/senchalabs/jsduck/wiki/Changelog) page in wiki.
152
+
153
+
154
+ More questions?
155
+ ---------------
156
+
157
+ Feel free to [post an issue][issues], but read the [FAQ][] first.
158
+
159
+ [issues]: https://github.com/senchalabs/jsduck/issues
160
+ [FAQ]: https://github.com/senchalabs/jsduck/wiki/FAQ
@@ -2,8 +2,8 @@ Gem::Specification.new do |s|
2
2
  s.required_rubygems_version = ">= 1.3.5"
3
3
 
4
4
  s.name = 'jsduck'
5
- s.version = '3.10.5'
6
- s.date = '2012-05-23'
5
+ s.version = '3.11.0'
6
+ s.date = '2012-06-05'
7
7
  s.summary = "Simple JavaScript Duckumentation generator"
8
8
  s.description = "Documentation generator for Sencha JS frameworks"
9
9
  s.homepage = "https://github.com/senchalabs/jsduck"
@@ -48,6 +48,7 @@ module JsDuck
48
48
  m[:html_type] = (@include_types && !is_css_tag) ? format_type(m[:type]) : m[:type] if m[:type]
49
49
  m[:params] = m[:params].map {|p| format_item(p, is_css_tag) } if m[:params]
50
50
  m[:return] = format_item(m[:return], is_css_tag) if m[:return]
51
+ m[:throws] = m[:throws].map {|t| format_item(t, is_css_tag) } if m[:throws]
51
52
  m[:properties] = m[:properties].map {|b| format_item(b, is_css_tag) } if m[:properties]
52
53
  m[:html_meta] = format_meta_data(m)
53
54
  m
@@ -0,0 +1,201 @@
1
+ require 'strscan'
2
+
3
+ module JsDuck
4
+
5
+ # Tokenizes CSS or SCSS code into lexical tokens.
6
+ #
7
+ # Each token has a type and value.
8
+ # Types and possible values for them are as follows:
9
+ #
10
+ # - :number -- "25.8"
11
+ # - :percentage -- "25%"
12
+ # - :dimension -- "2em"
13
+ # - :string -- '"Hello world"'
14
+ # - :ident -- "foo-bar"
15
+ # - :at_keyword -- "@mixin"
16
+ # - :hash -- "#00FF66"
17
+ # - :delim -- "{"
18
+ # - :doc_comment -- "/** My comment */"
19
+ #
20
+ # Notice that doc-comments are recognized as tokens while normal
21
+ # comments are ignored just as whitespace.
22
+ #
23
+ class CssLexer
24
+ # Initializes lexer with input string.
25
+ def initialize(input)
26
+ @input = StringScanner.new(input)
27
+ @buffer = []
28
+ end
29
+
30
+ # Tests if given pattern matches the tokens that follow at current
31
+ # position.
32
+ #
33
+ # Takes list of strings and symbols. Symbols are compared to
34
+ # token type, while strings to token value. For example:
35
+ #
36
+ # look(:ident, ":", :dimension)
37
+ #
38
+ def look(*tokens)
39
+ buffer_tokens(tokens.length)
40
+ i = 0
41
+ tokens.all? do |t|
42
+ tok = @buffer[i]
43
+ i += 1
44
+ if !tok
45
+ false
46
+ elsif t.instance_of?(Symbol)
47
+ tok[:type] == t
48
+ else
49
+ tok[:value] == t
50
+ end
51
+ end
52
+ end
53
+
54
+ # Returns the value of next token, moving the current token cursor
55
+ # also to next token.
56
+ #
57
+ # When full=true, returns full token as hash like so:
58
+ #
59
+ # {:type => :ident, :value => "foo"}
60
+ #
61
+ # For doc-comments the full token also contains the field :linenr,
62
+ # pointing to the line where the doc-comment began.
63
+ #
64
+ def next(full=false)
65
+ buffer_tokens(1)
66
+ tok = @buffer.shift
67
+ # advance the scanpointer to the position after this token
68
+ @input.pos = tok[:pos]
69
+ full ? tok : tok[:value]
70
+ end
71
+
72
+ # True when no more tokens.
73
+ def empty?
74
+ buffer_tokens(1)
75
+ return !@buffer.first
76
+ end
77
+
78
+ # Ensures next n tokens are read in buffer
79
+ #
80
+ # At the end of buffering the initial position scanpointer is
81
+ # restored. Only the #next method will advance the scanpointer in
82
+ # a way that's visible outside this class.
83
+ def buffer_tokens(n)
84
+ prev_pos = @input.pos
85
+ @input.pos = @buffer.last[:pos] if @buffer.last
86
+ (n - @buffer.length).times do
87
+ @previous_token = tok = next_token
88
+ if tok
89
+ # remember scanpointer position after each token
90
+ tok[:pos] = @input.pos
91
+ @buffer << tok
92
+ end
93
+ end
94
+ @input.pos = prev_pos
95
+ end
96
+
97
+ # Parses out next token from input stream.
98
+ def next_token
99
+ while !@input.eos? do
100
+ skip_white
101
+ if @input.check(IDENT)
102
+ return {
103
+ :type => :ident,
104
+ :value => @input.scan(IDENT)
105
+ }
106
+ elsif @input.check(/'/)
107
+ return {
108
+ :type => :string,
109
+ :value => @input.scan(/'([^'\\]|\\.)*('|\Z)/m)
110
+ }
111
+ elsif @input.check(/"/)
112
+ return {
113
+ :type => :string,
114
+ :value => @input.scan(/"([^"\\]|\\.)*("|\Z)/m)
115
+ }
116
+ elsif @input.check(/\//)
117
+ # Several things begin with dash:
118
+ # - comments, regexes, division-operators
119
+ if @input.check(/\/\*\*[^\/]/)
120
+ return {
121
+ :type => :doc_comment,
122
+ # Calculate current line number, starting with 1
123
+ :linenr => @input.string[0...@input.pos].count("\n") + 1,
124
+ :value => @input.scan_until(/\*\/|\Z/)
125
+ }
126
+ elsif @input.check(/\/\*/)
127
+ # skip multiline comment
128
+ @input.scan_until(/\*\/|\Z/)
129
+ elsif @input.check(/\/\//)
130
+ # skip line comment
131
+ @input.scan_until(/\n|\Z/)
132
+ else
133
+ return {
134
+ :type => :operator,
135
+ :value => @input.scan(/\//)
136
+ }
137
+ end
138
+ elsif @input.check(NUM)
139
+ nr = @input.scan(NUM)
140
+ if @input.check(/%/)
141
+ return {
142
+ :type => :percentage,
143
+ :value => nr + @input.scan(/%/)
144
+ }
145
+ elsif @input.check(IDENT)
146
+ return {
147
+ :type => :dimension,
148
+ :value => nr + @input.scan(IDENT)
149
+ }
150
+ else
151
+ return {
152
+ :type => :number,
153
+ :value => nr
154
+ }
155
+ end
156
+ elsif @input.check(/@/)
157
+ return maybe(:at_keyword, /@/, IDENT)
158
+ elsif @input.check(/#/)
159
+ return maybe(:hash, /#/, NAME)
160
+ elsif @input.check(/\$/)
161
+ return maybe(:var, /\$/, IDENT)
162
+ elsif @input.check(/./)
163
+ return {
164
+ :type => :delim,
165
+ :value => @input.scan(/./)
166
+ }
167
+ end
168
+ end
169
+ end
170
+
171
+ # Returns token of given type when both regexes match.
172
+ # Otherwise returns :delim token with value of first regex match.
173
+ # First regex must always match.
174
+ def maybe(token_type, before_re, after_re)
175
+ before = @input.scan(before_re)
176
+ if @input.check(after_re)
177
+ return {
178
+ :type => token_type,
179
+ :value => before + @input.scan(after_re)
180
+ }
181
+ else
182
+ return {
183
+ :type => :delim,
184
+ :value => before
185
+ }
186
+ end
187
+ end
188
+
189
+ def skip_white
190
+ @input.scan(/\s+/)
191
+ end
192
+
193
+ # Simplified token syntax based on:
194
+ # http://www.w3.org/TR/CSS21/syndata.html
195
+ IDENT = /-?[_a-z][_a-z0-9-]*/i
196
+ NAME = /[_a-z0-9-]+/i
197
+ NUM = /[0-9]*\.[0-9]+|[0-9]+/
198
+
199
+ end
200
+
201
+ end
@@ -1,11 +1,11 @@
1
- require 'jsduck/lexer'
1
+ require 'jsduck/css_lexer'
2
2
  require 'jsduck/doc_parser'
3
3
 
4
4
  module JsDuck
5
5
 
6
6
  class CssParser
7
7
  def initialize(input, options = {})
8
- @lex = Lexer.new(input)
8
+ @lex = CssLexer.new(input)
9
9
  @doc_parser = DocParser.new
10
10
  @docs = []
11
11
  end
@@ -28,31 +28,77 @@ module JsDuck
28
28
  @docs
29
29
  end
30
30
 
31
- # <code-block> := <mixin> | <nop>
31
+ # <code-block> := <mixin-declaration> | <var-declaration> | <nop>
32
32
  def code_block
33
- if look("@", "mixin")
34
- mixin
33
+ if look("@mixin")
34
+ mixin_declaration
35
+ elsif look(:var, ":")
36
+ var_declaration
35
37
  else
36
38
  {:type => :nop}
37
39
  end
38
40
  end
39
41
 
40
- # <mixin> := "@mixin" <css-ident>
41
- def mixin
42
- match("@", "mixin")
42
+ # <mixin-declaration> := "@mixin" <ident>
43
+ def mixin_declaration
44
+ match("@mixin")
43
45
  return {
44
46
  :type => :css_mixin,
45
- :name => look(:ident) ? css_ident : nil,
47
+ :name => look(:ident) ? match(:ident) : nil,
46
48
  }
47
49
  end
48
50
 
49
- # <css-ident> := <ident> [ "-" <ident> ]*
50
- def css_ident
51
- chain = [match(:ident)]
52
- while look("-", :ident) do
53
- chain << match("-", :ident)
51
+ # <var-declaration> := <var> ":" <css-value>
52
+ def var_declaration
53
+ name = match(:var)
54
+ match(":")
55
+ value_list = css_value
56
+ return {
57
+ :type => :css_var,
58
+ :name => name,
59
+ :value => {
60
+ :default => value_list.map {|v| v[:value] }.join(" "),
61
+ :type => value_type(value_list),
62
+ }
63
+ }
64
+ end
65
+
66
+ # <css-value> := ...anything up to... [ ";" | "}" | "!default" ]
67
+ def css_value
68
+ val = []
69
+ while !look(";") && !look("}") && !look("!", "default")
70
+ val << @lex.next(true)
71
+ end
72
+ val
73
+ end
74
+
75
+ # Determines type of CSS value
76
+ def value_type(val)
77
+ case val[0][:type]
78
+ when :number
79
+ "number"
80
+ when :dimension
81
+ "length"
82
+ when :percentage
83
+ "percentage"
84
+ when :string
85
+ "string"
86
+ when :hash
87
+ "color"
88
+ when :ident
89
+ case val[0][:value]
90
+ when "true", "false"
91
+ return "boolean"
92
+ when "rgb", "rgba", "hsl", "hsla"
93
+ return "color"
94
+ when "black", "silver", "gray", "white", "maroon",
95
+ "red", "purple", "fuchsia", "green", "lime", "olive",
96
+ "yellow", "navy", "blue", "teal", "aqua", "orange"
97
+ return "color"
98
+ when "transparent"
99
+ return "color"
100
+ end
54
101
  end
55
- return chain.join("-")
56
102
  end
57
103
 
58
104
  # Matches all arguments, returns the value of last match
@@ -132,6 +132,8 @@ module JsDuck
132
132
  at_alias
133
133
  elsif look(/@var\b/)
134
134
  at_var
135
+ elsif look(/@throws\b/)
136
+ at_throws
135
137
  elsif look(/@inheritable\b/)
136
138
  boolean_at_tag(/@inheritable/, :inheritable)
137
139
  elsif look(/@accessor\b/)
@@ -272,7 +274,15 @@ module JsDuck
272
274
  match(/@var/)
273
275
  add_tag(:css_var)
274
276
  maybe_type
275
- maybe_name
277
+ maybe_name_with_default
278
+ skip_white
279
+ end
280
+
281
+ # matches @throws {type} ...
282
+ def at_throws
283
+ match(/@throws/)
284
+ add_tag(:throws)
285
+ maybe_type
276
286
  skip_white
277
287
  end
278
288
 
@@ -10,7 +10,18 @@ module JsDuck
10
10
  super(input)
11
11
  @doc_parser = DocParser.new
12
12
  @docs = []
13
- @ext_namespaces = options[:ext_namespaces] || ["Ext"]
13
+ @ext_namespaces = (options[:ext_namespaces] || ["Ext"]).map {|ns| tokenize_ns(ns) }
14
+ end
15
+
16
+ # Splits namespace string into array like so:
17
+ #
18
+ # "Foo.Bar.Baz" --> ["Foo", ".", "Bar", ".", "Baz"]
19
+ #
20
+ def tokenize_ns(ns)
21
+ ns.split(".").reduce([]) do |res, x|
22
+ res << "." unless res.length == 0
23
+ res << x
24
+ end
14
25
  end
15
26
 
16
27
  # Parses the whole JavaScript block and returns array where for
@@ -78,9 +89,9 @@ module JsDuck
78
89
  elsif look(:var)
79
90
  var_declaration
80
91
  elsif ext_look(:ns, ".", "define", "(", :string)
81
- ext_define
92
+ ext_define(:ns, ".", "define", "(", :string)
82
93
  elsif ext_look(:ns, ".", "ClassManager", ".", "create", "(", :string)
83
- ext_define
94
+ ext_define(:ns, ".", "ClassManager", ".", "create", "(", :string)
84
95
  elsif look(:ident, ":") || look(:string, ":")
85
96
  property_literal
86
97
  elsif look(",", :ident, ":") || look(",", :string, ":")
@@ -244,10 +255,8 @@ module JsDuck
244
255
  end
245
256
 
246
257
  # <ext-define> := "Ext" "." ["define" | "ClassManager" "." "create" ] "(" <string> "," <ext-define-cfg>
247
- def ext_define
248
- match(:ident, ".");
249
- look("define") ? match("define") : match("ClassManager", ".", "create");
250
- name = match("(", :string)[:value]
258
+ def ext_define(*pattern)
259
+ name = ext_match(*pattern)[:value]
251
260
 
252
261
  if look(",", "{")
253
262
  match(",")
@@ -400,11 +409,22 @@ module JsDuck
400
409
  # names listed in @ext_namespaces
401
410
  def ext_look(placeholder, *args)
402
411
  @ext_namespaces.each do |ns|
403
- return true if look(ns, *args)
412
+ return true if look(*(ns + args))
404
413
  end
405
414
  return false
406
415
  end
407
416
 
417
+ # Like match() but tries as the first argument all the names
418
+ # listed in @ext_namespaces
419
+ def ext_match(placeholder, *args)
420
+ @ext_namespaces.each do |ns|
421
+ pattern = ns + args
422
+ if look(*pattern)
423
+ return match(*pattern)
424
+ end
425
+ end
426
+ end
427
+
408
428
  end
409
429
 
410
430
  end
@@ -63,6 +63,8 @@ module JsDuck
63
63
  :class
64
64
  elsif code[:type] == :css_mixin
65
65
  :css_mixin
66
+ elsif code[:type] == :css_var
67
+ :css_var
66
68
  elsif doc_map[:cfg]
67
69
  :cfg
68
70
  elsif code[:type] == :function
@@ -160,6 +162,7 @@ module JsDuck
160
162
  :doc => detect_doc(docs),
161
163
  :params => detect_params(:method, doc_map, code),
162
164
  :return => detect_return(doc_map, name == "constructor" ? "Object" : "undefined"),
165
+ :throws => detect_throws(doc_map),
163
166
  }, doc_map)
164
167
  end
165
168
 
@@ -209,6 +212,7 @@ module JsDuck
209
212
  :name => detect_name(:css_var, doc_map, code),
210
213
  :owner => detect_owner(doc_map),
211
214
  :type => detect_type(:css_var, doc_map, code),
215
+ :default => detect_default(:css_var, doc_map, code),
212
216
  :doc => detect_doc(docs),
213
217
  }, doc_map)
214
218
  end
@@ -251,7 +255,7 @@ module JsDuck
251
255
  main_tag[:name]
252
256
  elsif doc_map[:constructor]
253
257
  "constructor"
254
- elsif code[:type] == :function || code[:type] == :css_mixin
258
+ elsif code[:type] == :function || code[:type] == :css_mixin || code[:type] == :css_var
255
259
  code[:name]
256
260
  elsif code[:type] == :assignment
257
261
  name_type == :full_name ? code[:left].join(".") : code[:left].last
@@ -285,6 +289,8 @@ module JsDuck
285
289
  elsif code[:right][:type] == :literal && code[:right][:class] != nil
286
290
  return code[:right][:class]
287
291
  end
292
+ elsif code[:type] == :css_var && code[:value][:type] != nil
293
+ return code[:value][:type]
288
294
  end
289
295
  end
290
296
  return "Object"
@@ -311,6 +317,8 @@ module JsDuck
311
317
  main_tag[:default]
312
318
  elsif code_matches_doc?(tagname, doc_map, code) && code[:type] == :assignment && code[:right]
313
319
  code[:right][:value]
320
+ elsif code_matches_doc?(tagname, doc_map, code) && code[:type] == :css_var && code[:value][:default]
321
+ code[:value][:default]
314
322
  end
315
323
  end
316
324
 
@@ -470,6 +478,17 @@ module JsDuck
470
478
  }
471
479
  end
472
480
 
481
+ def detect_throws(doc_map)
482
+ return unless doc_map[:throws]
483
+
484
+ doc_map[:throws].map do |throws|
485
+ {
486
+ :type => throws[:type] || "Object",
487
+ :doc => throws[:doc] || "",
488
+ }
489
+ end
490
+ end
491
+
473
492
  # Combines :doc-s of most tags
474
493
  # Ignores tags that have doc comment themselves and subproperty tags
475
494
  def detect_doc(docs)
@@ -75,7 +75,7 @@ module JsDuck
75
75
  ]
76
76
  @meta_tag_paths = []
77
77
 
78
- @version = "3.10.5"
78
+ @version = "3.11.0"
79
79
 
80
80
  # Customizing output
81
81
  @title = "Sencha Docs - Ext JS"
@@ -318,6 +318,10 @@ module JsDuck
318
318
  doc << render_return(ret)
319
319
  end
320
320
 
321
+ if item[:throws]
322
+ doc << render_throws(item[:throws])
323
+ end
324
+
321
325
  doc
322
326
  end
323
327
 
@@ -351,6 +355,22 @@ module JsDuck
351
355
  "</ul>",
352
356
  ]
353
357
  end
358
+
359
+ def render_throws(throws)
360
+ return [
361
+ "<h3 class='pa'>Throws</h3>",
362
+ "<ul>",
363
+ throws.map do |thr|
364
+ [
365
+ "<li>",
366
+ "<span class='pre'>#{thr[:html_type]}</span>",
367
+ "<div class='sub-desc'>#{thr[:doc]}</div>",
368
+ "</li>",
369
+ ]
370
+ end,
371
+ "</ul>",
372
+ ]
373
+ end
354
374
  end
355
375
 
356
376
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jsduck
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.10.5
4
+ version: 3.11.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2012-05-23 00:00:00.000000000 Z
13
+ date: 2012-06-05 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rdiscount
@@ -144,6 +144,7 @@ files:
144
144
  - lib/jsduck/class.rb
145
145
  - lib/jsduck/class_formatter.rb
146
146
  - lib/jsduck/class_writer.rb
147
+ - lib/jsduck/css_lexer.rb
147
148
  - lib/jsduck/css_parser.rb
148
149
  - lib/jsduck/doc_formatter.rb
149
150
  - lib/jsduck/doc_parser.rb