jsduck 0.5 → 0.6
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 +30 -2
- data/bin/jsduck +24 -2
- data/jsduck.gemspec +2 -2
- data/lib/jsduck/aggregator.rb +53 -32
- data/lib/jsduck/app.rb +71 -22
- data/lib/jsduck/cfg_table.rb +2 -2
- data/lib/jsduck/class.rb +5 -0
- data/lib/jsduck/css_parser.rb +75 -0
- data/lib/jsduck/doc_formatter.rb +111 -20
- data/lib/jsduck/doc_parser.rb +64 -4
- data/lib/jsduck/event_table.rb +3 -3
- data/lib/jsduck/exporter.rb +11 -9
- data/lib/jsduck/inheritance_tree.rb +2 -7
- data/lib/jsduck/{parser.rb → js_parser.rb} +20 -4
- data/lib/jsduck/lexer.rb +1 -2
- data/lib/jsduck/long_params.rb +4 -8
- data/lib/jsduck/members.rb +15 -1
- data/lib/jsduck/merger.rb +50 -5
- data/lib/jsduck/method_table.rb +4 -8
- data/lib/jsduck/page.rb +20 -9
- data/lib/jsduck/property_table.rb +2 -2
- data/lib/jsduck/relations.rb +4 -0
- data/lib/jsduck/source_file.rb +101 -0
- data/lib/jsduck/{source_formatter.rb → source_writer.rb} +14 -27
- data/lib/jsduck/table.rb +12 -11
- data/template/resources/docs.js +43 -51
- metadata +8 -6
data/lib/jsduck/doc_formatter.rb
CHANGED
@@ -1,17 +1,31 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'rdiscount'
|
3
|
+
require 'strscan'
|
4
|
+
require 'cgi'
|
3
5
|
|
4
6
|
module JsDuck
|
5
7
|
|
6
8
|
# Formats doc-comments
|
7
9
|
class DocFormatter
|
8
|
-
#
|
9
|
-
|
10
|
+
# Template HTML that replaces {@link Class#member anchor text}.
|
11
|
+
# Can contain placeholders:
|
12
|
+
#
|
13
|
+
# %c - full class name (e.g. "Ext.Panel")
|
14
|
+
# %m - class member name (e.g. "urlEncode")
|
15
|
+
# %M - class member name, prefixed with hash (e.g. "#urlEncode")
|
16
|
+
# %a - anchor text for link
|
17
|
+
#
|
18
|
+
# Default value: '<a href="%c%M">%a</a>'
|
19
|
+
attr_accessor :link_tpl
|
10
20
|
|
11
|
-
# Template
|
12
|
-
# Can contain
|
13
|
-
#
|
14
|
-
|
21
|
+
# Template HTML that replaces {@img URL alt text}
|
22
|
+
# Can contain placeholders:
|
23
|
+
#
|
24
|
+
# %u - URL from @img tag (e.g. "some/path.png")
|
25
|
+
# %a - alt text for image
|
26
|
+
#
|
27
|
+
# Default value: '<img src="%u" alt="%a"/>'
|
28
|
+
attr_accessor :img_tpl
|
15
29
|
|
16
30
|
# Sets up instance to work in context of particular class, so
|
17
31
|
# that when {@link #blah} is encountered it knows that
|
@@ -21,19 +35,53 @@ module JsDuck
|
|
21
35
|
# Maximum length for text that doesn't get shortened, defaults to 120
|
22
36
|
attr_accessor :max_length
|
23
37
|
|
38
|
+
# JsDuck::Relations for looking up class names.
|
39
|
+
#
|
40
|
+
# When auto-creating class links from CamelCased names found from
|
41
|
+
# text, we check the relations object to see if a class with that
|
42
|
+
# name actually exists.
|
43
|
+
attr_accessor :relations
|
44
|
+
|
24
45
|
def initialize
|
25
46
|
@context = ""
|
26
|
-
@css_class = nil
|
27
|
-
@url_template = "%cls%"
|
28
47
|
@max_length = 120
|
48
|
+
@relations = {}
|
49
|
+
@link_tpl = '<a href="%c%M">%a</a>'
|
50
|
+
@img_tpl = '<img src="%u" alt="%a"/>'
|
51
|
+
@link_re = /\{@link\s+(\S*?)(?:\s+(.+?))?\}/m
|
52
|
+
@img_re = /\{@img\s+(\S*?)(?:\s+(.+?))?\}/m
|
29
53
|
end
|
30
54
|
|
55
|
+
# Replaces {@link} and {@img} tags, auto-generates links for
|
56
|
+
# recognized classnames.
|
57
|
+
#
|
31
58
|
# Replaces {@link Class#member link text} in given string with
|
32
|
-
# HTML
|
33
|
-
#
|
34
|
-
#
|
59
|
+
# HTML from @link_tpl.
|
60
|
+
#
|
61
|
+
# Replaces {@img path/to/image.jpg Alt text} with HTML from @img_tpl.
|
62
|
+
#
|
63
|
+
# Additionally replaces strings recognized as ClassNames with
|
64
|
+
# links to these classes. So one doesn even need to use the @link
|
65
|
+
# tag to create a link.
|
35
66
|
def replace(input)
|
36
|
-
|
67
|
+
s = StringScanner.new(input)
|
68
|
+
out = ""
|
69
|
+
while !s.eos? do
|
70
|
+
if s.check(@link_re)
|
71
|
+
out += replace_link_tag(s.scan(@link_re))
|
72
|
+
elsif s.check(@img_re)
|
73
|
+
out += replace_img_tag(s.scan(@img_re))
|
74
|
+
elsif s.check(/\{/)
|
75
|
+
out += s.scan(/\{/)
|
76
|
+
else
|
77
|
+
out += replace_class_names(s.scan(/[^{]+/))
|
78
|
+
end
|
79
|
+
end
|
80
|
+
out
|
81
|
+
end
|
82
|
+
|
83
|
+
def replace_link_tag(input)
|
84
|
+
input.sub(@link_re) do
|
37
85
|
target = $1
|
38
86
|
text = $2
|
39
87
|
if target =~ /^(.*)#(.*)$/
|
@@ -57,14 +105,57 @@ module JsDuck
|
|
57
105
|
end
|
58
106
|
end
|
59
107
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
108
|
+
def replace_img_tag(input)
|
109
|
+
input.sub(@img_re) { img($1, $2) }
|
110
|
+
end
|
111
|
+
|
112
|
+
def replace_class_names(input)
|
113
|
+
input.gsub(/(\A|\s)([A-Z][A-Za-z0-9.]*[A-Za-z0-9])(?:(#)([A-Za-z0-9]+))?([.,]?(?:\s|\Z))/m) do
|
114
|
+
before = $1
|
115
|
+
cls = $2
|
116
|
+
hash = $3
|
117
|
+
method = $4
|
118
|
+
after = $5
|
119
|
+
|
120
|
+
if @relations[cls]
|
121
|
+
label = method ? cls+"."+method : cls
|
122
|
+
before + link(cls, method, label) + after
|
123
|
+
else
|
124
|
+
before + cls + (hash || "") + (method || "") + after
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
# applies the image template
|
130
|
+
def img(url, alt_text)
|
131
|
+
@img_tpl.gsub(/(%\w)/) do
|
132
|
+
case $1
|
133
|
+
when '%u'
|
134
|
+
url
|
135
|
+
when '%a'
|
136
|
+
CGI.escapeHTML(alt_text||"")
|
137
|
+
else
|
138
|
+
$1
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
# applies the link template
|
144
|
+
def link(cls, member, anchor_text)
|
145
|
+
@link_tpl.gsub(/(%\w)/) do
|
146
|
+
case $1
|
147
|
+
when '%c'
|
148
|
+
cls
|
149
|
+
when '%m'
|
150
|
+
member ? member : ""
|
151
|
+
when '%M'
|
152
|
+
member ? "#"+member : ""
|
153
|
+
when '%a'
|
154
|
+
CGI.escapeHTML(anchor_text||"")
|
155
|
+
else
|
156
|
+
$1
|
157
|
+
end
|
158
|
+
end
|
68
159
|
end
|
69
160
|
|
70
161
|
# Formats doc-comment for placement into HTML.
|
data/lib/jsduck/doc_parser.rb
CHANGED
@@ -21,6 +21,11 @@ module JsDuck
|
|
21
21
|
# @see and {@link} are parsed separately in JsDuck::DocFormatter.
|
22
22
|
#
|
23
23
|
class DocParser
|
24
|
+
# Pass in :css to be able to parse CSS doc-comments
|
25
|
+
def initialize(mode = :js)
|
26
|
+
@ident_pattern = (mode == :css) ? /\$[a-zA-Z0-9_-]*/ : /\w+/
|
27
|
+
end
|
28
|
+
|
24
29
|
def parse(input)
|
25
30
|
@tags = []
|
26
31
|
@input = StringScanner.new(purify(input))
|
@@ -66,8 +71,12 @@ module JsDuck
|
|
66
71
|
while !@input.eos? do
|
67
72
|
if look(/@class\b/)
|
68
73
|
at_class
|
69
|
-
elsif look(/@extends
|
74
|
+
elsif look(/@extends?\b/)
|
70
75
|
at_extends
|
76
|
+
elsif look(/@mixins?\b/)
|
77
|
+
at_mixins
|
78
|
+
elsif look(/@alternateClassNames?\b/)
|
79
|
+
at_alternateClassName
|
71
80
|
elsif look(/@singleton\b/)
|
72
81
|
boolean_at_tag(/@singleton/, :singleton)
|
73
82
|
elsif look(/@event\b/)
|
@@ -92,6 +101,10 @@ module JsDuck
|
|
92
101
|
at_member
|
93
102
|
elsif look(/@author\b/)
|
94
103
|
at_author
|
104
|
+
elsif look(/@docauthor\b/)
|
105
|
+
at_docauthor
|
106
|
+
elsif look(/@var\b/)
|
107
|
+
at_var
|
95
108
|
elsif look(/@static\b/)
|
96
109
|
boolean_at_tag(/@static/, :static)
|
97
110
|
elsif look(/@(private|ignore|hide|protected)\b/)
|
@@ -117,12 +130,30 @@ module JsDuck
|
|
117
130
|
|
118
131
|
# matches @extends name ...
|
119
132
|
def at_extends
|
120
|
-
match(/@extends
|
133
|
+
match(/@extends?/)
|
121
134
|
add_tag(:extends)
|
122
135
|
maybe_ident_chain(:extends)
|
123
136
|
skip_white
|
124
137
|
end
|
125
138
|
|
139
|
+
# matches @mixins name1 name2 ...
|
140
|
+
def at_mixins
|
141
|
+
match(/@mixins?/)
|
142
|
+
add_tag(:mixins)
|
143
|
+
skip_horiz_white
|
144
|
+
@current_tag[:mixins] = class_list
|
145
|
+
skip_white
|
146
|
+
end
|
147
|
+
|
148
|
+
# matches @alternateClassName name1 name2 ...
|
149
|
+
def at_alternateClassName
|
150
|
+
match(/@alternateClassNames?/)
|
151
|
+
add_tag(:alternateClassNames)
|
152
|
+
skip_horiz_white
|
153
|
+
@current_tag[:alternateClassNames] = class_list
|
154
|
+
skip_white
|
155
|
+
end
|
156
|
+
|
126
157
|
# matches @event name ...
|
127
158
|
def at_event
|
128
159
|
match(/@event/)
|
@@ -179,6 +210,15 @@ module JsDuck
|
|
179
210
|
skip_white
|
180
211
|
end
|
181
212
|
|
213
|
+
# matches @var {type} $name ...
|
214
|
+
def at_var
|
215
|
+
match(/@var/)
|
216
|
+
add_tag(:css_var)
|
217
|
+
maybe_type
|
218
|
+
maybe_name
|
219
|
+
skip_white
|
220
|
+
end
|
221
|
+
|
182
222
|
# matches @type {type} or @type type
|
183
223
|
#
|
184
224
|
# The presence of @type implies that we are dealing with property.
|
@@ -221,6 +261,15 @@ module JsDuck
|
|
221
261
|
skip_white
|
222
262
|
end
|
223
263
|
|
264
|
+
# matches @docauthor some name ... newline
|
265
|
+
def at_docauthor
|
266
|
+
match(/@docauthor/)
|
267
|
+
add_tag(:docauthor)
|
268
|
+
skip_horiz_white
|
269
|
+
@current_tag[:name] = @input.scan(/.*$/)
|
270
|
+
skip_white
|
271
|
+
end
|
272
|
+
|
224
273
|
# Used to match @private, @ignore, @hide, ...
|
225
274
|
def boolean_at_tag(regex, propname)
|
226
275
|
match(regex)
|
@@ -239,8 +288,8 @@ module JsDuck
|
|
239
288
|
# matches identifier name if possible and sets it on @current_tag
|
240
289
|
def maybe_name
|
241
290
|
skip_horiz_white
|
242
|
-
if look(
|
243
|
-
@current_tag[:name] =
|
291
|
+
if look(@ident_pattern)
|
292
|
+
@current_tag[:name] = @input.scan(@ident_pattern)
|
244
293
|
end
|
245
294
|
end
|
246
295
|
|
@@ -260,6 +309,17 @@ module JsDuck
|
|
260
309
|
return name
|
261
310
|
end
|
262
311
|
|
312
|
+
# matches <ident_chain> <ident_chain> ... until line end
|
313
|
+
def class_list
|
314
|
+
skip_horiz_white
|
315
|
+
classes = []
|
316
|
+
while look(/\w/)
|
317
|
+
classes << ident_chain
|
318
|
+
skip_horiz_white
|
319
|
+
end
|
320
|
+
classes
|
321
|
+
end
|
322
|
+
|
263
323
|
# matches chained.identifier.name and returns it
|
264
324
|
def ident_chain
|
265
325
|
@input.scan(/[\w.]+/)
|
data/lib/jsduck/event_table.rb
CHANGED
@@ -5,15 +5,15 @@ require 'jsduck/long_params'
|
|
5
5
|
module JsDuck
|
6
6
|
|
7
7
|
class EventTable < Table
|
8
|
-
def initialize(cls, cache={})
|
9
|
-
super(cls, cache)
|
8
|
+
def initialize(cls, formatter, cache={})
|
9
|
+
super(cls, formatter, cache)
|
10
10
|
@type = :event
|
11
11
|
@id = @cls.full_name + "-events"
|
12
12
|
@title = "Public Events"
|
13
13
|
@column_title = "Event"
|
14
14
|
@row_class = "event-row"
|
15
15
|
@short_params = ShortParams.new
|
16
|
-
@long_params = LongParams.new(@
|
16
|
+
@long_params = LongParams.new(@formatter)
|
17
17
|
end
|
18
18
|
|
19
19
|
def signature_suffix(item)
|
data/lib/jsduck/exporter.rb
CHANGED
@@ -9,29 +9,31 @@ module JsDuck
|
|
9
9
|
# Also all the :doc elements will be formatted - converted from
|
10
10
|
# markdown to HTML and @links resolved.
|
11
11
|
class Exporter
|
12
|
-
|
13
|
-
|
14
|
-
def initialize(relations)
|
12
|
+
def initialize(relations, formatter)
|
15
13
|
@relations = relations
|
16
|
-
@formatter =
|
17
|
-
@formatter.css_class = 'docClass'
|
14
|
+
@formatter = formatter
|
18
15
|
end
|
19
16
|
|
20
17
|
# Returns all data in Class object as hash.
|
21
18
|
def export(cls)
|
22
19
|
h = cls.to_hash
|
23
20
|
h[:cfgs] = cls.members(:cfg)
|
24
|
-
h[:properties] = cls.members(:property)
|
25
|
-
h[:methods] = cls.members(:method)
|
26
|
-
h[:events] = cls.members(:event)
|
27
21
|
h.delete(:cfg)
|
22
|
+
h[:properties] = cls.members(:property)
|
28
23
|
h.delete(:property)
|
24
|
+
h[:methods] = cls.members(:method)
|
29
25
|
h.delete(:method)
|
26
|
+
h[:events] = cls.members(:event)
|
30
27
|
h.delete(:event)
|
28
|
+
h[:cssVars] = cls.members(:css_var)
|
29
|
+
h.delete(:css_var)
|
30
|
+
h[:cssMixins] = cls.members(:css_mixin)
|
31
|
+
h.delete(:css_mixin)
|
31
32
|
h[:component] = cls.inherits_from?("Ext.Component")
|
32
33
|
h[:superclasses] = cls.superclasses.collect {|c| c.full_name }
|
33
34
|
h[:subclasses] = @relations.subclasses(cls).collect {|c| c.full_name }
|
34
35
|
h[:mixedInto] = @relations.mixed_into(cls).collect {|c| c.full_name }
|
36
|
+
h[:allMixins] = cls.all_mixins.collect {|c| c.full_name }
|
35
37
|
format_class(h)
|
36
38
|
end
|
37
39
|
|
@@ -39,7 +41,7 @@ module JsDuck
|
|
39
41
|
def format_class(c)
|
40
42
|
@formatter.context = c[:name]
|
41
43
|
c[:doc] = @formatter.format(c[:doc]) if c[:doc]
|
42
|
-
[:cfgs, :properties, :methods, :events].each do |type|
|
44
|
+
[:cfgs, :properties, :methods, :events, :cssVars, :cssMixins].each do |type|
|
43
45
|
c[type] = c[type].map {|m| format_member(m) }
|
44
46
|
end
|
45
47
|
c
|
@@ -1,15 +1,10 @@
|
|
1
|
-
require 'jsduck/doc_formatter'
|
2
|
-
|
3
1
|
module JsDuck
|
4
2
|
|
5
3
|
# Creates the inheritance tree shown on class documentation page.
|
6
4
|
class InheritanceTree
|
7
|
-
def initialize(cls)
|
5
|
+
def initialize(cls, formatter)
|
8
6
|
@cls = cls
|
9
|
-
@formatter =
|
10
|
-
@formatter.context = cls.full_name
|
11
|
-
@formatter.css_class = 'docClass'
|
12
|
-
@formatter.url_template = 'output/%cls%.html'
|
7
|
+
@formatter = formatter
|
13
8
|
end
|
14
9
|
|
15
10
|
# Renders the tree using HTML <pre> element
|
@@ -3,7 +3,7 @@ require 'jsduck/doc_parser'
|
|
3
3
|
|
4
4
|
module JsDuck
|
5
5
|
|
6
|
-
class
|
6
|
+
class JsParser
|
7
7
|
def initialize(input)
|
8
8
|
@lex = Lexer.new(input)
|
9
9
|
@doc_parser = DocParser.new
|
@@ -195,7 +195,7 @@ module JsDuck
|
|
195
195
|
cfg
|
196
196
|
end
|
197
197
|
|
198
|
-
# <ext-define-cfg> := "{" ( <extend> | <mixins> | <?> )*
|
198
|
+
# <ext-define-cfg> := "{" ( <extend> | <mixins> | <alternate-class-name> | <?> )*
|
199
199
|
def ext_define_cfg
|
200
200
|
match("{")
|
201
201
|
cfg = {}
|
@@ -208,6 +208,9 @@ module JsDuck
|
|
208
208
|
elsif look("mixins", ":", "{")
|
209
209
|
cfg[:mixins] = ext_define_mixins
|
210
210
|
found = true
|
211
|
+
elsif look("alternateClassName", ":")
|
212
|
+
cfg[:alternateClassNames] = ext_define_alternate_class_name
|
213
|
+
found = true
|
211
214
|
elsif look(:ident, ":")
|
212
215
|
match(:ident, ":")
|
213
216
|
if look(:string) || look(:number) || look(:regex) ||
|
@@ -231,6 +234,18 @@ module JsDuck
|
|
231
234
|
match("extend", ":", :string)
|
232
235
|
end
|
233
236
|
|
237
|
+
# <ext-define-alternate-class-name> := "alternateClassName" ":" ( <string> | <array-of-strings> )
|
238
|
+
def ext_define_alternate_class_name
|
239
|
+
match("alternateClassName", ":")
|
240
|
+
if look(:string)
|
241
|
+
[ match(:string) ]
|
242
|
+
elsif look("[")
|
243
|
+
array_of_strings
|
244
|
+
else
|
245
|
+
[]
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
234
249
|
# <ext-define-mixins> := "mixins" ":" "{" [ <ident> ":" <string> ","? ]* "}"
|
235
250
|
def ext_define_mixins
|
236
251
|
match("mixins", ":", "{")
|
@@ -246,14 +261,15 @@ module JsDuck
|
|
246
261
|
# <array-of-strings> := "[" [ <string> ","? ]* "]"
|
247
262
|
def array_of_strings
|
248
263
|
match("[")
|
264
|
+
strs = []
|
249
265
|
while look(:string)
|
250
|
-
match(:string)
|
266
|
+
strs << match(:string)
|
251
267
|
match(",") if look(",")
|
252
268
|
end
|
253
269
|
|
254
270
|
if look("]")
|
255
271
|
match("]")
|
256
|
-
|
272
|
+
strs
|
257
273
|
else
|
258
274
|
false
|
259
275
|
end
|
data/lib/jsduck/lexer.rb
CHANGED
@@ -135,8 +135,7 @@ module JsDuck
|
|
135
135
|
nr = @input.scan(/[0-9]+(\.[0-9]*)?/)
|
136
136
|
@tokens << {
|
137
137
|
:type => :number,
|
138
|
-
|
139
|
-
:value => eval(/\.$/ =~ nr ? nr+"0" : nr)
|
138
|
+
:value => nr
|
140
139
|
}
|
141
140
|
elsif @input.check(/\$/)
|
142
141
|
value = @input.scan(/\$\w*/)
|