jsduck 3.0.pre → 3.0.pre2
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 +21 -229
- data/Rakefile +31 -17
- data/bin/jsduck +1 -0
- data/js-classes/Array.js +561 -0
- data/js-classes/Boolean.js +110 -0
- data/js-classes/Date.js +999 -0
- data/js-classes/Function.js +256 -0
- data/js-classes/Number.js +308 -0
- data/js-classes/Object.js +404 -0
- data/js-classes/RegExp.js +415 -0
- data/js-classes/String.js +1034 -0
- data/jsduck.gemspec +2 -2
- data/lib/jsduck/accessors.rb +71 -0
- data/lib/jsduck/aggregator.rb +14 -2
- data/lib/jsduck/app.rb +6 -5
- data/lib/jsduck/class_formatter.rb +12 -8
- data/lib/jsduck/css_parser.rb +2 -2
- data/lib/jsduck/doc_formatter.rb +2 -2
- data/lib/jsduck/doc_parser.rb +32 -25
- data/lib/jsduck/exporter.rb +1 -1
- data/lib/jsduck/guides.rb +11 -2
- data/lib/jsduck/js_parser.rb +30 -8
- data/lib/jsduck/merger.rb +31 -16
- data/lib/jsduck/options.rb +93 -15
- data/lib/jsduck/renderer.rb +40 -3
- data/lib/jsduck/search_data.rb +8 -5
- data/lib/jsduck/source_file.rb +5 -4
- data/lib/jsduck/type_parser.rb +7 -6
- metadata +17 -5
- data/example.js +0 -144
data/jsduck.gemspec
CHANGED
@@ -2,8 +2,8 @@ Gem::Specification.new do |s|
|
|
2
2
|
s.required_rubygems_version = ">= 1.3.7"
|
3
3
|
|
4
4
|
s.name = 'jsduck'
|
5
|
-
s.version = '3.0.
|
6
|
-
s.date = '2011-09-
|
5
|
+
s.version = '3.0.pre2'
|
6
|
+
s.date = '2011-09-20'
|
7
7
|
s.summary = "Simple JavaScript Duckumentation generator"
|
8
8
|
s.description = "Documentation generator for ExtJS 4"
|
9
9
|
s.homepage = "https://github.com/senchalabs/jsduck"
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'jsduck/logger'
|
2
|
+
|
3
|
+
module JsDuck
|
4
|
+
|
5
|
+
class Accessors
|
6
|
+
# Given a class, generates accessor methods to configs with
|
7
|
+
# @accessor tag. Modifies the class by adding these methods.
|
8
|
+
# When class already contains a getter or setter, the method is
|
9
|
+
# not added.
|
10
|
+
def create(cls)
|
11
|
+
# Grab all configs tagged as @accessor
|
12
|
+
accessors = cls[:members][:cfg].find_all {|cfg| cfg[:accessor] }
|
13
|
+
|
14
|
+
# Build lookup table of method names
|
15
|
+
methods = {}
|
16
|
+
cls[:members][:method].each do |m|
|
17
|
+
methods[m[:name]] = m;
|
18
|
+
end
|
19
|
+
|
20
|
+
accessors.each do |cfg|
|
21
|
+
# add getter if no method with same name exists
|
22
|
+
get = create_getter(cfg)
|
23
|
+
if !methods[get[:name]]
|
24
|
+
cls[:members][:method] << get
|
25
|
+
end
|
26
|
+
# add setter if no method with same name exists
|
27
|
+
set = create_setter(cfg)
|
28
|
+
if !methods[set[:name]]
|
29
|
+
cls[:members][:method] << set
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def create_getter(cfg)
|
35
|
+
return {
|
36
|
+
:tagname => :method,
|
37
|
+
:name => "get" + upcase_first(cfg[:name]),
|
38
|
+
:doc => "Returns the value of {@link #cfg-#{cfg[:name]}}.",
|
39
|
+
:params => [],
|
40
|
+
:return => {
|
41
|
+
:type => cfg[:type],
|
42
|
+
:doc => "",
|
43
|
+
},
|
44
|
+
:owner => cfg[:owner],
|
45
|
+
}
|
46
|
+
end
|
47
|
+
|
48
|
+
def create_setter(cfg)
|
49
|
+
return {
|
50
|
+
:tagname => :method,
|
51
|
+
:name => "set" + upcase_first(cfg[:name]),
|
52
|
+
:doc => "Sets the value of {@link #cfg-#{cfg[:name]}}.",
|
53
|
+
:params => [{
|
54
|
+
:type => cfg[:type],
|
55
|
+
:name => cfg[:name],
|
56
|
+
:doc => "",
|
57
|
+
}],
|
58
|
+
:return => {
|
59
|
+
:type => "undefined",
|
60
|
+
:doc => "",
|
61
|
+
},
|
62
|
+
:owner => cfg[:owner],
|
63
|
+
}
|
64
|
+
end
|
65
|
+
|
66
|
+
def upcase_first(str)
|
67
|
+
str[0,1].upcase + str[1..-1]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
data/lib/jsduck/aggregator.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'jsduck/class'
|
2
|
+
require 'jsduck/accessors'
|
2
3
|
|
3
4
|
module JsDuck
|
4
5
|
|
@@ -50,12 +51,15 @@ module JsDuck
|
|
50
51
|
|
51
52
|
# Merges new class-doc into old one.
|
52
53
|
def merge_classes(old, new)
|
53
|
-
[:extends, :
|
54
|
+
[:extends, :singleton, :private, :protected].each do |tag|
|
54
55
|
old[tag] = old[tag] || new[tag]
|
55
56
|
end
|
56
|
-
[:mixins, :alternateClassNames
|
57
|
+
[:mixins, :alternateClassNames].each do |tag|
|
57
58
|
old[tag] = old[tag] + new[tag]
|
58
59
|
end
|
60
|
+
new[:xtypes].each_pair do |key, xtypes|
|
61
|
+
old[:xtypes][key] = (old[:xtypes][key] || []) + xtypes
|
62
|
+
end
|
59
63
|
old[:doc] = old[:doc].length > 0 ? old[:doc] : new[:doc]
|
60
64
|
# Additionally the doc-comment can contain configs and constructor
|
61
65
|
old[:members][:cfg] += new[:members][:cfg]
|
@@ -162,6 +166,14 @@ module JsDuck
|
|
162
166
|
end
|
163
167
|
end
|
164
168
|
|
169
|
+
# Creates accessor method for configs marked with @accessor
|
170
|
+
def create_accessors
|
171
|
+
accessors = Accessors.new
|
172
|
+
@classes.each_value do |cls|
|
173
|
+
accessors.create(cls)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
165
177
|
# Are we dealing with ExtJS 4?
|
166
178
|
# True if any of the classes is defined with Ext.define()
|
167
179
|
def ext4?
|
data/lib/jsduck/app.rb
CHANGED
@@ -82,8 +82,6 @@ module JsDuck
|
|
82
82
|
@timer.time(:generating) { puts JsonDuck.generate(@relations.classes) }
|
83
83
|
elsif @opts.export == :json
|
84
84
|
FileUtils.mkdir(@opts.output_dir)
|
85
|
-
init_output_dirs
|
86
|
-
@timer.time(:generating) { write_src(parsed_files) }
|
87
85
|
@timer.time(:generating) { format_classes }
|
88
86
|
@timer.time(:generating) { write_classes }
|
89
87
|
else
|
@@ -114,7 +112,7 @@ module JsDuck
|
|
114
112
|
def parallel_parse(filenames)
|
115
113
|
@parallel.map(filenames) do |fname|
|
116
114
|
Logger.instance.log("Parsing #{fname} ...")
|
117
|
-
SourceFile.new(IO.read(fname), fname)
|
115
|
+
SourceFile.new(IO.read(fname), fname, @opts)
|
118
116
|
end
|
119
117
|
end
|
120
118
|
|
@@ -127,6 +125,7 @@ module JsDuck
|
|
127
125
|
end
|
128
126
|
agr.classify_orphans
|
129
127
|
agr.create_global_class unless @opts.ignore_global
|
128
|
+
agr.create_accessors
|
130
129
|
agr.append_ext4_event_options
|
131
130
|
agr.result
|
132
131
|
end
|
@@ -179,9 +178,10 @@ module JsDuck
|
|
179
178
|
# Writes JSON export or JsonP file for each class
|
180
179
|
def write_classes
|
181
180
|
exporter = Exporter.new(@relations)
|
182
|
-
renderer = Renderer.new
|
181
|
+
renderer = Renderer.new(@opts)
|
182
|
+
dir = @opts.output_dir + (@opts.export ? "" : "/output")
|
183
183
|
@parallel.each(@relations.classes) do |cls|
|
184
|
-
filename =
|
184
|
+
filename = dir + "/" + cls[:name] + (@opts.export ? ".json" : ".js")
|
185
185
|
Logger.instance.log("Writing to #{filename} ...")
|
186
186
|
data = exporter.export(cls)
|
187
187
|
if @opts.export
|
@@ -251,6 +251,7 @@ module JsDuck
|
|
251
251
|
"{footer}" => "<div id='footer-content' style='display: none'>#{@opts.footer}</div>",
|
252
252
|
"{extjs_path}" => @opts.extjs_path,
|
253
253
|
"{local_storage_db}" => @opts.local_storage_db,
|
254
|
+
"{show_print_button}" => @opts.seo ? "true" : "false",
|
254
255
|
"{welcome}" => @welcome.to_html,
|
255
256
|
"{categories}" => @categories.to_html,
|
256
257
|
"{guides}" => @guides.to_html,
|
@@ -39,21 +39,25 @@ module JsDuck
|
|
39
39
|
if expandable?(m) || @formatter.too_long?(m[:doc])
|
40
40
|
m[:shortDoc] = @formatter.shorten(m[:doc])
|
41
41
|
end
|
42
|
-
|
43
|
-
|
44
|
-
m[:
|
45
|
-
|
42
|
+
|
43
|
+
# We don't validate and format CSS var and mixin type definitions
|
44
|
+
is_css_tag = m[:tagname] == :css_var || m[:tagname] == :css_mixin
|
45
|
+
|
46
|
+
m[:html_type] = (@include_types && !is_css_tag) ? format_type(m[:type]) : m[:type] if m[:type]
|
47
|
+
m[:params] = m[:params].map {|p| format_item(p, is_css_tag) } if m[:params]
|
48
|
+
m[:return] = format_item(m[:return], is_css_tag) if m[:return]
|
49
|
+
m[:properties] = m[:properties].map {|b| format_item(b, is_css_tag) } if m[:properties]
|
46
50
|
m
|
47
51
|
end
|
48
52
|
|
49
53
|
def expandable?(m)
|
50
|
-
m[:params] || (m[:properties] && m[:properties].length > 0) || m[:default] || m[:deprecated]
|
54
|
+
m[:params] || (m[:properties] && m[:properties].length > 0) || m[:default] || m[:deprecated] || m[:template]
|
51
55
|
end
|
52
56
|
|
53
|
-
def format_item(it)
|
57
|
+
def format_item(it, is_css_tag)
|
54
58
|
it[:doc] = @formatter.format(it[:doc]) if it[:doc]
|
55
|
-
it[:html_type] = format_type(it[:type])
|
56
|
-
it[:properties] = it[:properties].map {|s| format_item(s) } if it[:properties]
|
59
|
+
it[:html_type] = (@include_types && !is_css_tag) ? format_type(it[:type]) : it[:type] if it[:type]
|
60
|
+
it[:properties] = it[:properties].map {|s| format_item(s, is_css_tag) } if it[:properties]
|
57
61
|
it
|
58
62
|
end
|
59
63
|
|
data/lib/jsduck/css_parser.rb
CHANGED
@@ -4,9 +4,9 @@ require 'jsduck/doc_parser'
|
|
4
4
|
module JsDuck
|
5
5
|
|
6
6
|
class CssParser
|
7
|
-
def initialize(input)
|
7
|
+
def initialize(input, options = {})
|
8
8
|
@lex = Lexer.new(input)
|
9
|
-
@doc_parser = DocParser.new(:css)
|
9
|
+
@doc_parser = DocParser.new(:css, options[:meta_tags])
|
10
10
|
@docs = []
|
11
11
|
end
|
12
12
|
|
data/lib/jsduck/doc_formatter.rb
CHANGED
@@ -202,14 +202,14 @@ module JsDuck
|
|
202
202
|
# Use the canonical class name for link (not some alternateClassName)
|
203
203
|
cls = @relations[cls].full_name
|
204
204
|
# prepend type name to member name
|
205
|
-
member = member &&
|
205
|
+
member = member && get_member(cls, member, type)
|
206
206
|
|
207
207
|
@link_tpl.gsub(/(%[\w#-])/) do
|
208
208
|
case $1
|
209
209
|
when '%c'
|
210
210
|
cls
|
211
211
|
when '%m'
|
212
|
-
member ? member : ""
|
212
|
+
member ? member[:id] : ""
|
213
213
|
when '%#'
|
214
214
|
member ? "#" : ""
|
215
215
|
when '%-'
|
data/lib/jsduck/doc_parser.rb
CHANGED
@@ -24,9 +24,14 @@ module JsDuck
|
|
24
24
|
#
|
25
25
|
class DocParser
|
26
26
|
# Pass in :css to be able to parse CSS doc-comments
|
27
|
-
def initialize(mode = :js)
|
27
|
+
def initialize(mode = :js, meta_tags = nil)
|
28
28
|
@ident_pattern = (mode == :css) ? /\$?[\w-]+/ : /[$\w]\w*/
|
29
29
|
@ident_chain_pattern = (mode == :css) ? /\$?[\w-]+(\.[\w-]+)*/ : /[$\w]\w*(\.\w+)*/
|
30
|
+
|
31
|
+
@meta_tags_map = {}
|
32
|
+
(meta_tags || []).each do |tag|
|
33
|
+
@meta_tags_map[tag[:name]] = true
|
34
|
+
end
|
30
35
|
end
|
31
36
|
|
32
37
|
def parse(input)
|
@@ -54,12 +59,23 @@ module JsDuck
|
|
54
59
|
# Now we are left with only two types of lines:
|
55
60
|
# - those beginning with *
|
56
61
|
# - and those without it
|
62
|
+
indent = nil
|
57
63
|
input.each_line do |line|
|
58
64
|
line.chomp!
|
59
65
|
if line =~ /\A\s*\*\s?(.*)\Z/
|
66
|
+
# When comment contains *-lines, switch indent-trimming off
|
67
|
+
indent = 0
|
60
68
|
result << $1
|
61
|
-
|
69
|
+
elsif line =~ /\A\s*\Z/
|
70
|
+
# pass-through empty lines
|
62
71
|
result << line
|
72
|
+
elsif indent == nil && line =~ /\A(\s*)(.*?\Z)/
|
73
|
+
# When indent not measured, measure it and remember
|
74
|
+
indent = $1.length
|
75
|
+
result << $2
|
76
|
+
else
|
77
|
+
# Trim away indent if available
|
78
|
+
result << line.sub(/\A\s{0,#{indent||0}}/, "")
|
63
79
|
end
|
64
80
|
end
|
65
81
|
return result.join("\n")
|
@@ -106,10 +122,6 @@ module JsDuck
|
|
106
122
|
at_member
|
107
123
|
elsif look(/@alias\b/)
|
108
124
|
at_alias
|
109
|
-
elsif look(/@author\b/)
|
110
|
-
at_author
|
111
|
-
elsif look(/@docauthor\b/)
|
112
|
-
at_docauthor
|
113
125
|
elsif look(/@deprecated\b/)
|
114
126
|
at_deprecated
|
115
127
|
elsif look(/@var\b/)
|
@@ -122,6 +134,10 @@ module JsDuck
|
|
122
134
|
boolean_at_tag(/@(private|ignore|hide)/, :private)
|
123
135
|
elsif look(/@protected\b/)
|
124
136
|
boolean_at_tag(/@protected/, :protected)
|
137
|
+
elsif look(/@accessor\b/)
|
138
|
+
boolean_at_tag(/@accessor/, :accessor)
|
139
|
+
elsif look(/@template\b/)
|
140
|
+
boolean_at_tag(/@template/, :template)
|
125
141
|
elsif look(/@markdown\b/)
|
126
142
|
# this is detected just to be ignored
|
127
143
|
boolean_at_tag(/@markdown/, :markdown)
|
@@ -129,7 +145,16 @@ module JsDuck
|
|
129
145
|
# this is detected just to be ignored
|
130
146
|
boolean_at_tag(/@abstract/, :abstract)
|
131
147
|
elsif look(/@/)
|
132
|
-
@
|
148
|
+
@input.scan(/@/)
|
149
|
+
if @meta_tags_map[look(/\w+/)]
|
150
|
+
add_tag(:meta)
|
151
|
+
@current_tag[:name] = match(/\w+/)
|
152
|
+
skip_horiz_white
|
153
|
+
@current_tag[:content] = @input.scan(/.*$/)
|
154
|
+
skip_white
|
155
|
+
else
|
156
|
+
@current_tag[:doc] += "@"
|
157
|
+
end
|
133
158
|
elsif look(/[^@]/)
|
134
159
|
@current_tag[:doc] += @input.scan(/[^@]+/)
|
135
160
|
end
|
@@ -303,24 +328,6 @@ module JsDuck
|
|
303
328
|
skip_white
|
304
329
|
end
|
305
330
|
|
306
|
-
# matches @author some name ... newline
|
307
|
-
def at_author
|
308
|
-
match(/@author/)
|
309
|
-
add_tag(:author)
|
310
|
-
skip_horiz_white
|
311
|
-
@current_tag[:name] = @input.scan(/.*$/)
|
312
|
-
skip_white
|
313
|
-
end
|
314
|
-
|
315
|
-
# matches @docauthor some name ... newline
|
316
|
-
def at_docauthor
|
317
|
-
match(/@docauthor/)
|
318
|
-
add_tag(:docauthor)
|
319
|
-
skip_horiz_white
|
320
|
-
@current_tag[:name] = @input.scan(/.*$/)
|
321
|
-
skip_white
|
322
|
-
end
|
323
|
-
|
324
331
|
# matches @deprecated <version> some text ... newline
|
325
332
|
def at_deprecated
|
326
333
|
match(/@deprecated/)
|
data/lib/jsduck/exporter.rb
CHANGED
@@ -42,7 +42,7 @@ module JsDuck
|
|
42
42
|
|
43
43
|
def compact_member(m)
|
44
44
|
m_copy = {}
|
45
|
-
[:name, :tagname, :owner, :protected, :static, :deprecated, :required].each do |key|
|
45
|
+
[:name, :tagname, :owner, :protected, :static, :deprecated, :required, :template, :id].each do |key|
|
46
46
|
m_copy[key] = m[key]
|
47
47
|
end
|
48
48
|
m_copy
|
data/lib/jsduck/guides.rb
CHANGED
@@ -29,9 +29,18 @@ module JsDuck
|
|
29
29
|
end
|
30
30
|
|
31
31
|
def write_guide(guide, dir)
|
32
|
-
|
32
|
+
guide_dir = @path + "/guides/" + guide["name"]
|
33
|
+
tutorial_dir = @path + "/tutorials/" + guide["name"]
|
33
34
|
out_dir = dir + "/" + guide["name"]
|
34
|
-
|
35
|
+
|
36
|
+
if File.exists?(guide_dir)
|
37
|
+
in_dir = guide_dir
|
38
|
+
elsif File.exists?(tutorial_dir)
|
39
|
+
in_dir = tutorial_dir
|
40
|
+
else
|
41
|
+
return Logger.instance.warn("Guide #{guide_dir} / #{tutorial_dir} not found")
|
42
|
+
end
|
43
|
+
|
35
44
|
guide_file = in_dir + "/README.md"
|
36
45
|
return Logger.instance.warn("README.md not found in #{in_dir}") unless File.exists?(guide_file)
|
37
46
|
|
data/lib/jsduck/js_parser.rb
CHANGED
@@ -6,10 +6,11 @@ require 'jsduck/js_literal_builder'
|
|
6
6
|
module JsDuck
|
7
7
|
|
8
8
|
class JsParser < JsLiteralParser
|
9
|
-
def initialize(input)
|
9
|
+
def initialize(input, options = {})
|
10
10
|
super(input)
|
11
|
-
@doc_parser = DocParser.new
|
11
|
+
@doc_parser = DocParser.new(:js, options[:meta_tags])
|
12
12
|
@docs = []
|
13
|
+
@ext_namespaces = options[:ext_namespaces] || ["Ext"]
|
13
14
|
end
|
14
15
|
|
15
16
|
# Parses the whole JavaScript block and returns array where for
|
@@ -76,9 +77,9 @@ module JsDuck
|
|
76
77
|
function
|
77
78
|
elsif look("var")
|
78
79
|
var_declaration
|
79
|
-
elsif
|
80
|
+
elsif ext_look(:ns, ".", "define", "(", :string)
|
80
81
|
ext_define
|
81
|
-
elsif
|
82
|
+
elsif ext_look(:ns, ".", "ClassManager", ".", "create", "(", :string)
|
82
83
|
ext_define
|
83
84
|
elsif look(:ident, ":") || look(:string, ":")
|
84
85
|
property_literal
|
@@ -155,12 +156,14 @@ module JsDuck
|
|
155
156
|
return chain
|
156
157
|
end
|
157
158
|
|
158
|
-
# <expression> := <function> | <ext-extend> | <literal>
|
159
|
+
# <expression> := <function> | <ext-extend> | <ext-base-css-prefix> | <literal>
|
159
160
|
def expression
|
160
161
|
if look("function")
|
161
162
|
function
|
162
|
-
elsif
|
163
|
+
elsif ext_look(:ns, ".", "extend")
|
163
164
|
ext_extend
|
165
|
+
elsif ext_look(:ns, ".", "baseCSSPrefix", "+", :string)
|
166
|
+
ext_base_css_prefix
|
164
167
|
else
|
165
168
|
my_literal
|
166
169
|
end
|
@@ -194,16 +197,26 @@ module JsDuck
|
|
194
197
|
|
195
198
|
# <ext-extend> := "Ext" "." "extend" "(" <ident-chain> "," ...
|
196
199
|
def ext_extend
|
197
|
-
match(
|
200
|
+
match(:ident, ".", "extend", "(")
|
198
201
|
return {
|
199
202
|
:type => :ext_extend,
|
200
203
|
:extend => ident_chain,
|
201
204
|
}
|
202
205
|
end
|
203
206
|
|
207
|
+
# <ext-base-css-prefix> := "Ext" "." "baseCSSPrefix" "+" <string>
|
208
|
+
def ext_base_css_prefix
|
209
|
+
match(:ident, ".", "baseCSSPrefix", "+")
|
210
|
+
return {
|
211
|
+
:type => :literal,
|
212
|
+
:class => "String",
|
213
|
+
:value => '"x-' + match(:string)[:value] + '"',
|
214
|
+
}
|
215
|
+
end
|
216
|
+
|
204
217
|
# <ext-define> := "Ext" "." ["define" | "ClassManager" "." "create" ] "(" <string> "," <ext-define-cfg>
|
205
218
|
def ext_define
|
206
|
-
match(
|
219
|
+
match(:ident, ".");
|
207
220
|
look("define") ? match("define") : match("ClassManager", ".", "create");
|
208
221
|
name = match("(", :string)[:value]
|
209
222
|
|
@@ -338,6 +351,15 @@ module JsDuck
|
|
338
351
|
}
|
339
352
|
end
|
340
353
|
|
354
|
+
# Like look() but tries to match as the first argument all the
|
355
|
+
# names listed in @ext_namespaces
|
356
|
+
def ext_look(placeholder, *args)
|
357
|
+
@ext_namespaces.each do |ns|
|
358
|
+
return true if look(ns, *args)
|
359
|
+
end
|
360
|
+
return false
|
361
|
+
end
|
362
|
+
|
341
363
|
end
|
342
364
|
|
343
365
|
end
|