jsduck 4.4.1 → 4.5.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.
@@ -6,6 +6,6 @@ install:
6
6
  - gem install rdiscount
7
7
  - gem install json
8
8
  - gem install parallel
9
- - gem install therubyracer
9
+ - gem install therubyracer -v 0.10.1
10
10
  - gem install rspec
11
11
  - gem install rake
data/README.md CHANGED
@@ -141,6 +141,7 @@ Who's using JSDuck?
141
141
  - Appcelerator [Titanium SDK](http://docs.appcelerator.com/titanium/2.0/index.html)
142
142
  - AT&T [API Platform SDK for HTML5](https://code-api-att.com/SenchaSdk20Drop23Docs/)
143
143
  - Bryntum [Siesta unit testing framework](http://www.bryntum.com/products/siesta/docs/)
144
+ - [CKEditor](http://docs.ckeditor.com)
144
145
  - [GeoExt 2](https://github.com/geoext/geoext2)
145
146
  - Rally Software [Rally App SDK](https://rally1.rallydev.com/apps/2.0p/doc/)
146
147
  - [Sencha](http://docs.sencha.com) - obviously :)
data/Rakefile CHANGED
@@ -104,7 +104,7 @@ def compress
104
104
  dir = "template-min"
105
105
 
106
106
  # Create JSB3 file for Docs app
107
- system("sencha", "create", "jsb", "-a", "http://localhost/docs/", "-p", "#{dir}/app.jsb3")
107
+ system("sencha", "create", "jsb", "-a", "http://localhost/~renesaarsoo/docs/", "-p", "#{dir}/app.jsb3")
108
108
  # Concatenate files listed in JSB3 file
109
109
  system("sencha", "build", "-p", "#{dir}/app.jsb3", "-d", dir)
110
110
 
@@ -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 = '4.4.1'
6
- s.date = '2012-11-20'
5
+ s.version = '4.5.0'
6
+ s.date = '2012-12-06'
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"
@@ -22,7 +22,7 @@ Gem::Specification.new do |s|
22
22
  s.add_dependency 'rdiscount'
23
23
  s.add_dependency 'json'
24
24
  s.add_dependency 'parallel'
25
- s.add_dependency 'therubyracer'
25
+ s.add_dependency 'therubyracer', '= 0.10.1'
26
26
 
27
27
  s.add_development_dependency 'rspec'
28
28
  s.add_development_dependency 'rake'
@@ -1,6 +1,7 @@
1
1
  require "jsduck/serializer"
2
2
  require "jsduck/evaluator"
3
3
  require "jsduck/function_ast"
4
+ require "jsduck/ext_patterns"
4
5
 
5
6
  module JsDuck
6
7
 
@@ -10,21 +11,10 @@ module JsDuck
10
11
  def initialize(docs = [], options = {})
11
12
  @serializer = JsDuck::Serializer.new
12
13
  @evaluator = JsDuck::Evaluator.new
13
- @ext_define_patterns = build_ext_define_patterns(options[:ext_namespaces] || ["Ext"])
14
+ @ext_patterns = JsDuck::ExtPatterns.new(options[:ext_namespaces] || ["Ext"])
14
15
  @docs = docs
15
16
  end
16
17
 
17
- # Given Array of alternate Ext namespaces builds list of patterns
18
- # for detecting Ext.define:
19
- #
20
- # ["Ext","Foo"] --> ["Ext.define", "Ext.ClassManager.create", "Foo.define", "Foo.ClassManager.create"]
21
- #
22
- def build_ext_define_patterns(namespaces)
23
- namespaces.map do |ns|
24
- [ns + ".define", ns + ".ClassManager.create"]
25
- end.flatten
26
- end
27
-
28
18
  # Performs the detection of code in all docsets.
29
19
  #
30
20
  # @returns the processed array of docsets. (But it does it
@@ -68,7 +58,11 @@ module JsDuck
68
58
  if exp && ext_define?(exp)
69
59
  make_class(to_value(exp["arguments"][0]), exp)
70
60
 
71
- # foo = Ext.extend("Parent", {})
61
+ # Ext.override(Class, {})
62
+ elsif exp && ext_override?(exp)
63
+ make_class("", exp)
64
+
65
+ # foo = Ext.extend(Parent, {})
72
66
  elsif exp && assignment?(exp) && ext_extend?(exp["right"])
73
67
  make_class(to_s(exp["left"]), exp["right"])
74
68
 
@@ -76,7 +70,7 @@ module JsDuck
76
70
  elsif exp && assignment?(exp) && class_name?(to_s(exp["left"]))
77
71
  make_class(to_s(exp["left"]), exp["right"])
78
72
 
79
- # var foo = Ext.extend("Parent", {})
73
+ # var foo = Ext.extend(Parent, {})
80
74
  elsif var && var["init"] && ext_extend?(var["init"])
81
75
  make_class(to_s(var["id"]), var["init"])
82
76
 
@@ -88,6 +82,10 @@ module JsDuck
88
82
  elsif function?(ast) && class_name?(to_s(ast["id"]))
89
83
  make_class(to_s(ast["id"]))
90
84
 
85
+ # { ... }
86
+ elsif object?(ast)
87
+ make_class("", ast)
88
+
91
89
  # function foo() {}
92
90
  elsif function?(ast)
93
91
  make_method(to_s(ast["id"]), ast)
@@ -108,6 +106,10 @@ module JsDuck
108
106
  elsif property?(ast) && function?(ast["value"])
109
107
  make_method(key_value(ast["key"]), ast["value"])
110
108
 
109
+ # this.fireEvent("foo", ...)
110
+ elsif exp && fire_event?(exp)
111
+ make_event(to_value(exp["arguments"][0]))
112
+
111
113
  # foo = ...
112
114
  elsif exp && assignment?(exp)
113
115
  make_property(to_s(exp["left"]), exp["right"])
@@ -152,11 +154,15 @@ module JsDuck
152
154
  end
153
155
 
154
156
  def ext_define?(ast)
155
- call?(ast) && @ext_define_patterns.include?(to_s(ast["callee"]))
157
+ call?(ast) && ext_pattern?("Ext.define", ast["callee"])
156
158
  end
157
159
 
158
160
  def ext_extend?(ast)
159
- call?(ast) && to_s(ast["callee"]) == "Ext.extend"
161
+ call?(ast) && ext_pattern?("Ext.extend", ast["callee"])
162
+ end
163
+
164
+ def ext_override?(ast)
165
+ call?(ast) && ext_pattern?("Ext.override", ast["callee"])
160
166
  end
161
167
 
162
168
  def function?(ast)
@@ -164,7 +170,15 @@ module JsDuck
164
170
  end
165
171
 
166
172
  def empty_fn?(ast)
167
- ast["type"] == "MemberExpression" && to_s(ast) == "Ext.emptyFn"
173
+ ast["type"] == "MemberExpression" && ext_pattern?("Ext.emptyFn", ast)
174
+ end
175
+
176
+ def ext_pattern?(pattern, ast)
177
+ @ext_patterns.matches?(pattern, to_s(ast))
178
+ end
179
+
180
+ def fire_event?(ast)
181
+ call?(ast) && to_s(ast["callee"]) == "this.fireEvent"
168
182
  end
169
183
 
170
184
  def var?(ast)
@@ -183,6 +197,10 @@ module JsDuck
183
197
  ast["type"] == "Literal" && ast["value"].is_a?(String)
184
198
  end
185
199
 
200
+ def object?(ast)
201
+ ast["type"] == "ObjectExpression"
202
+ end
203
+
186
204
  # Class name begins with upcase char
187
205
  def class_name?(name)
188
206
  return name.split(/\./).last =~ /\A[A-Z]/
@@ -196,15 +214,13 @@ module JsDuck
196
214
 
197
215
  # apply information from Ext.extend, Ext.define, or {}
198
216
  if ast
199
- if ext_extend?(ast)
200
- args = ast["arguments"]
201
- cls[:extends] = to_s(args[0])
202
- if args.length == 2 && args[1]["type"] == "ObjectExpression"
203
- detect_class_members_from_object(cls, args[1])
204
- end
205
- elsif ext_define?(ast)
217
+ if ext_define?(ast)
206
218
  detect_ext_define(cls, ast)
207
- elsif ast["type"] == "ObjectExpression"
219
+ elsif ext_extend?(ast)
220
+ detect_ext_something(:extends, cls, ast)
221
+ elsif ext_override?(ast)
222
+ detect_ext_something(:override, cls, ast)
223
+ elsif object?(ast)
208
224
  detect_class_members_from_object(cls, ast)
209
225
  elsif ast["type"] == "ArrayExpression"
210
226
  detect_class_members_from_array(cls, ast)
@@ -214,6 +230,16 @@ module JsDuck
214
230
  return cls
215
231
  end
216
232
 
233
+ # Detection of Ext.extend() or Ext.override().
234
+ # The type parameter must be correspondingly either :extend or :override.
235
+ def detect_ext_something(type, cls, ast)
236
+ args = ast["arguments"]
237
+ cls[type] = to_s(args[0])
238
+ if args.length == 2 && object?(args[1])
239
+ detect_class_members_from_object(cls, args[1])
240
+ end
241
+ end
242
+
217
243
  # Inspects Ext.define() and copies detected properties over to the
218
244
  # given cls Hash
219
245
  def detect_ext_define(cls, ast)
@@ -419,6 +445,13 @@ module JsDuck
419
445
  end
420
446
  end
421
447
 
448
+ def make_event(name)
449
+ return {
450
+ :tagname => :event,
451
+ :name => name,
452
+ }
453
+ end
454
+
422
455
  def make_property(name=nil, ast=nil, tagname=:property)
423
456
  return {
424
457
  :tagname => tagname,
@@ -461,7 +494,7 @@ module JsDuck
461
494
  # are turned into strings, but values are left as is for further
462
495
  # processing.
463
496
  def each_pair_in_object_expression(ast)
464
- return unless ast && ast["type"] == "ObjectExpression"
497
+ return unless ast && object?(ast)
465
498
 
466
499
  ast["properties"].each do |p|
467
500
  yield(key_value(p["key"]), p["value"], p)
@@ -1,5 +1,6 @@
1
1
  require 'strscan'
2
2
  require 'jsduck/meta_tag_registry'
3
+ require 'jsduck/logger'
3
4
 
4
5
  module JsDuck
5
6
 
@@ -28,7 +29,9 @@ module JsDuck
28
29
  @meta_tags = MetaTagRegistry.instance
29
30
  end
30
31
 
31
- def parse(input)
32
+ def parse(input, filename="", linenr=0)
33
+ @filename = filename
34
+ @linenr = linenr
32
35
  @tags = []
33
36
  @input = StringScanner.new(purify(input))
34
37
  parse_loop
@@ -77,6 +80,11 @@ module JsDuck
77
80
  @tags << @current_tag = {:tagname => tag, :doc => ""}
78
81
  end
79
82
 
83
+ def remove_last_tag
84
+ @tags.pop
85
+ @current_tag = @tags.last
86
+ end
87
+
80
88
  def parse_loop
81
89
  add_tag(:default)
82
90
  while !@input.eos? do
@@ -141,19 +149,56 @@ module JsDuck
141
149
  elsif look(/@evented\b/)
142
150
  boolean_at_tag(/@evented/, :evented)
143
151
  elsif look(/@/)
144
- match(/@/)
145
- tag = @meta_tags[look(/\w+/)]
146
- if tag
147
- meta_at_tag(tag)
148
- else
149
- @current_tag[:doc] += "@"
150
- end
152
+ other_at_tag
151
153
  elsif look(/[^@]/)
152
- @current_tag[:doc] += match(/[^@]+/)
154
+ skip_to_next_at_tag
153
155
  end
154
156
  end
155
157
  end
156
158
 
159
+ # Skips until the beginning of next @tag.
160
+ #
161
+ # There must be space before the next @tag - this ensures that we
162
+ # don't detect tags inside "foo@example.com" or "{@link}".
163
+ #
164
+ # Also check that the @tag is not part of an indented code block -
165
+ # in which case we also ignore the tag.
166
+ def skip_to_next_at_tag
167
+ @current_tag[:doc] += match(/[^@]+/)
168
+
169
+ while look(/@/) && (!prev_char_is_whitespace? || indented_as_code?)
170
+ @current_tag[:doc] += match(/@+[^@]+/)
171
+ end
172
+ end
173
+
174
+ def prev_char_is_whitespace?
175
+ @current_tag[:doc][-1,1] =~ /\s/
176
+ end
177
+
178
+ def indented_as_code?
179
+ @current_tag[:doc] =~ /^ {4,}[^\n]*\Z/
180
+ end
181
+
182
+ # Processes anything else beginning with @-sign.
183
+ #
184
+ # - When @ is not followed by any word chards, do nothing.
185
+ # - When it's one of the meta-tags, process it as such.
186
+ # - When it's something else, print a warning.
187
+ #
188
+ def other_at_tag
189
+ match(/@/)
190
+
191
+ name = look(/\w+/)
192
+ tag = @meta_tags[name]
193
+
194
+ if tag
195
+ meta_at_tag(tag)
196
+ elsif name
197
+ Logger.warn(:tag, "Unsupported tag: @#{name}", @filename, @linenr)
198
+ @current_tag[:doc] += "@"
199
+ end
200
+ end
201
+
157
202
  # Matches the given meta-tag
158
203
  def meta_at_tag(tag)
159
204
  prev_tag = @current_tag
@@ -302,6 +347,14 @@ module JsDuck
302
347
  add_tag(:override)
303
348
  maybe_ident_chain(:class)
304
349
  skip_white
350
+
351
+ # When @override not followed by class name, ignore the tag.
352
+ # That's because the current ext codebase has some methods
353
+ # tagged with @override to denote they override something.
354
+ # But that's not what @override is meant for in JSDuck.
355
+ unless @current_tag[:class]
356
+ remove_last_tag
357
+ end
305
358
  end
306
359
 
307
360
  # matches @type {type} or @type type
@@ -12,7 +12,7 @@ module JsDuck
12
12
  def detect(docs, code)
13
13
  doc_map = build_doc_map(docs)
14
14
 
15
- if doc_map[:class]
15
+ if doc_map[:class] || doc_map[:override]
16
16
  :class
17
17
  elsif doc_map[:event]
18
18
  :event
@@ -57,4 +57,3 @@ module JsDuck
57
57
  end
58
58
 
59
59
  end
60
-
@@ -0,0 +1,58 @@
1
+ module JsDuck
2
+
3
+ # Identifies Ext JS builtins like Ext.define and Ext.extend, taking
4
+ # also into account the possibility of aliasing the Ext namespace.
5
+ #
6
+ # For example when the following command line option is used:
7
+ #
8
+ # --ext-namespaces=Ext,MyApp
9
+ #
10
+ # we need to identify both Ext.define and MyApp.define, but
11
+ # Ext.define is additionally aliased withing ExtJS as
12
+ # Ext.ClassManager.create, so we also need to recognize
13
+ # Ext.ClassManager.create and MyApp.ClassManager.create.
14
+ #
15
+ # The matches? method will take care of identifying all these four
16
+ # cases:
17
+ #
18
+ # ps = ExtPatterns.new(["Ext", "MyApp"])
19
+ # matches?("Ext.define", "MyApp.define") --> true
20
+ #
21
+ class ExtPatterns
22
+ def initialize(namespaces)
23
+ @patterns = {
24
+ "Ext.define" => build_patterns(namespaces, [".define", ".ClassManager.create"]),
25
+ "Ext.extend" => build_patterns(namespaces, [".extend"]),
26
+ "Ext.override" => build_patterns(namespaces, [".override"]),
27
+ "Ext.emptyFn" => build_patterns(namespaces, [".emptyFn"]),
28
+ }
29
+ end
30
+
31
+ # True when string matches the given pattern type.
32
+ #
33
+ # Pattern type is one of: "Ext.define", "Ext.extend",
34
+ # "Ext.override", "Ext.emptyFn"
35
+ def matches?(pattern, string)
36
+ @patterns[pattern].include?(string)
37
+ end
38
+
39
+ private
40
+
41
+ # Given Array of alternate Ext namespaces builds list of patterns
42
+ # for detecting Ext.define or some other construct:
43
+ #
44
+ # build_patterns(["Ext", "Foo"], [".define"]) --> ["Ext.define", "Foo.define"]
45
+ #
46
+ def build_patterns(namespaces, suffixes)
47
+ patterns = []
48
+ namespaces.each do |ns|
49
+ suffixes.each do |suffix|
50
+ patterns << ns + suffix
51
+ end
52
+ end
53
+ patterns
54
+ end
55
+
56
+ end
57
+
58
+ end
@@ -0,0 +1,30 @@
1
+ module JsDuck
2
+
3
+ # Handles patterns of external classes.
4
+ #
5
+ # A pattern can be a simple classname or a one with a wildcard "*".
6
+ class ExternalClasses
7
+
8
+ def initialize(classnames = [])
9
+ @class_names = {}
10
+ @patterns = []
11
+ classnames.each do |name|
12
+ if name =~ /\*/
13
+ @patterns << make_pattern(name)
14
+ else
15
+ @class_names[name] = true
16
+ end
17
+ end
18
+ end
19
+
20
+ # True if the classname matches an external class pattern.
21
+ def is?(classname)
22
+ @class_names[classname] || @patterns.any? {|p| classname =~ p }
23
+ end
24
+
25
+ def make_pattern(pattern)
26
+ Regexp.new("^" + pattern.split(/\*/, -1).map {|s| Regexp.escape(s) }.join(".*") + "$")
27
+ end
28
+ end
29
+
30
+ end
@@ -138,17 +138,17 @@ module JsDuck
138
138
 
139
139
  # True if range A is less than range B
140
140
  def less(a, b)
141
- return a[1] < b[0]
141
+ return a[1] <= b[0]
142
142
  end
143
143
 
144
144
  # True if range A is greater than range B
145
145
  def greater(a, b)
146
- return a[0] > b[1]
146
+ return a[0] >= b[1]
147
147
  end
148
148
 
149
149
  # True if range A is within range B
150
150
  def within(a, b)
151
- return b[0] < a[0] && a[1] < b[1]
151
+ return b[0] <= a[0] && a[1] <= b[1]
152
152
  end
153
153
 
154
154