jsduck 3.1.0 → 3.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +14 -9
- data/Rakefile +31 -230
- data/jsduck.gemspec +2 -2
- data/lib/jsduck/accessors.rb +14 -6
- data/lib/jsduck/aggregator.rb +9 -4
- data/lib/jsduck/app.rb +1 -0
- data/lib/jsduck/app_data.rb +14 -7
- data/lib/jsduck/app_exporter.rb +3 -3
- data/lib/jsduck/class.rb +8 -5
- data/lib/jsduck/class_formatter.rb +1 -3
- data/lib/jsduck/css_parser.rb +1 -1
- data/lib/jsduck/doc_formatter.rb +140 -36
- data/lib/jsduck/doc_parser.rb +27 -44
- data/lib/jsduck/index_html.rb +0 -3
- data/lib/jsduck/inherit_doc.rb +20 -4
- data/lib/jsduck/js_parser.rb +1 -1
- data/lib/jsduck/lint.rb +15 -0
- data/lib/jsduck/logger.rb +9 -7
- data/lib/jsduck/merger.rb +18 -16
- data/lib/jsduck/meta_tag.rb +28 -5
- data/lib/jsduck/meta_tag_loader.rb +38 -21
- data/lib/jsduck/meta_tag_registry.rb +79 -0
- data/lib/jsduck/options.rb +69 -12
- data/lib/jsduck/renderer.rb +10 -38
- data/lib/jsduck/search_data.rb +53 -3
- data/lib/jsduck/tag/abstract.rb +14 -0
- data/lib/jsduck/{author_tag.rb → tag/author.rb} +2 -2
- data/lib/jsduck/tag/deprecated.rb +33 -0
- data/lib/jsduck/{doc_author_tag.rb → tag/docauthor.rb} +2 -2
- data/lib/jsduck/tag/markdown.rb +12 -0
- data/lib/jsduck/tag/preventable.rb +28 -0
- data/lib/jsduck/tag/protected.rb +14 -0
- data/lib/jsduck/tag/readonly.rb +14 -0
- data/lib/jsduck/tag/required.rb +21 -0
- data/lib/jsduck/tag/static.rb +14 -0
- data/lib/jsduck/tag/template.rb +23 -0
- data/opt/example.js +149 -0
- metadata +17 -9
- data/opt/extjs-welcome.html +0 -74
- data/opt/touch-iframe.html +0 -85
- data/opt/touch-welcome.html +0 -122
data/lib/jsduck/index_html.rb
CHANGED
@@ -34,9 +34,6 @@ module JsDuck
|
|
34
34
|
"{header}" => @opts.header,
|
35
35
|
"{footer}" => "<div id='footer-content' style='display: none'>#{@opts.footer}</div>",
|
36
36
|
"{extjs_path}" => @opts.extjs_path,
|
37
|
-
"{local_storage_db}" => @opts.local_storage_db,
|
38
|
-
"{show_print_button}" => @opts.seo ? "true" : "false",
|
39
|
-
"{touch_examples_ui}" => @opts.touch_examples_ui ? "true" : "false",
|
40
37
|
"{welcome}" => @welcome.to_html,
|
41
38
|
"{categories}" => @categories.to_html,
|
42
39
|
"{guides}" => @guides.to_html,
|
data/lib/jsduck/inherit_doc.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'jsduck/logger'
|
2
|
+
require 'pp'
|
2
3
|
|
3
4
|
module JsDuck
|
4
5
|
|
@@ -41,19 +42,34 @@ module JsDuck
|
|
41
42
|
warn("@inheritdoc #{inherit[:cls]}##{inherit[:member]} - class not found", context)
|
42
43
|
return m
|
43
44
|
end
|
44
|
-
parent = parent_cls.
|
45
|
+
parent = parent_cls.get_members(inherit[:member], inherit[:type] || m[:tagname], inherit[:static] || m[:meta][:static])[0]
|
45
46
|
unless parent
|
46
47
|
warn("@inheritdoc #{inherit[:cls]}##{inherit[:member]} - member not found", context)
|
47
48
|
return m
|
48
49
|
end
|
49
50
|
else
|
50
51
|
parent_cls = @relations[m[:owner]].parent
|
51
|
-
|
52
|
+
mixins = @relations[m[:owner]].mixins
|
53
|
+
# Warn when no parent or mixins at all
|
54
|
+
if !parent_cls && mixins.length == 0
|
52
55
|
warn("@inheritdoc - parent class not found", context)
|
53
56
|
return m
|
54
57
|
end
|
55
|
-
|
56
|
-
|
58
|
+
# First check for the member in all mixins, because members
|
59
|
+
# from mixins override those from parent class. Looking first
|
60
|
+
# from mixins is probably a bit slower, but it's the correct
|
61
|
+
# order to do things.
|
62
|
+
if mixins.length > 0
|
63
|
+
parent = mixins.map do |mix|
|
64
|
+
mix.get_members(m[:name], m[:tagname], m[:meta][:static])[0]
|
65
|
+
end.compact.first
|
66
|
+
end
|
67
|
+
# When not found, try looking from parent class
|
68
|
+
if !parent && parent_cls
|
69
|
+
parent = parent_cls.get_members(m[:name], m[:tagname], m[:meta][:static])[0]
|
70
|
+
end
|
71
|
+
# Only when both parent and mixins fail, throw warning
|
72
|
+
if !parent
|
57
73
|
warn("@inheritdoc - parent member not found", context)
|
58
74
|
return m
|
59
75
|
end
|
data/lib/jsduck/js_parser.rb
CHANGED
@@ -8,7 +8,7 @@ module JsDuck
|
|
8
8
|
class JsParser < JsLiteralParser
|
9
9
|
def initialize(input, options = {})
|
10
10
|
super(input)
|
11
|
-
@doc_parser = DocParser.new
|
11
|
+
@doc_parser = DocParser.new
|
12
12
|
@docs = []
|
13
13
|
@ext_namespaces = options[:ext_namespaces] || ["Ext"]
|
14
14
|
end
|
data/lib/jsduck/lint.rb
CHANGED
@@ -13,6 +13,7 @@ module JsDuck
|
|
13
13
|
# Runs the linter
|
14
14
|
def run
|
15
15
|
warn_globals
|
16
|
+
warn_no_doc
|
16
17
|
warn_unnamed
|
17
18
|
warn_optional_params
|
18
19
|
warn_duplicate_params
|
@@ -41,6 +42,20 @@ module JsDuck
|
|
41
42
|
end
|
42
43
|
end
|
43
44
|
|
45
|
+
# print warning for each member or parameter with no name
|
46
|
+
def warn_no_doc
|
47
|
+
@relations.each do |cls|
|
48
|
+
if cls[:doc] == ""
|
49
|
+
warn(:no_doc, "No documentation for #{cls[:name]}", cls)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
each_member do |member|
|
53
|
+
if member[:doc] == ""
|
54
|
+
warn(:no_doc, "No documentation for #{member[:owner]}##{member[:name]}", member)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
44
59
|
# print warning for each non-optional parameter that follows an optional parameter
|
45
60
|
def warn_optional_params
|
46
61
|
each_member do |member|
|
data/lib/jsduck/logger.rb
CHANGED
@@ -17,9 +17,13 @@ module JsDuck
|
|
17
17
|
[:inheritdoc, "@inheritdoc referring to unknown class or member"],
|
18
18
|
[:extend, "@extend or @mixin referring to unknown class"],
|
19
19
|
[:link, "{@link} to unknown class or member"],
|
20
|
+
[:link_private, "{@link} to private member"],
|
21
|
+
[:link_ambiguous, "{@link} is ambiguous"],
|
22
|
+
[:link_auto, "Auto-detected link to unknown class or member"],
|
20
23
|
|
21
24
|
[:alt_name, "Name used as both classname and alternate classname"],
|
22
25
|
[:name_missing, "Member or parameter has no name"],
|
26
|
+
[:no_doc, "Member or class without documentation"],
|
23
27
|
[:dup_param, "Method has two parameters with same name"],
|
24
28
|
[:req_after_opt, "Required parameter comes after optional"],
|
25
29
|
[:subproperty, "@param foo.bar where foo param doesn't exist"],
|
@@ -34,10 +38,12 @@ module JsDuck
|
|
34
38
|
[:cat_class_missing, "Class is missing from categories file"],
|
35
39
|
[:guide, "Guide is missing from --guides dir"],
|
36
40
|
]
|
37
|
-
# Turn
|
41
|
+
# Turn off all warnings by default.
|
42
|
+
# This is good for testing.
|
43
|
+
# When running JSDuck app, the Options class enables most warnings.
|
38
44
|
@warnings = {}
|
39
45
|
@warning_docs.each do |w|
|
40
|
-
@warnings[w[0]] =
|
46
|
+
@warnings[w[0]] = false
|
41
47
|
end
|
42
48
|
|
43
49
|
@shown_warnings = {}
|
@@ -66,11 +72,7 @@ module JsDuck
|
|
66
72
|
|
67
73
|
# get documentation for all warnings
|
68
74
|
def doc_warnings
|
69
|
-
@warning_docs.map {|w| "
|
70
|
-
" ",
|
71
|
-
"+all - to turn on all warnings (default)",
|
72
|
-
" ",
|
73
|
-
]
|
75
|
+
@warning_docs.map {|w| " #{@warnings[w[0]] ? '+' : '-'}#{w[0]} - #{w[1]}" } + [" "]
|
74
76
|
end
|
75
77
|
|
76
78
|
# Prints warning message.
|
data/lib/jsduck/merger.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'jsduck/logger'
|
2
|
+
require 'jsduck/meta_tag_registry'
|
2
3
|
|
3
4
|
module JsDuck
|
4
5
|
|
@@ -15,6 +16,7 @@ module JsDuck
|
|
15
16
|
def initialize
|
16
17
|
@filename = ""
|
17
18
|
@linenr = 0
|
19
|
+
@meta_tags = MetaTagRegistry.instance
|
18
20
|
end
|
19
21
|
|
20
22
|
def merge(docs, code)
|
@@ -64,6 +66,8 @@ module JsDuck
|
|
64
66
|
:method
|
65
67
|
elsif code[:type] == :assignment && code[:right] && code[:right][:type] == :function
|
66
68
|
:method
|
69
|
+
elsif doc_map[:return] || doc_map[:param]
|
70
|
+
:method
|
67
71
|
else
|
68
72
|
:property
|
69
73
|
end
|
@@ -153,7 +157,6 @@ module JsDuck
|
|
153
157
|
:doc => detect_doc(docs),
|
154
158
|
:params => detect_params(docs, code),
|
155
159
|
:return => detect_return(doc_map, name == "constructor" ? "Object" : "undefined"),
|
156
|
-
:template => !!doc_map[:template],
|
157
160
|
}, doc_map)
|
158
161
|
end
|
159
162
|
|
@@ -176,7 +179,6 @@ module JsDuck
|
|
176
179
|
:owner => detect_owner(doc_map) || owner,
|
177
180
|
:type => detect_type(:cfg, doc_map, code),
|
178
181
|
:doc => detect_doc(docs),
|
179
|
-
:required => detect_required(:cfg, doc_map),
|
180
182
|
:default => detect_default(:cfg, doc_map, code),
|
181
183
|
:properties => detect_subproperties(docs, :cfg),
|
182
184
|
:accessor => !!doc_map[:accessor],
|
@@ -192,6 +194,7 @@ module JsDuck
|
|
192
194
|
:owner => detect_owner(doc_map),
|
193
195
|
:type => detect_type(:property, doc_map, code),
|
194
196
|
:doc => detect_doc(docs),
|
197
|
+
:default => detect_default(:property, doc_map, code),
|
195
198
|
:properties => detect_subproperties(docs, :property),
|
196
199
|
}, doc_map)
|
197
200
|
end
|
@@ -222,10 +225,7 @@ module JsDuck
|
|
222
225
|
def add_shared(hash, doc_map)
|
223
226
|
hash.merge!({
|
224
227
|
:private => !!doc_map[:private],
|
225
|
-
:protected => !!doc_map[:protected],
|
226
|
-
:static => !!doc_map[:static],
|
227
228
|
:inheritable => !!doc_map[:inheritable],
|
228
|
-
:deprecated => detect_deprecated(doc_map),
|
229
229
|
:inheritdoc => doc_map[:inheritdoc] ? doc_map[:inheritdoc].first : nil,
|
230
230
|
:meta => detect_meta(doc_map),
|
231
231
|
})
|
@@ -236,7 +236,7 @@ module JsDuck
|
|
236
236
|
def create_member_id(m)
|
237
237
|
# Sanitize $ in member names with something safer
|
238
238
|
name = m[:name].gsub(/\$/, 'S-')
|
239
|
-
"#{m[:static] ? 'static-' : ''}#{m[:tagname]}-#{name}"
|
239
|
+
"#{m[:meta][:static] ? 'static-' : ''}#{m[:tagname]}-#{name}"
|
240
240
|
end
|
241
241
|
|
242
242
|
def detect_name(tagname, doc_map, code, name_type = :last_name)
|
@@ -314,11 +314,6 @@ module JsDuck
|
|
314
314
|
return explicit_name == "" || explicit_name == implicit_name
|
315
315
|
end
|
316
316
|
|
317
|
-
def detect_required(tagname, doc_map)
|
318
|
-
main_tag = doc_map[tagname] ? doc_map[tagname].first : {}
|
319
|
-
return main_tag[:optional] == false
|
320
|
-
end
|
321
|
-
|
322
317
|
# for detecting mixins and alternateClassNames
|
323
318
|
def detect_list(type, doc_map, code)
|
324
319
|
if doc_map[type]
|
@@ -350,7 +345,7 @@ module JsDuck
|
|
350
345
|
# it instead of creating a new hash.
|
351
346
|
def build_aliases_hash(aliases, hash={})
|
352
347
|
aliases.each do |a|
|
353
|
-
if a =~ /^(
|
348
|
+
if a =~ /^(.+)\.([^.]+)$/
|
354
349
|
if hash[$1]
|
355
350
|
hash[$1] << $2
|
356
351
|
else
|
@@ -367,17 +362,24 @@ module JsDuck
|
|
367
362
|
meta[tag[:name]] = [] unless meta[tag[:name]]
|
368
363
|
meta[tag[:name]] << tag[:doc]
|
369
364
|
end
|
370
|
-
meta
|
371
|
-
end
|
372
365
|
|
373
|
-
|
374
|
-
|
366
|
+
meta.each_pair do |key, value|
|
367
|
+
tag = @meta_tags[key]
|
368
|
+
meta[key] = tag.to_value(tag.boolean ? true : value)
|
369
|
+
end
|
370
|
+
|
371
|
+
meta[:required] = true if detect_required(doc_map)
|
372
|
+
meta
|
375
373
|
end
|
376
374
|
|
377
375
|
def detect_singleton(doc_map, code)
|
378
376
|
!!(doc_map[:singleton] || code[:type] == :ext_define && code[:singleton])
|
379
377
|
end
|
380
378
|
|
379
|
+
def detect_required(doc_map)
|
380
|
+
doc_map[:cfg] && doc_map[:cfg].first[:optional] == false
|
381
|
+
end
|
382
|
+
|
381
383
|
def detect_params(docs, code)
|
382
384
|
implicit = detect_implicit_params(code)
|
383
385
|
explicit = detect_explicit_params(docs)
|
data/lib/jsduck/meta_tag.rb
CHANGED
@@ -8,17 +8,40 @@ module JsDuck
|
|
8
8
|
# Name of the tag (required)
|
9
9
|
attr_reader :name
|
10
10
|
|
11
|
+
# The key under which to store this tag. Must be a symbol. When
|
12
|
+
# not provided then :name is converted to symbol and used as key.
|
13
|
+
attr_accessor :key
|
14
|
+
|
15
|
+
# The text to display in member signature. Must be a hash
|
16
|
+
# defining the short and long versions of the signature text:
|
17
|
+
#
|
18
|
+
# {:long => "something", :short => "SOM"}
|
19
|
+
#
|
20
|
+
attr_reader :signature
|
21
|
+
|
11
22
|
# True to include all lines up to next @tag as part of this meta-tag
|
12
23
|
attr_reader :multiline
|
13
24
|
|
25
|
+
# True to ignore any text after the @tag, just record the
|
26
|
+
# existance of the tag.
|
27
|
+
attr_reader :boolean
|
28
|
+
|
29
|
+
# It gets passed an array of contents gathered from all meta-tags
|
30
|
+
# of given type. It should return the value to be stored for this
|
31
|
+
# meta-tag at :key. The returned value is also passed to #to_html
|
32
|
+
# method. Returning nil will cause the tag to be ignored. By
|
33
|
+
# default the contents are returned unchanged.
|
34
|
+
def to_value(contents)
|
35
|
+
contents
|
36
|
+
end
|
37
|
+
|
14
38
|
# Override this to transform the content of meta-tag to HTML to be
|
15
39
|
# included into documentation.
|
16
40
|
#
|
17
|
-
# It gets passed
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
# of meta-tag.
|
41
|
+
# It gets passed the value returned by #to_value method. It should
|
42
|
+
# return an HTML string to inject into document. For help in that
|
43
|
+
# it can use the #format method to easily support Markdown and
|
44
|
+
# {@link/img} tags inside the contents of meta-tag.
|
22
45
|
#
|
23
46
|
# By default the method returns nil, which means the tag will not
|
24
47
|
# be rendered at all.
|
@@ -1,32 +1,41 @@
|
|
1
1
|
require "jsduck/meta_tag"
|
2
|
-
require 'jsduck/author_tag'
|
3
|
-
require 'jsduck/doc_author_tag'
|
4
2
|
|
5
3
|
module JsDuck
|
6
4
|
|
7
|
-
#
|
5
|
+
# Loader for built-in and user-defined meta-tags.
|
8
6
|
class MetaTagLoader
|
9
|
-
|
7
|
+
attr_reader :meta_tags
|
8
|
+
|
10
9
|
def initialize
|
11
|
-
@classes =
|
12
|
-
@meta_tags =
|
10
|
+
@classes = []
|
11
|
+
@meta_tags = []
|
13
12
|
end
|
14
13
|
|
15
|
-
# Loads user-defined meta-tags from given
|
16
|
-
#
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
14
|
+
# Loads user-defined meta-tags from given path.
|
15
|
+
#
|
16
|
+
# * If path is a directory, loads all *.rb files in it.
|
17
|
+
# * If path is the symbol :builtins, loads the builtin
|
18
|
+
# tags from ./tag dir.
|
19
|
+
# * Otherwise loads tags from the single file.
|
20
|
+
def load(path)
|
21
|
+
if path == :builtins
|
22
|
+
load(File.dirname(__FILE__) + "/tag")
|
23
|
+
elsif File.directory?(path)
|
24
|
+
# Sort paths, so they are always loaded in the same order.
|
25
|
+
# This is important for signatures to always be rendered in
|
26
|
+
# the same order.
|
27
|
+
Dir[path+"/**/*.rb"].sort.each {|file| load_file(file) }
|
28
|
+
else
|
29
|
+
load_file(path)
|
28
30
|
end
|
29
|
-
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
# Loads just one file.
|
36
|
+
def load_file(file)
|
37
|
+
require(file)
|
38
|
+
init_remaining
|
30
39
|
end
|
31
40
|
|
32
41
|
# Instantiates meta tag classes that haven't been instantiated
|
@@ -37,12 +46,20 @@ module JsDuck
|
|
37
46
|
MetaTag.descendants.each do |cls|
|
38
47
|
if !@classes.include?(cls)
|
39
48
|
@classes << cls
|
40
|
-
newtag = cls
|
49
|
+
newtag = create_tag(cls)
|
41
50
|
@meta_tags = @meta_tags.find_all {|t| t.name != newtag.name }
|
42
51
|
@meta_tags << newtag
|
43
52
|
end
|
44
53
|
end
|
45
54
|
end
|
55
|
+
|
56
|
+
# Instanciates tag class.
|
57
|
+
# When .key is missing, creates it from .name
|
58
|
+
def create_tag(cls)
|
59
|
+
tag = cls.new
|
60
|
+
tag.key = tag.name.to_sym unless tag.key
|
61
|
+
tag
|
62
|
+
end
|
46
63
|
end
|
47
64
|
|
48
65
|
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
require "jsduck/meta_tag_loader"
|
3
|
+
|
4
|
+
module JsDuck
|
5
|
+
|
6
|
+
# Access to meta-tags
|
7
|
+
class MetaTagRegistry
|
8
|
+
include Singleton
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@tags = []
|
12
|
+
@map = {}
|
13
|
+
end
|
14
|
+
|
15
|
+
# Loads meta-tags from the given paths. See MetaTagLoader#load
|
16
|
+
# for details.
|
17
|
+
#
|
18
|
+
# This should only be called once. Calling it twice will override
|
19
|
+
# the previously loaded tags.
|
20
|
+
def load(paths)
|
21
|
+
loader = MetaTagLoader.new
|
22
|
+
paths.each {|p| loader.load(p) }
|
23
|
+
register(loader.meta_tags)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Registers MetaTag instances.
|
27
|
+
#
|
28
|
+
# NB! This is for testing purposes only, elsewhere always use #load.
|
29
|
+
def register(tags)
|
30
|
+
@tags = tags
|
31
|
+
register_keys
|
32
|
+
end
|
33
|
+
|
34
|
+
# Returns array of all available tag instances
|
35
|
+
def tags
|
36
|
+
@tags
|
37
|
+
end
|
38
|
+
|
39
|
+
# Accesses tag by key or name
|
40
|
+
def [](name)
|
41
|
+
@map[name]
|
42
|
+
end
|
43
|
+
|
44
|
+
# Returns the formatter assigned to tags
|
45
|
+
def formatter
|
46
|
+
@formatter
|
47
|
+
end
|
48
|
+
|
49
|
+
# Sets the doc-formatter for all tags
|
50
|
+
def formatter=(doc_formatter)
|
51
|
+
@formatter = doc_formatter
|
52
|
+
@tags.each {|tag| tag.formatter = doc_formatter }
|
53
|
+
end
|
54
|
+
|
55
|
+
# Returns array of attributes to be shown in member signatures
|
56
|
+
# (and in order they should be shown in).
|
57
|
+
def signatures
|
58
|
+
if !@signatures
|
59
|
+
@signatures = @tags.find_all(&:signature).map do |tag|
|
60
|
+
s = tag.signature
|
61
|
+
s[:key] = tag.key
|
62
|
+
s
|
63
|
+
end
|
64
|
+
end
|
65
|
+
@signatures
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def register_keys
|
71
|
+
@map = {}
|
72
|
+
@tags.each do |tag|
|
73
|
+
@map[tag.key] = tag
|
74
|
+
@map[tag.name] = tag
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|