jsduck 3.1.0 → 3.2.1
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 +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
|