jsduck 4.10.4 → 5.0.0.beta01
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +0 -1
- data/README.md +32 -6
- data/Rakefile +10 -18
- data/bin/compare +5 -5
- data/bin/jsduck +2 -3
- data/jsduck.gemspec +3 -4
- data/lib/jsduck/aggregator.rb +21 -80
- data/lib/jsduck/app.rb +7 -14
- data/lib/jsduck/app_data.rb +4 -5
- data/lib/jsduck/assets.rb +4 -7
- data/lib/jsduck/base_type.rb +53 -0
- data/lib/jsduck/batch_parser.rb +8 -87
- data/lib/jsduck/batch_processor.rb +77 -0
- data/lib/jsduck/categories/auto.rb +83 -0
- data/lib/jsduck/categories/class_name.rb +63 -0
- data/lib/jsduck/categories/factory.rb +113 -0
- data/lib/jsduck/categories/file.rb +75 -0
- data/lib/jsduck/class.rb +3 -9
- data/lib/jsduck/class_doc_expander.rb +1 -1
- data/lib/jsduck/css/lexer.rb +203 -0
- data/lib/jsduck/css/parser.rb +121 -0
- data/lib/jsduck/doc/comment.rb +40 -0
- data/lib/jsduck/doc/map.rb +23 -0
- data/lib/jsduck/doc/parser.rb +128 -0
- data/lib/jsduck/doc/processor.rb +52 -0
- data/lib/jsduck/doc/scanner.rb +76 -0
- data/lib/jsduck/doc/standard_tag_parser.rb +154 -0
- data/lib/jsduck/doc/subproperties.rb +64 -0
- data/lib/jsduck/docs_code_comparer.rb +31 -0
- data/lib/jsduck/export_writer.rb +2 -2
- data/lib/jsduck/exporter/app.rb +16 -4
- data/lib/jsduck/exporter/full.rb +2 -2
- data/lib/jsduck/format/batch.rb +58 -0
- data/lib/jsduck/format/class.rb +62 -0
- data/lib/jsduck/format/doc.rb +172 -0
- data/lib/jsduck/format/html_stack.rb +109 -0
- data/lib/jsduck/format/shortener.rb +55 -0
- data/lib/jsduck/format/subproperties.rb +64 -0
- data/lib/jsduck/guides.rb +32 -14
- data/lib/jsduck/index_html.rb +3 -1
- data/lib/jsduck/inline/auto_link.rb +2 -2
- data/lib/jsduck/inline/link.rb +4 -3
- data/lib/jsduck/inline/link_renderer.rb +2 -2
- data/lib/jsduck/inline/video.rb +8 -2
- data/lib/jsduck/js/ast.rb +361 -0
- data/lib/jsduck/js/esprima.rb +39 -0
- data/lib/jsduck/{esprima → js/esprima}/esprima.js +0 -0
- data/lib/jsduck/js/evaluator.rb +70 -0
- data/lib/jsduck/js/ext_patterns.rb +70 -0
- data/lib/jsduck/js/function.rb +206 -0
- data/lib/jsduck/js/node.rb +194 -0
- data/lib/jsduck/js/node_array.rb +36 -0
- data/lib/jsduck/js/parser.rb +223 -0
- data/lib/jsduck/js/serializer.rb +263 -0
- data/lib/jsduck/js/utils.rb +21 -0
- data/lib/jsduck/logger.rb +3 -13
- data/lib/jsduck/members_index.rb +3 -4
- data/lib/jsduck/merger.rb +25 -145
- data/lib/jsduck/options.rb +29 -132
- data/lib/jsduck/parser.rb +76 -0
- data/lib/jsduck/process/accessors.rb +133 -0
- data/lib/jsduck/process/circular_deps.rb +58 -0
- data/lib/jsduck/process/enums.rb +91 -0
- data/lib/jsduck/process/ext4_events.rb +43 -0
- data/lib/jsduck/process/global_members.rb +36 -0
- data/lib/jsduck/process/ignored_classes.rb +16 -0
- data/lib/jsduck/process/importer.rb +58 -0
- data/lib/jsduck/process/inherit_doc.rb +197 -0
- data/lib/jsduck/process/lint.rb +135 -0
- data/lib/jsduck/process/overrides.rb +99 -0
- data/lib/jsduck/process/return_values.rb +72 -0
- data/lib/jsduck/process/versions.rb +102 -0
- data/lib/jsduck/relations.rb +5 -0
- data/lib/jsduck/render/class.rb +144 -0
- data/lib/jsduck/render/sidebar.rb +97 -0
- data/lib/jsduck/render/signature.rb +94 -0
- data/lib/jsduck/render/subproperties.rb +99 -0
- data/lib/jsduck/render/tags.rb +38 -0
- data/lib/jsduck/search_data.rb +19 -13
- data/lib/jsduck/source/file.rb +8 -17
- data/lib/jsduck/tag/abstract.rb +4 -7
- data/lib/jsduck/tag/accessor.rb +10 -0
- data/lib/jsduck/tag/alias.rb +61 -0
- data/lib/jsduck/tag/alternate_class_names.rb +17 -0
- data/lib/jsduck/tag/aside.rb +28 -31
- data/lib/jsduck/tag/author.rb +9 -5
- data/lib/jsduck/tag/boolean_tag.rb +24 -0
- data/lib/jsduck/tag/cfg.rb +45 -0
- data/lib/jsduck/tag/chainable.rb +5 -7
- data/lib/jsduck/tag/class.rb +28 -0
- data/lib/jsduck/tag/class_list_tag.rb +40 -0
- data/lib/jsduck/tag/constructor.rb +24 -0
- data/lib/jsduck/tag/css_mixin.rb +17 -0
- data/lib/jsduck/tag/css_var.rb +29 -0
- data/lib/jsduck/tag/default.rb +31 -0
- data/lib/jsduck/tag/deprecated.rb +13 -27
- data/lib/jsduck/tag/deprecated_tag.rb +58 -0
- data/lib/jsduck/tag/doc.rb +32 -0
- data/lib/jsduck/tag/docauthor.rb +4 -5
- data/lib/jsduck/tag/enum.rb +70 -0
- data/lib/jsduck/tag/event.rb +28 -0
- data/lib/jsduck/tag/evented.rb +10 -0
- data/lib/jsduck/tag/extends.rb +45 -0
- data/lib/jsduck/tag/ftype.rb +18 -0
- data/lib/jsduck/tag/hide.rb +4 -11
- data/lib/jsduck/tag/ignore.rb +6 -7
- data/lib/jsduck/tag/inheritable.rb +10 -0
- data/lib/jsduck/tag/inheritdoc.rb +48 -0
- data/lib/jsduck/tag/markdown.rb +8 -6
- data/lib/jsduck/tag/member.rb +24 -0
- data/lib/jsduck/tag/method.rb +35 -0
- data/lib/jsduck/tag/mixins.rb +26 -0
- data/lib/jsduck/tag/name.rb +36 -0
- data/lib/jsduck/tag/new.rb +13 -27
- data/lib/jsduck/tag/override.rb +37 -0
- data/lib/jsduck/tag/overrides.rb +29 -0
- data/lib/jsduck/tag/param.rb +87 -0
- data/lib/jsduck/tag/preventable.rb +19 -10
- data/lib/jsduck/tag/private.rb +28 -13
- data/lib/jsduck/tag/property.rb +39 -0
- data/lib/jsduck/tag/protected.rb +5 -7
- data/lib/jsduck/tag/ptype.rb +18 -0
- data/lib/jsduck/tag/readonly.rb +4 -7
- data/lib/jsduck/tag/removed.rb +21 -29
- data/lib/jsduck/tag/required.rb +11 -9
- data/lib/jsduck/tag/requires.rb +12 -0
- data/lib/jsduck/tag/return.rb +47 -0
- data/lib/jsduck/tag/since.rb +19 -11
- data/lib/jsduck/tag/singleton.rb +15 -0
- data/lib/jsduck/tag/static.rb +5 -7
- data/lib/jsduck/tag/subproperties.rb +23 -0
- data/lib/jsduck/tag/tag.rb +208 -0
- data/lib/jsduck/tag/template.rb +14 -9
- data/lib/jsduck/tag/throws.rb +38 -0
- data/lib/jsduck/tag/type.rb +48 -0
- data/lib/jsduck/tag/uses.rb +12 -0
- data/lib/jsduck/tag/xtype.rb +30 -0
- data/lib/jsduck/tag_loader.rb +39 -0
- data/lib/jsduck/tag_registry.rb +189 -0
- data/lib/jsduck/type_parser.rb +3 -3
- data/lib/jsduck/web_writer.rb +2 -2
- data/lib/jsduck/welcome.rb +1 -1
- metadata +578 -538
- data/lib/jsduck/accessors.rb +0 -136
- data/lib/jsduck/ast.rb +0 -524
- data/lib/jsduck/auto_categories.rb +0 -80
- data/lib/jsduck/batch_formatter.rb +0 -60
- data/lib/jsduck/categories.rb +0 -73
- data/lib/jsduck/categories_class_name.rb +0 -37
- data/lib/jsduck/circular_deps.rb +0 -56
- data/lib/jsduck/class_formatter.rb +0 -102
- data/lib/jsduck/columns.rb +0 -56
- data/lib/jsduck/css_lexer.rb +0 -201
- data/lib/jsduck/css_parser.rb +0 -119
- data/lib/jsduck/doc_ast.rb +0 -319
- data/lib/jsduck/doc_formatter.rb +0 -142
- data/lib/jsduck/doc_parser.rb +0 -611
- data/lib/jsduck/doc_type.rb +0 -59
- data/lib/jsduck/enum.rb +0 -73
- data/lib/jsduck/esprima.rb +0 -51
- data/lib/jsduck/evaluator.rb +0 -69
- data/lib/jsduck/ext_patterns.rb +0 -58
- data/lib/jsduck/file_categories.rb +0 -76
- data/lib/jsduck/function_ast.rb +0 -206
- data/lib/jsduck/guide_anchors.rb +0 -32
- data/lib/jsduck/guide_toc.rb +0 -49
- data/lib/jsduck/html_stack.rb +0 -105
- data/lib/jsduck/importer.rb +0 -121
- data/lib/jsduck/inherit_doc.rb +0 -193
- data/lib/jsduck/js_parser.rb +0 -221
- data/lib/jsduck/lint.rb +0 -133
- data/lib/jsduck/meta_tag.rb +0 -88
- data/lib/jsduck/meta_tag_loader.rb +0 -67
- data/lib/jsduck/meta_tag_registry.rb +0 -111
- data/lib/jsduck/meta_tag_renderer.rb +0 -34
- data/lib/jsduck/news.rb +0 -128
- data/lib/jsduck/override.rb +0 -87
- data/lib/jsduck/renderer.rb +0 -361
- data/lib/jsduck/return_values.rb +0 -72
- data/lib/jsduck/serializer.rb +0 -262
- data/lib/jsduck/shortener.rb +0 -58
- data/lib/jsduck/signature_renderer.rb +0 -91
- data/lib/jsduck/source/file_parser.rb +0 -72
@@ -0,0 +1,55 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'jsduck/util/html'
|
3
|
+
|
4
|
+
module JsDuck
|
5
|
+
module Format
|
6
|
+
|
7
|
+
# Little helper for shortening text
|
8
|
+
class Shortener
|
9
|
+
# Takes as parameter the maximum length for text that doesn't
|
10
|
+
# get shortened. Used for testing purposes.
|
11
|
+
def initialize(max_length = 120)
|
12
|
+
@max_length = max_length
|
13
|
+
end
|
14
|
+
|
15
|
+
# Shortens text
|
16
|
+
#
|
17
|
+
# 116 chars is also where ext-doc makes its cut, but unlike
|
18
|
+
# ext-doc we only make the cut when there's more than 120 chars.
|
19
|
+
#
|
20
|
+
# This way we don't get stupid expansions like:
|
21
|
+
#
|
22
|
+
# Blah blah blah some text...
|
23
|
+
#
|
24
|
+
# expanding to:
|
25
|
+
#
|
26
|
+
# Blah blah blah some text.
|
27
|
+
#
|
28
|
+
def shorten(input)
|
29
|
+
sent = first_sentence(Util::HTML.strip_tags(input).strip)
|
30
|
+
# Use u-modifier to correctly count multi-byte characters
|
31
|
+
chars = sent.scan(/./mu)
|
32
|
+
if chars.length > @max_length
|
33
|
+
chars[0..(@max_length-4)].join + "..."
|
34
|
+
else
|
35
|
+
sent + " ..."
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Returns the first sentence inside a string.
|
40
|
+
def first_sentence(str)
|
41
|
+
str.sub(/\A(.+?(\.|。))\s.*\z/mu, "\\1")
|
42
|
+
end
|
43
|
+
|
44
|
+
# Returns true when input should get shortened.
|
45
|
+
def too_long?(input)
|
46
|
+
stripped = Util::HTML.strip_tags(input).strip
|
47
|
+
# for sentence v/s full - compare byte length
|
48
|
+
# for full v/s max - compare char length
|
49
|
+
first_sentence(stripped).length < stripped.length || stripped.scan(/./mu).length > @max_length
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'jsduck/util/html'
|
2
|
+
require 'jsduck/logger'
|
3
|
+
require 'jsduck/type_parser'
|
4
|
+
|
5
|
+
module JsDuck
|
6
|
+
module Format
|
7
|
+
|
8
|
+
# Helper for recursively formatting subproperties.
|
9
|
+
class Subproperties
|
10
|
+
|
11
|
+
def initialize(formatter)
|
12
|
+
@formatter = formatter
|
13
|
+
@skip_type_parsing = false
|
14
|
+
end
|
15
|
+
|
16
|
+
# Set to true to skip parsing and formatting of types.
|
17
|
+
# Used to skip parsing of CSS typesdefs.
|
18
|
+
attr_accessor :skip_type_parsing
|
19
|
+
|
20
|
+
# Takes a hash of param, return value, throws value or subproperty.
|
21
|
+
#
|
22
|
+
# - Markdown-formats the :doc field in it.
|
23
|
+
# - Parses the :type field and saves HTML to :html_type.
|
24
|
+
# - Recursively does the same with all items in :properties field.
|
25
|
+
#
|
26
|
+
def format(item)
|
27
|
+
item[:doc] = @formatter.format(item[:doc]) if item[:doc]
|
28
|
+
|
29
|
+
if item[:type]
|
30
|
+
item[:html_type] = format_type(item[:type])
|
31
|
+
end
|
32
|
+
|
33
|
+
if item[:properties]
|
34
|
+
item[:properties].each {|p| format(p) }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Formats the given type definition string using TypeParser.
|
39
|
+
#
|
40
|
+
# - On success returns HTML-version of the type definition.
|
41
|
+
# - On failure logs error and returns the type string with only HTML escaped.
|
42
|
+
#
|
43
|
+
def format_type(type)
|
44
|
+
# Skip the formatting entirely when type-parsing is turned off.
|
45
|
+
return Util::HTML.escape(type) if @skip_type_parsing
|
46
|
+
|
47
|
+
tp = TypeParser.new(@formatter)
|
48
|
+
if tp.parse(type)
|
49
|
+
tp.out
|
50
|
+
else
|
51
|
+
context = @formatter.doc_context
|
52
|
+
if tp.error == :syntax
|
53
|
+
Logger.warn(:type_syntax, "Incorrect type syntax #{type}", context[:filename], context[:linenr])
|
54
|
+
else
|
55
|
+
Logger.warn(:type_name, "Unknown type #{type}", context[:filename], context[:linenr])
|
56
|
+
end
|
57
|
+
Util::HTML.escape(type)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
data/lib/jsduck/guides.rb
CHANGED
@@ -4,8 +4,7 @@ require 'jsduck/util/io'
|
|
4
4
|
require 'jsduck/util/null_object'
|
5
5
|
require 'jsduck/logger'
|
6
6
|
require 'jsduck/grouped_asset'
|
7
|
-
require 'jsduck/
|
8
|
-
require 'jsduck/guide_anchors'
|
7
|
+
require 'jsduck/util/html'
|
9
8
|
require 'jsduck/img/dir'
|
10
9
|
require 'fileutils'
|
11
10
|
|
@@ -56,10 +55,6 @@ module JsDuck
|
|
56
55
|
def load_guide(guide)
|
57
56
|
return Logger.warn(:guide, "Guide not found", guide["url"]) unless File.exists?(guide["url"])
|
58
57
|
return Logger.warn(:guide, "Guide not found", guide[:filename]) unless File.exists?(guide[:filename])
|
59
|
-
unless js_ident?(guide["name"])
|
60
|
-
# Guide name is also used as JSONP callback method name.
|
61
|
-
return Logger.warn(:guide, "Guide name is not valid JS identifier: #{guide["name"]}", guide[:filename])
|
62
|
-
end
|
63
58
|
|
64
59
|
begin
|
65
60
|
return format_guide(guide)
|
@@ -72,9 +67,7 @@ module JsDuck
|
|
72
67
|
def format_guide(guide)
|
73
68
|
@formatter.doc_context = {:filename => guide[:filename], :linenr => 0}
|
74
69
|
@formatter.images = Img::Dir.new(guide["url"], "guides/#{guide["name"]}")
|
75
|
-
html = @formatter.format(Util::IO.read(guide[:filename]))
|
76
|
-
html = GuideToc.inject(html, guide['name'])
|
77
|
-
html = GuideAnchors.transform(html, guide['name'])
|
70
|
+
html = add_toc(guide, @formatter.format(Util::IO.read(guide[:filename])))
|
78
71
|
|
79
72
|
# Report unused images (but ignore the icon files)
|
80
73
|
@formatter.images.get("icon.png")
|
@@ -109,11 +102,6 @@ module JsDuck
|
|
109
102
|
end
|
110
103
|
end
|
111
104
|
|
112
|
-
# True when string is valid JavaScript identifier
|
113
|
-
def js_ident?(str)
|
114
|
-
/\A[$\w]+\z/ =~ str
|
115
|
-
end
|
116
|
-
|
117
105
|
# Ensures the guide dir contains icon.png.
|
118
106
|
# When there isn't looks for icon-lg.png and renames it to icon.png.
|
119
107
|
# When neither exists, copies over default icon.
|
@@ -127,6 +115,36 @@ module JsDuck
|
|
127
115
|
end
|
128
116
|
end
|
129
117
|
|
118
|
+
# Creates table of contents at the top of guide by looking for <h2> elements in HTML.
|
119
|
+
def add_toc(guide, html)
|
120
|
+
toc = [
|
121
|
+
"<div class='toc'>\n",
|
122
|
+
"<p><strong>Contents</strong></p>\n",
|
123
|
+
"<ol>\n",
|
124
|
+
]
|
125
|
+
new_html = []
|
126
|
+
i = 0
|
127
|
+
html.each_line do |line|
|
128
|
+
if line =~ /^<h2>(.*)<\/h2>$/
|
129
|
+
i += 1
|
130
|
+
text = Util::HTML.strip_tags($1)
|
131
|
+
toc << "<li><a href='#!/guide/#{guide['name']}-section-#{i}'>#{text}</a></li>\n"
|
132
|
+
new_html << "<h2 id='#{guide['name']}-section-#{i}'>#{text}</h2>\n"
|
133
|
+
else
|
134
|
+
new_html << line
|
135
|
+
end
|
136
|
+
end
|
137
|
+
toc << "</ol>\n"
|
138
|
+
toc << "</div>\n"
|
139
|
+
# Inject TOC at below first heading if at least 2 items in TOC
|
140
|
+
if i >= 2
|
141
|
+
new_html.insert(1, toc)
|
142
|
+
new_html.flatten.join
|
143
|
+
else
|
144
|
+
html
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
130
148
|
# Returns HTML listing of guides
|
131
149
|
def to_html(style="")
|
132
150
|
html = @groups.map do |group|
|
data/lib/jsduck/index_html.rb
CHANGED
@@ -37,10 +37,10 @@ module JsDuck
|
|
37
37
|
"{data_path}" => File.basename(@opts.data_path),
|
38
38
|
"{welcome}" => @assets.welcome.to_html("display:none"),
|
39
39
|
"{categories}" => @assets.categories.to_html("display:none"),
|
40
|
-
"{news}" => @assets.news.to_html("display:none"),
|
41
40
|
"{guides}" => @assets.guides.to_html("display:none"),
|
42
41
|
"{head_html}" => @opts.head_html,
|
43
42
|
"{body_html}" => @opts.body_html,
|
43
|
+
"{head_css}" => TagRegistry.css,
|
44
44
|
})
|
45
45
|
end
|
46
46
|
|
@@ -48,6 +48,7 @@ module JsDuck
|
|
48
48
|
write_template(in_file, out_file, {
|
49
49
|
"{title}" => @opts.title,
|
50
50
|
"{header}" => @opts.header,
|
51
|
+
"{head_css}" => TagRegistry.css,
|
51
52
|
})
|
52
53
|
end
|
53
54
|
|
@@ -60,6 +61,7 @@ module JsDuck
|
|
60
61
|
"{header}" => @opts.header,
|
61
62
|
"{categories}" => categories ? "<h1>API Documentation</h1> #{categories}" : "",
|
62
63
|
"{guides}" => guides ? "<h1>Guides</h1> #{guides}" : "",
|
64
|
+
"{head_css}" => TagRegistry.css,
|
63
65
|
})
|
64
66
|
end
|
65
67
|
|
@@ -71,7 +71,7 @@ module JsDuck
|
|
71
71
|
cls2, member2 = split_to_cls_and_member(cls)
|
72
72
|
if @relations[cls2] && @renderer.get_matching_member(cls2, {:name => member2})
|
73
73
|
return @renderer.link(cls2, member2, cls2+"."+member2)
|
74
|
-
elsif cls =~ /\.(js|css|html|php)\
|
74
|
+
elsif cls =~ /\.(js|css|html|php)\z/
|
75
75
|
# Ignore common filenames
|
76
76
|
else
|
77
77
|
warn_magic_link("#{cls} links to non-existing class")
|
@@ -80,7 +80,7 @@ module JsDuck
|
|
80
80
|
else
|
81
81
|
if @renderer.get_matching_member(@class_context, {:name => member})
|
82
82
|
return @renderer.link(@class_context, member, member)
|
83
|
-
elsif member =~ /\A([A-F0-9]{3}|[A-F0-9]{6})\
|
83
|
+
elsif member =~ /\A([A-F0-9]{3}|[A-F0-9]{6})\z/i || member =~ /\A[0-9]/
|
84
84
|
# Ignore HEX color codes and
|
85
85
|
# member names beginning with number
|
86
86
|
else
|
data/lib/jsduck/inline/link.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'jsduck/logger'
|
2
|
+
require 'jsduck/tag_registry'
|
2
3
|
|
3
4
|
module JsDuck
|
4
5
|
module Inline
|
@@ -40,7 +41,7 @@ module JsDuck
|
|
40
41
|
|
41
42
|
# applies the link template
|
42
43
|
def apply_tpl(target, text, full_link)
|
43
|
-
if target =~ /^(.*)#(static-)?(
|
44
|
+
if target =~ /^(.*)#(static-)?#{TagRegistry.member_type_regex}?(.*)$/
|
44
45
|
cls = $1.empty? ? @class_context : $1
|
45
46
|
static = $2 ? true : nil
|
46
47
|
type = $3 ? $3.intern : nil
|
@@ -78,12 +79,12 @@ module JsDuck
|
|
78
79
|
# one when we ignore the static members. If there's more,
|
79
80
|
# report ambiguity. If there's only static members, also
|
80
81
|
# report ambiguity.
|
81
|
-
instance_ms = ms.find_all {|m| !m[:
|
82
|
+
instance_ms = ms.find_all {|m| !m[:static] }
|
82
83
|
if instance_ms.length > 1
|
83
84
|
alternatives = instance_ms.map {|m| "#{m[:tagname]} in #{m[:owner]}" }.join(", ")
|
84
85
|
Logger.warn(:link_ambiguous, "#{full_link} is ambiguous: "+alternatives, file, line)
|
85
86
|
elsif instance_ms.length == 0
|
86
|
-
static_ms = ms.find_all {|m| m[:
|
87
|
+
static_ms = ms.find_all {|m| m[:static] }
|
87
88
|
alternatives = static_ms.map {|m| "static " + m[:tagname].to_s }.join(", ")
|
88
89
|
Logger.warn(:link_ambiguous, "#{full_link} is ambiguous: "+alternatives, file, line)
|
89
90
|
end
|
@@ -52,8 +52,8 @@ module JsDuck
|
|
52
52
|
def get_matching_member(cls, query)
|
53
53
|
ms = find_members(cls, query)
|
54
54
|
if ms.length > 1
|
55
|
-
instance_ms = ms.find_all {|m| !m[:
|
56
|
-
instance_ms.length > 0 ? instance_ms[0] : ms.find_all {|m| m[:
|
55
|
+
instance_ms = ms.find_all {|m| !m[:static] }
|
56
|
+
instance_ms.length > 0 ? instance_ms[0] : ms.find_all {|m| m[:static] }[0]
|
57
57
|
else
|
58
58
|
ms[0]
|
59
59
|
end
|
data/lib/jsduck/inline/video.rb
CHANGED
@@ -16,8 +16,14 @@ module JsDuck
|
|
16
16
|
@templates = {
|
17
17
|
"html5" => '<video src="%u">%a</video>',
|
18
18
|
"vimeo" => [
|
19
|
-
'<p><
|
20
|
-
|
19
|
+
'<p><object width="640" height="360">',
|
20
|
+
'<param name="allowfullscreen" value="true" />',
|
21
|
+
'<param name="allowscriptaccess" value="always" />',
|
22
|
+
'<param name="flashvars" value="api=1" />',
|
23
|
+
'<param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=%u&server=vimeo.com&color=4CC208&fullscreen=1" />',
|
24
|
+
'<embed src="http://vimeo.com/moogaloop.swf?clip_id=%u&server=vimeo.com&color=4CC208&fullscreen=1" ',
|
25
|
+
'type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="640" height="360"></embed>',
|
26
|
+
'</object></p>',
|
21
27
|
].join
|
22
28
|
}
|
23
29
|
|
@@ -0,0 +1,361 @@
|
|
1
|
+
require "jsduck/js/function"
|
2
|
+
require "jsduck/js/node"
|
3
|
+
require "jsduck/tag_registry"
|
4
|
+
|
5
|
+
module JsDuck
|
6
|
+
module Js
|
7
|
+
|
8
|
+
# Analyzes the AST produced by EsprimaParser.
|
9
|
+
class Ast
|
10
|
+
# Should be initialized with EsprimaParser#parse result.
|
11
|
+
def initialize(docs = [])
|
12
|
+
@docs = docs
|
13
|
+
end
|
14
|
+
|
15
|
+
# Performs the detection of code in all docsets.
|
16
|
+
#
|
17
|
+
# @returns the processed array of docsets. (But it does it
|
18
|
+
# destructively by modifying the passed-in docsets.)
|
19
|
+
#
|
20
|
+
def detect_all!
|
21
|
+
# First deal only with doc-comments
|
22
|
+
doc_comments = @docs.find_all {|d| d[:type] == :doc_comment }
|
23
|
+
|
24
|
+
# Detect code in each docset. Sometimes a docset has already
|
25
|
+
# been detected as part of detecting some previous docset (like
|
26
|
+
# Class detecting all of its configs) - in such case, skip.
|
27
|
+
doc_comments.each do |docset|
|
28
|
+
code = docset[:code]
|
29
|
+
docset[:code] = detect(code) unless code && code[:tagname]
|
30
|
+
end
|
31
|
+
|
32
|
+
# Return all doc-comments + other comments for which related
|
33
|
+
# code was detected.
|
34
|
+
@docs.find_all {|d| d[:type] == :doc_comment || d[:code] && d[:code][:tagname] }
|
35
|
+
end
|
36
|
+
|
37
|
+
# Given Esprima-produced syntax tree, detects documentation data.
|
38
|
+
#
|
39
|
+
# This method is exposed for testing purposes only, JSDuck itself
|
40
|
+
# only calls the above #detect_all method.
|
41
|
+
#
|
42
|
+
# @param ast :code from Result of EsprimaParser
|
43
|
+
# @returns Hash consisting of the detected :tagname, :name, and
|
44
|
+
# other properties relative to the tag. Like so:
|
45
|
+
#
|
46
|
+
# { :tagname => :method, :name => "foo", ... }
|
47
|
+
#
|
48
|
+
def detect(node)
|
49
|
+
ast = Js::Node.create(node)
|
50
|
+
|
51
|
+
exp = ast.expression_statement? ? ast["expression"] : nil
|
52
|
+
var = ast.variable_declaration? ? ast["declarations"][0] : nil
|
53
|
+
|
54
|
+
# Ext.define("Class", {})
|
55
|
+
if exp && exp.ext_define?
|
56
|
+
make_class(exp["arguments"][0].to_value, exp)
|
57
|
+
|
58
|
+
# Ext.override(Class, {})
|
59
|
+
elsif exp && exp.ext_override?
|
60
|
+
make_class("", exp)
|
61
|
+
|
62
|
+
# foo = Ext.extend(Parent, {})
|
63
|
+
elsif exp && exp.assignment_expression? && exp["right"].ext_extend?
|
64
|
+
make_class(exp["left"].to_s, exp["right"])
|
65
|
+
|
66
|
+
# Foo = ...
|
67
|
+
elsif exp && exp.assignment_expression? && class_name?(exp["left"].to_s)
|
68
|
+
make_class(exp["left"].to_s, exp["right"])
|
69
|
+
|
70
|
+
# var foo = Ext.extend(Parent, {})
|
71
|
+
elsif var && var["init"].ext_extend?
|
72
|
+
make_class(var["id"].to_s, var["init"])
|
73
|
+
|
74
|
+
# var Foo = ...
|
75
|
+
elsif var && class_name?(var["id"].to_s)
|
76
|
+
make_class(var["id"].to_s, var["right"])
|
77
|
+
|
78
|
+
# function Foo() {}
|
79
|
+
elsif ast.function? && class_name?(ast["id"].to_s || "")
|
80
|
+
make_class(ast["id"].to_s)
|
81
|
+
|
82
|
+
# { ... }
|
83
|
+
elsif ast.object_expression?
|
84
|
+
make_class("", ast)
|
85
|
+
|
86
|
+
# function foo() {}
|
87
|
+
elsif ast.function?
|
88
|
+
make_method(ast["id"].to_s || "", ast)
|
89
|
+
|
90
|
+
# foo = function() {}
|
91
|
+
elsif exp && exp.assignment_expression? && exp["right"].function?
|
92
|
+
make_method(exp["left"].to_s, exp["right"])
|
93
|
+
|
94
|
+
# var foo = function() {}
|
95
|
+
elsif var && var["init"] && var["init"].function?
|
96
|
+
make_method(var["id"].to_s, var["init"])
|
97
|
+
|
98
|
+
# (function() {})
|
99
|
+
elsif exp && exp.function?
|
100
|
+
make_method(exp["id"].to_s || "", exp)
|
101
|
+
|
102
|
+
# foo: function() {}
|
103
|
+
elsif ast.property? && ast["value"].function?
|
104
|
+
make_method(ast["key"].key_value, ast["value"])
|
105
|
+
|
106
|
+
# this.fireEvent("foo", ...)
|
107
|
+
elsif exp && exp.fire_event?
|
108
|
+
make_event(exp["arguments"][0].to_value)
|
109
|
+
|
110
|
+
# foo = ...
|
111
|
+
elsif exp && exp.assignment_expression?
|
112
|
+
make_property(exp["left"].to_s, exp["right"])
|
113
|
+
|
114
|
+
# var foo = ...
|
115
|
+
elsif var
|
116
|
+
make_property(var["id"].to_s, var["init"])
|
117
|
+
|
118
|
+
# foo: ...
|
119
|
+
elsif ast.property?
|
120
|
+
make_property(ast["key"].key_value, ast["value"])
|
121
|
+
|
122
|
+
# foo;
|
123
|
+
elsif exp && exp.identifier?
|
124
|
+
make_property(exp.to_s)
|
125
|
+
|
126
|
+
# "foo" (inside some expression)
|
127
|
+
elsif ast.string?
|
128
|
+
make_property(ast.to_value)
|
129
|
+
|
130
|
+
# "foo"; (as a statement of it's own)
|
131
|
+
elsif exp && exp.string?
|
132
|
+
make_property(exp.to_value)
|
133
|
+
|
134
|
+
else
|
135
|
+
make_property()
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
private
|
140
|
+
|
141
|
+
# Class name begins with upcase char
|
142
|
+
def class_name?(name)
|
143
|
+
return name.split(/\./).last =~ /\A[A-Z]/
|
144
|
+
end
|
145
|
+
|
146
|
+
def make_class(name, ast=nil)
|
147
|
+
cls = {
|
148
|
+
:tagname => :class,
|
149
|
+
:name => name,
|
150
|
+
}
|
151
|
+
|
152
|
+
# apply information from Ext.extend, Ext.define, or {}
|
153
|
+
if ast
|
154
|
+
if ast.ext_define?
|
155
|
+
detect_ext_define(cls, ast)
|
156
|
+
elsif ast.ext_extend?
|
157
|
+
detect_ext_something(:extends, cls, ast)
|
158
|
+
elsif ast.ext_override?
|
159
|
+
detect_ext_something(:override, cls, ast)
|
160
|
+
elsif ast.object_expression?
|
161
|
+
detect_class_members_from_object(cls, ast)
|
162
|
+
elsif ast.array_expression?
|
163
|
+
detect_class_members_from_array(cls, ast)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
return cls
|
168
|
+
end
|
169
|
+
|
170
|
+
# Detection of Ext.extend() or Ext.override().
|
171
|
+
# The type parameter must be correspondingly either :extend or :override.
|
172
|
+
def detect_ext_something(type, cls, ast)
|
173
|
+
args = ast["arguments"]
|
174
|
+
cls[type] = args[0].to_s
|
175
|
+
if args.length == 2 && args[1].object_expression?
|
176
|
+
detect_class_members_from_object(cls, args[1])
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
# Inspects Ext.define() and copies detected properties over to the
|
181
|
+
# given cls Hash
|
182
|
+
def detect_ext_define(cls, ast)
|
183
|
+
# defaults
|
184
|
+
cls.merge!(TagRegistry.ext_define_defaults)
|
185
|
+
cls[:members] = []
|
186
|
+
cls[:code_type] = :ext_define
|
187
|
+
|
188
|
+
ast["arguments"][1].each_property do |key, value, pair|
|
189
|
+
if tag = TagRegistry.get_by_ext_define_pattern(key)
|
190
|
+
tag.parse_ext_define(cls, value)
|
191
|
+
else
|
192
|
+
case key
|
193
|
+
when "config"
|
194
|
+
cls[:members] += make_configs(value, {:accessor => true})
|
195
|
+
when "cachedConfig"
|
196
|
+
cls[:members] += make_configs(value, {:accessor => true})
|
197
|
+
when "eventedConfig"
|
198
|
+
cls[:members] += make_configs(value, {:accessor => true, :evented => true})
|
199
|
+
when "statics"
|
200
|
+
cls[:members] += make_statics(value)
|
201
|
+
when "inheritableStatics"
|
202
|
+
cls[:members] += make_statics(value, {:inheritable => true})
|
203
|
+
else
|
204
|
+
detect_method_or_property(cls, key, value, pair)
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
# Detects class members from object literal
|
211
|
+
def detect_class_members_from_object(cls, ast)
|
212
|
+
cls[:members] = []
|
213
|
+
ast.each_property do |key, value, pair|
|
214
|
+
detect_method_or_property(cls, key, value, pair)
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
# Detects class members from array literal
|
219
|
+
def detect_class_members_from_array(cls, ast)
|
220
|
+
cls[:members] = []
|
221
|
+
|
222
|
+
# This will most likely be an @enum class, in which case the
|
223
|
+
# enum will be for documentation purposes only.
|
224
|
+
cls[:enum] = {:doc_only => true}
|
225
|
+
|
226
|
+
ast["elements"].each do |el|
|
227
|
+
detect_method_or_property(cls, el.key_value, el, el)
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
# Detects item in object literal either as method or property
|
232
|
+
def detect_method_or_property(cls, key, value, pair)
|
233
|
+
if value.function?
|
234
|
+
m = make_method(key, value)
|
235
|
+
cls[:members] << m if apply_autodetected(m, pair)
|
236
|
+
else
|
237
|
+
p = make_property(key, value)
|
238
|
+
cls[:members] << p if apply_autodetected(p, pair)
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
def make_configs(ast, defaults={})
|
243
|
+
configs = []
|
244
|
+
|
245
|
+
ast.each_property do |name, value, pair|
|
246
|
+
cfg = make_property(name, value, :cfg)
|
247
|
+
cfg.merge!(defaults)
|
248
|
+
configs << cfg if apply_autodetected(cfg, pair)
|
249
|
+
end
|
250
|
+
|
251
|
+
configs
|
252
|
+
end
|
253
|
+
|
254
|
+
def make_statics(ast, defaults={})
|
255
|
+
statics = []
|
256
|
+
|
257
|
+
ast.each_property do |name, value, pair|
|
258
|
+
if value.function?
|
259
|
+
s = make_method(name, value)
|
260
|
+
else
|
261
|
+
s = make_property(name, value)
|
262
|
+
end
|
263
|
+
|
264
|
+
s[:static] = true
|
265
|
+
s.merge!(defaults)
|
266
|
+
|
267
|
+
statics << s if apply_autodetected(s, pair, defaults[:inheritable])
|
268
|
+
end
|
269
|
+
|
270
|
+
statics
|
271
|
+
end
|
272
|
+
|
273
|
+
# Sets auto-detection related properties :autodetected and
|
274
|
+
# :inheritdoc on the given member Hash.
|
275
|
+
#
|
276
|
+
# When member has a comment, adds code to the related docset and
|
277
|
+
# returns false.
|
278
|
+
#
|
279
|
+
# Otherwise detects the line number of member and returns true.
|
280
|
+
def apply_autodetected(m, ast, inheritable=true)
|
281
|
+
docset = find_docset(ast.raw)
|
282
|
+
|
283
|
+
if !docset || docset[:type] != :doc_comment
|
284
|
+
if inheritable
|
285
|
+
m[:inheritdoc] = {}
|
286
|
+
else
|
287
|
+
m[:private] = true
|
288
|
+
end
|
289
|
+
m[:autodetected] = true
|
290
|
+
end
|
291
|
+
|
292
|
+
if docset
|
293
|
+
docset[:code] = m
|
294
|
+
return false
|
295
|
+
else
|
296
|
+
m[:linenr] = ast.linenr
|
297
|
+
return true
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
# Looks up docset associated with given AST node.
|
302
|
+
# A dead-stupid and -slow implementation, but works.
|
303
|
+
#
|
304
|
+
# The comparison needs to be done between raw AST nodes - multiple
|
305
|
+
# Node instances can be created to wrap a single raw AST node,
|
306
|
+
# and they will then not be equal.
|
307
|
+
def find_docset(raw_ast)
|
308
|
+
@docs.find do |docset|
|
309
|
+
docset[:code] == raw_ast
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
def make_method(name, ast)
|
314
|
+
return {
|
315
|
+
:tagname => :method,
|
316
|
+
:name => name,
|
317
|
+
:params => make_params(ast),
|
318
|
+
:chainable => chainable?(ast) && name != "constructor",
|
319
|
+
}
|
320
|
+
end
|
321
|
+
|
322
|
+
def make_params(ast)
|
323
|
+
if ast.function? && !ast.ext_empty_fn?
|
324
|
+
ast["params"].map {|p| {:name => p.to_s} }
|
325
|
+
else
|
326
|
+
[]
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
def chainable?(ast)
|
331
|
+
if ast.function? && !ast.ext_empty_fn?
|
332
|
+
Js::Function.return_types(ast.raw) == [:this]
|
333
|
+
else
|
334
|
+
false
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
def make_event(name)
|
339
|
+
return {
|
340
|
+
:tagname => :event,
|
341
|
+
:name => name,
|
342
|
+
}
|
343
|
+
end
|
344
|
+
|
345
|
+
def make_property(name=nil, ast=nil, tagname=:property)
|
346
|
+
return {
|
347
|
+
:tagname => tagname,
|
348
|
+
:name => name,
|
349
|
+
:type => ast && ast.value_type,
|
350
|
+
:default => ast && make_default(ast),
|
351
|
+
}
|
352
|
+
end
|
353
|
+
|
354
|
+
def make_default(ast)
|
355
|
+
ast.to_value != nil ? ast.to_s : nil
|
356
|
+
end
|
357
|
+
|
358
|
+
end
|
359
|
+
|
360
|
+
end
|
361
|
+
end
|