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.
- data/.travis.yml +1 -1
- data/README.md +1 -0
- data/Rakefile +1 -1
- data/jsduck.gemspec +3 -3
- data/lib/jsduck/ast.rb +59 -26
- data/lib/jsduck/doc_parser.rb +62 -9
- data/lib/jsduck/doc_type.rb +1 -2
- data/lib/jsduck/ext_patterns.rb +58 -0
- data/lib/jsduck/external_classes.rb +30 -0
- data/lib/jsduck/js_parser.rb +3 -3
- data/lib/jsduck/logger.rb +1 -0
- data/lib/jsduck/options.rb +9 -1
- data/lib/jsduck/override.rb +12 -4
- data/lib/jsduck/relations.rb +4 -3
- data/lib/jsduck/source/file_parser.rb +1 -1
- data/lib/jsduck/type_parser.rb +3 -3
- metadata +406 -400
data/.travis.yml
CHANGED
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
|
|
data/jsduck.gemspec
CHANGED
@@ -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.
|
6
|
-
s.date = '2012-
|
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'
|
data/lib/jsduck/ast.rb
CHANGED
@@ -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
|
-
@
|
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
|
-
#
|
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(
|
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) &&
|
157
|
+
call?(ast) && ext_pattern?("Ext.define", ast["callee"])
|
156
158
|
end
|
157
159
|
|
158
160
|
def ext_extend?(ast)
|
159
|
-
call?(ast) &&
|
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" &&
|
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
|
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
|
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
|
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)
|
data/lib/jsduck/doc_parser.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
data/lib/jsduck/doc_type.rb
CHANGED
@@ -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
|
data/lib/jsduck/js_parser.rb
CHANGED
@@ -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]
|
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]
|
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]
|
151
|
+
return b[0] <= a[0] && a[1] <= b[1]
|
152
152
|
end
|
153
153
|
|
154
154
|
|