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
data/lib/jsduck/doc_type.rb
DELETED
@@ -1,59 +0,0 @@
|
|
1
|
-
module JsDuck
|
2
|
-
|
3
|
-
# Detects the type of documentation object: class, method, cfg, etc
|
4
|
-
class DocType
|
5
|
-
# Given parsed documentation and code, returns the tagname for
|
6
|
-
# documentation item.
|
7
|
-
#
|
8
|
-
# @param docs Result from DocParser
|
9
|
-
# @param code Result from Ast#detect or CssParser#parse
|
10
|
-
# @returns One of: :class, :method, :event, :cfg, :property, :css_var, :css_mixin
|
11
|
-
#
|
12
|
-
def detect(docs, code)
|
13
|
-
doc_map = build_doc_map(docs)
|
14
|
-
|
15
|
-
if doc_map[:class] || doc_map[:override]
|
16
|
-
:class
|
17
|
-
elsif doc_map[:event]
|
18
|
-
:event
|
19
|
-
elsif doc_map[:method]
|
20
|
-
:method
|
21
|
-
elsif doc_map[:property] || doc_map[:type]
|
22
|
-
:property
|
23
|
-
elsif doc_map[:css_var]
|
24
|
-
:css_var
|
25
|
-
elsif doc_map[:cfg] && doc_map[:cfg].length == 1
|
26
|
-
# When just one @cfg, avoid treating it as @class
|
27
|
-
:cfg
|
28
|
-
elsif code[:tagname] == :class
|
29
|
-
:class
|
30
|
-
elsif code[:tagname] == :css_mixin
|
31
|
-
:css_mixin
|
32
|
-
elsif doc_map[:cfg]
|
33
|
-
:cfg
|
34
|
-
elsif doc_map[:constructor]
|
35
|
-
:method
|
36
|
-
elsif doc_map[:param] || doc_map[:return]
|
37
|
-
:method
|
38
|
-
else
|
39
|
-
code[:tagname]
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
private
|
44
|
-
|
45
|
-
# Build map of at-tags for quick lookup
|
46
|
-
def build_doc_map(docs)
|
47
|
-
map = {}
|
48
|
-
docs.each do |tag|
|
49
|
-
if map[tag[:tagname]]
|
50
|
-
map[tag[:tagname]] << tag
|
51
|
-
else
|
52
|
-
map[tag[:tagname]] = [tag]
|
53
|
-
end
|
54
|
-
end
|
55
|
-
map
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
end
|
data/lib/jsduck/enum.rb
DELETED
@@ -1,73 +0,0 @@
|
|
1
|
-
module JsDuck
|
2
|
-
|
3
|
-
class Enum
|
4
|
-
def initialize(classes)
|
5
|
-
@classes = classes
|
6
|
-
end
|
7
|
-
|
8
|
-
# Applies additional processing to all enum-classes.
|
9
|
-
def process_all!
|
10
|
-
@classes.each_value do |cls|
|
11
|
-
if cls[:enum]
|
12
|
-
process(cls)
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
private
|
18
|
-
|
19
|
-
# processes single class
|
20
|
-
def process(cls)
|
21
|
-
expand_default(cls)
|
22
|
-
strip_inheritdoc(cls)
|
23
|
-
cls[:enum][:type] = infer_type(cls) unless cls[:enum][:type]
|
24
|
-
end
|
25
|
-
|
26
|
-
# Given an enum class, returns the type infered from its values.
|
27
|
-
def infer_type(cls)
|
28
|
-
if cls[:members].length > 0
|
29
|
-
types = cls[:members].map {|p| p[:type] }
|
30
|
-
types.sort.uniq.join("/")
|
31
|
-
else
|
32
|
-
"Object"
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
# Expands default value like widget.* into list of properties
|
37
|
-
def expand_default(cls)
|
38
|
-
if cls[:enum][:default] =~ /\A(.*)\.\*\Z/
|
39
|
-
each_alias($1) do |name, owner|
|
40
|
-
cls[:members] << {
|
41
|
-
:tagname => :property,
|
42
|
-
:id => 'property-' + name,
|
43
|
-
:name => name,
|
44
|
-
:default => "'" + name + "'",
|
45
|
-
:type => "String",
|
46
|
-
:meta => {:private => owner[:private]},
|
47
|
-
:private => owner[:private],
|
48
|
-
:files => cls[:files],
|
49
|
-
:owner => cls[:name],
|
50
|
-
:doc => "Alias for {@link #{owner[:name]}}.",
|
51
|
-
}
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
def each_alias(prefix)
|
57
|
-
@classes.each_value do |cls|
|
58
|
-
if cls[:aliases] && cls[:aliases][prefix]
|
59
|
-
cls[:aliases][prefix].each {|name| yield(name, cls) }
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
# Remove the auto-inserted inheritdoc tag so the auto-detected enum
|
65
|
-
# values default to being public.
|
66
|
-
def strip_inheritdoc(cls)
|
67
|
-
cls[:members].each do |p|
|
68
|
-
p[:inheritdoc] = nil if p[:autodetected]
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
end
|
data/lib/jsduck/esprima.rb
DELETED
@@ -1,51 +0,0 @@
|
|
1
|
-
require 'execjs'
|
2
|
-
require 'jsduck/util/json'
|
3
|
-
require 'jsduck/util/singleton'
|
4
|
-
|
5
|
-
module JsDuck
|
6
|
-
|
7
|
-
# Runs Esprima.js through JavaScript runtime selected by ExecJS.
|
8
|
-
# Normally this will be V8 engine within therubyracer gem, but when
|
9
|
-
# JSDuck is installed through some other means than rubygems, then
|
10
|
-
# one could use any of the runtimes supported by ExecJS. (NodeJS
|
11
|
-
# for example.)
|
12
|
-
#
|
13
|
-
# Initialized as singleton to avoid loading the esprima.js more
|
14
|
-
# than once - otherwise performace will severely suffer.
|
15
|
-
class Esprima
|
16
|
-
include Util::Singleton
|
17
|
-
|
18
|
-
def initialize
|
19
|
-
esprima_path = File.dirname(File.expand_path(__FILE__)) + "/esprima/esprima.js"
|
20
|
-
esprima = IO.read(esprima_path)
|
21
|
-
|
22
|
-
# Esprima attempts to assign to window.esprima, but our v8
|
23
|
-
# engine has no global window variable defined. So define our
|
24
|
-
# own and then grab esprima out from it again.
|
25
|
-
source = <<-EOJS
|
26
|
-
if (typeof window === "undefined") {
|
27
|
-
var window = {};
|
28
|
-
}
|
29
|
-
|
30
|
-
#{esprima}
|
31
|
-
|
32
|
-
var esprima = window.esprima;
|
33
|
-
|
34
|
-
function runEsprima(js) {
|
35
|
-
return JSON.stringify(esprima.parse(js, {comment: true, range: true, raw: true}));
|
36
|
-
}
|
37
|
-
EOJS
|
38
|
-
|
39
|
-
@context = ExecJS.compile(source)
|
40
|
-
end
|
41
|
-
|
42
|
-
# Parses JavaScript source code using Esprima.js
|
43
|
-
#
|
44
|
-
# Returns the resulting AST
|
45
|
-
def parse(input)
|
46
|
-
json = @context.call("runEsprima", input)
|
47
|
-
return Util::Json.parse(json, :max_nesting => false)
|
48
|
-
end
|
49
|
-
|
50
|
-
end
|
51
|
-
end
|
data/lib/jsduck/evaluator.rb
DELETED
@@ -1,69 +0,0 @@
|
|
1
|
-
module JsDuck
|
2
|
-
|
3
|
-
# Evaluates Esprima AST node into Ruby object
|
4
|
-
class Evaluator
|
5
|
-
|
6
|
-
# Converts AST node into a value.
|
7
|
-
#
|
8
|
-
# - String literals become Ruby strings
|
9
|
-
# - Number literals become Ruby numbers
|
10
|
-
# - Regex literals become :regexp symbols
|
11
|
-
# - Array expressions become Ruby arrays
|
12
|
-
# - etc
|
13
|
-
#
|
14
|
-
# For anything it doesn't know how to evaluate (like a function
|
15
|
-
# expression) it throws exception.
|
16
|
-
#
|
17
|
-
def to_value(ast)
|
18
|
-
case ast["type"]
|
19
|
-
when "ArrayExpression"
|
20
|
-
ast["elements"].map {|e| to_value(e) }
|
21
|
-
when "ObjectExpression"
|
22
|
-
h = {}
|
23
|
-
ast["properties"].each do |p|
|
24
|
-
key = key_value(p["key"])
|
25
|
-
value = to_value(p["value"])
|
26
|
-
h[key] = value
|
27
|
-
end
|
28
|
-
h
|
29
|
-
when "BinaryExpression"
|
30
|
-
if ast["operator"] == "+"
|
31
|
-
to_value(ast["left"]) + to_value(ast["right"])
|
32
|
-
else
|
33
|
-
throw "Unable to handle operator: " + ast["operator"]
|
34
|
-
end
|
35
|
-
when "MemberExpression"
|
36
|
-
if base_css_prefix?(ast)
|
37
|
-
"x-"
|
38
|
-
else
|
39
|
-
throw "Unable to handle this MemberExpression"
|
40
|
-
end
|
41
|
-
when "Literal"
|
42
|
-
if ast["raw"] =~ /\A\//
|
43
|
-
:regexp
|
44
|
-
else
|
45
|
-
ast["value"]
|
46
|
-
end
|
47
|
-
else
|
48
|
-
throw "Unknown node type: " + ast["type"]
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
# Turns object property key into string value
|
53
|
-
def key_value(key)
|
54
|
-
key["type"] == "Identifier" ? key["name"] : key["value"]
|
55
|
-
end
|
56
|
-
|
57
|
-
# True when MemberExpression == Ext.baseCSSPrefix
|
58
|
-
def base_css_prefix?(ast)
|
59
|
-
ast["computed"] == false &&
|
60
|
-
ast["object"]["type"] == "Identifier" &&
|
61
|
-
ast["object"]["name"] == "Ext" &&
|
62
|
-
ast["property"]["type"] == "Identifier" &&
|
63
|
-
ast["property"]["name"] == "baseCSSPrefix"
|
64
|
-
end
|
65
|
-
|
66
|
-
end
|
67
|
-
|
68
|
-
end
|
69
|
-
|
data/lib/jsduck/ext_patterns.rb
DELETED
@@ -1,58 +0,0 @@
|
|
1
|
-
module JsDuck
|
2
|
-
|
3
|
-
# Identifies Ext JS builtins like Ext.define and Ext.extend, taking
|
4
|
-
# also into account the possibility of aliasing the Ext namespace.
|
5
|
-
#
|
6
|
-
# For example when the following command line option is used:
|
7
|
-
#
|
8
|
-
# --ext-namespaces=Ext,MyApp
|
9
|
-
#
|
10
|
-
# we need to identify both Ext.define and MyApp.define, but
|
11
|
-
# Ext.define is additionally aliased withing ExtJS as
|
12
|
-
# Ext.ClassManager.create, so we also need to recognize
|
13
|
-
# Ext.ClassManager.create and MyApp.ClassManager.create.
|
14
|
-
#
|
15
|
-
# The matches? method will take care of identifying all these four
|
16
|
-
# cases:
|
17
|
-
#
|
18
|
-
# ps = ExtPatterns.new(["Ext", "MyApp"])
|
19
|
-
# matches?("Ext.define", "MyApp.define") --> true
|
20
|
-
#
|
21
|
-
class ExtPatterns
|
22
|
-
def initialize(namespaces)
|
23
|
-
@patterns = {
|
24
|
-
"Ext.define" => build_patterns(namespaces, [".define", ".ClassManager.create"]),
|
25
|
-
"Ext.extend" => build_patterns(namespaces, [".extend"]),
|
26
|
-
"Ext.override" => build_patterns(namespaces, [".override"]),
|
27
|
-
"Ext.emptyFn" => build_patterns(namespaces, [".emptyFn"]),
|
28
|
-
}
|
29
|
-
end
|
30
|
-
|
31
|
-
# True when string matches the given pattern type.
|
32
|
-
#
|
33
|
-
# Pattern type is one of: "Ext.define", "Ext.extend",
|
34
|
-
# "Ext.override", "Ext.emptyFn"
|
35
|
-
def matches?(pattern, string)
|
36
|
-
@patterns[pattern].include?(string)
|
37
|
-
end
|
38
|
-
|
39
|
-
private
|
40
|
-
|
41
|
-
# Given Array of alternate Ext namespaces builds list of patterns
|
42
|
-
# for detecting Ext.define or some other construct:
|
43
|
-
#
|
44
|
-
# build_patterns(["Ext", "Foo"], [".define"]) --> ["Ext.define", "Foo.define"]
|
45
|
-
#
|
46
|
-
def build_patterns(namespaces, suffixes)
|
47
|
-
patterns = []
|
48
|
-
namespaces.each do |ns|
|
49
|
-
suffixes.each do |suffix|
|
50
|
-
patterns << ns + suffix
|
51
|
-
end
|
52
|
-
end
|
53
|
-
patterns
|
54
|
-
end
|
55
|
-
|
56
|
-
end
|
57
|
-
|
58
|
-
end
|
@@ -1,76 +0,0 @@
|
|
1
|
-
require 'jsduck/logger'
|
2
|
-
require 'jsduck/util/json'
|
3
|
-
|
4
|
-
module JsDuck
|
5
|
-
|
6
|
-
# Reads categories info from config file
|
7
|
-
class FileCategories
|
8
|
-
def initialize(filename, relations)
|
9
|
-
@filename = filename
|
10
|
-
@relations = relations
|
11
|
-
end
|
12
|
-
|
13
|
-
# Parses categories in JSON file
|
14
|
-
def generate
|
15
|
-
@categories = Util::Json.read(@filename)
|
16
|
-
|
17
|
-
# Don't crash if old syntax is used.
|
18
|
-
if @categories.is_a?(Hash) && @categories["categories"]
|
19
|
-
Logger.warn(nil, 'Update categories file to contain just the array inside {"categories": [...]}', @filename)
|
20
|
-
@categories = @categories["categories"]
|
21
|
-
end
|
22
|
-
|
23
|
-
# Perform expansion on all class names containing * wildcard
|
24
|
-
@categories.each do |cat|
|
25
|
-
cat["groups"].each do |group|
|
26
|
-
group["classes"] = group["classes"].map do |name|
|
27
|
-
expand(name)
|
28
|
-
end.flatten
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
validate
|
33
|
-
|
34
|
-
@categories
|
35
|
-
end
|
36
|
-
|
37
|
-
# Expands class name like 'Foo.*' into multiple class names.
|
38
|
-
def expand(name)
|
39
|
-
re = Regexp.new("^" + name.split(/\*/, -1).map {|part| Regexp.escape(part) }.join('.*') + "$")
|
40
|
-
|
41
|
-
classes = @relations.to_a.find_all do |cls|
|
42
|
-
re =~ cls[:name] && !cls[:private] && !deprecated?(cls)
|
43
|
-
end.map {|cls| cls[:name] }.sort
|
44
|
-
|
45
|
-
if classes.length == 0
|
46
|
-
Logger.warn(:cat_no_match, "No class found matching a pattern '#{name}' in categories file", @filename)
|
47
|
-
end
|
48
|
-
classes
|
49
|
-
end
|
50
|
-
|
51
|
-
# Prints warnings for missing classes in categories file
|
52
|
-
def validate
|
53
|
-
# Build a map of all classes listed in categories
|
54
|
-
listed_classes = {}
|
55
|
-
@categories.each do |cat|
|
56
|
-
cat["groups"].each do |group|
|
57
|
-
group["classes"].each do |cls_name|
|
58
|
-
listed_classes[cls_name] = true
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
# Check that each existing non-private & non-deprecated class is listed
|
64
|
-
@relations.each do |cls|
|
65
|
-
unless listed_classes[cls[:name]] || cls[:private] || deprecated?(cls)
|
66
|
-
Logger.warn(:cat_class_missing, "Class '#{cls[:name]}' not found in categories file", @filename)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
def deprecated?(cls)
|
72
|
-
cls[:meta] && cls[:meta][:deprecated]
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
end
|
data/lib/jsduck/function_ast.rb
DELETED
@@ -1,206 +0,0 @@
|
|
1
|
-
require "jsduck/util/singleton"
|
2
|
-
require "jsduck/serializer"
|
3
|
-
require "jsduck/evaluator"
|
4
|
-
|
5
|
-
module JsDuck
|
6
|
-
|
7
|
-
# Analyzes the AST of a FunctionDeclaration or FunctionExpression.
|
8
|
-
class FunctionAst
|
9
|
-
include Util::Singleton
|
10
|
-
|
11
|
-
# Detects possible return types of the given function.
|
12
|
-
#
|
13
|
-
# For now there are three possible detected return values:
|
14
|
-
#
|
15
|
-
# * :this - the code contins 'return this;'
|
16
|
-
#
|
17
|
-
# * "undefined" - the code finishes by returning undefined or
|
18
|
-
# without explicitly returning anything
|
19
|
-
#
|
20
|
-
# * :other - some other value is returned.
|
21
|
-
#
|
22
|
-
def return_types(ast)
|
23
|
-
h = return_types_hash(ast["body"]["body"])
|
24
|
-
|
25
|
-
# Replace the special :void value that signifies possibility of
|
26
|
-
# exiting without explicitly returning anything
|
27
|
-
if h[:void]
|
28
|
-
h["undefined"] = true
|
29
|
-
h.delete(:void)
|
30
|
-
end
|
31
|
-
|
32
|
-
h.keys
|
33
|
-
end
|
34
|
-
|
35
|
-
private
|
36
|
-
|
37
|
-
def return_types_hash(body)
|
38
|
-
rvalues = {}
|
39
|
-
body.each do |ast|
|
40
|
-
if return?(ast)
|
41
|
-
type = value_type(ast["argument"])
|
42
|
-
rvalues[type] = true
|
43
|
-
return rvalues
|
44
|
-
elsif possibly_blocking?(ast)
|
45
|
-
extract_bodies(ast).each do |b|
|
46
|
-
rvalues.merge!(return_types_hash(b))
|
47
|
-
end
|
48
|
-
if !rvalues[:void]
|
49
|
-
return rvalues
|
50
|
-
else
|
51
|
-
rvalues.delete(:void)
|
52
|
-
end
|
53
|
-
elsif control_flow?(ast)
|
54
|
-
extract_bodies(ast).each do |b|
|
55
|
-
rvalues.merge!(return_types_hash(b))
|
56
|
-
end
|
57
|
-
rvalues.delete(:void)
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
rvalues[:void] = true
|
62
|
-
return rvalues
|
63
|
-
end
|
64
|
-
|
65
|
-
def return?(ast)
|
66
|
-
ast["type"] == "ReturnStatement"
|
67
|
-
end
|
68
|
-
|
69
|
-
def value_type(ast)
|
70
|
-
if !ast
|
71
|
-
:void
|
72
|
-
elsif undefined?(ast) || void?(ast)
|
73
|
-
"undefined"
|
74
|
-
elsif this?(ast)
|
75
|
-
:this
|
76
|
-
elsif boolean?(ast)
|
77
|
-
"Boolean"
|
78
|
-
elsif string?(ast)
|
79
|
-
"String"
|
80
|
-
elsif regexp?(ast)
|
81
|
-
"RegExp"
|
82
|
-
else
|
83
|
-
:other
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
def undefined?(ast)
|
88
|
-
ast["type"] == "Identifier" && ast["name"] == "undefined"
|
89
|
-
end
|
90
|
-
|
91
|
-
def void?(ast)
|
92
|
-
ast["type"] == "UnaryExpression" && ast["operator"] == "void"
|
93
|
-
end
|
94
|
-
|
95
|
-
def this?(ast)
|
96
|
-
ast["type"] == "ThisExpression"
|
97
|
-
end
|
98
|
-
|
99
|
-
def boolean?(ast)
|
100
|
-
if boolean_literal?(ast)
|
101
|
-
true
|
102
|
-
elsif ast["type"] == "UnaryExpression" || ast["type"] == "BinaryExpression"
|
103
|
-
!!BOOLEAN_RETURNING_OPERATORS[ast["operator"]]
|
104
|
-
elsif ast["type"] == "LogicalExpression"
|
105
|
-
boolean?(ast["left"]) && boolean?(ast["right"])
|
106
|
-
elsif ast["type"] == "ConditionalExpression"
|
107
|
-
boolean?(ast["consequent"]) && boolean?(ast["alternate"])
|
108
|
-
elsif ast["type"] == "AssignmentExpression" && ast["operator"] == "="
|
109
|
-
boolean?(ast["right"])
|
110
|
-
else
|
111
|
-
false
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
def boolean_literal?(ast)
|
116
|
-
ast["type"] == "Literal" && (ast["value"] == true || ast["value"] == false)
|
117
|
-
end
|
118
|
-
|
119
|
-
def string?(ast)
|
120
|
-
if string_literal?(ast)
|
121
|
-
true
|
122
|
-
elsif ast["type"] == "BinaryExpression" && ast["operator"] == "+"
|
123
|
-
string?(ast["left"]) || string?(ast["right"])
|
124
|
-
elsif ast["type"] == "UnaryExpression" && ast["operator"] == "typeof"
|
125
|
-
true
|
126
|
-
else
|
127
|
-
false
|
128
|
-
end
|
129
|
-
end
|
130
|
-
|
131
|
-
def string_literal?(ast)
|
132
|
-
ast["type"] == "Literal" && ast["value"].is_a?(String)
|
133
|
-
end
|
134
|
-
|
135
|
-
def regexp?(ast)
|
136
|
-
ast["type"] == "Literal" && ast["raw"] =~ /^\//
|
137
|
-
end
|
138
|
-
|
139
|
-
def control_flow?(ast)
|
140
|
-
CONTROL_FLOW[ast["type"]]
|
141
|
-
end
|
142
|
-
|
143
|
-
def extract_bodies(ast)
|
144
|
-
body = []
|
145
|
-
CONTROL_FLOW[ast["type"]].each do |name|
|
146
|
-
statements = ast[name]
|
147
|
-
if statements.is_a?(Hash)
|
148
|
-
body << [statements]
|
149
|
-
else
|
150
|
-
body << Array(statements)
|
151
|
-
end
|
152
|
-
end
|
153
|
-
body
|
154
|
-
end
|
155
|
-
|
156
|
-
# True if the node is a control structure which will block further
|
157
|
-
# program flow when all its branches finish with a return
|
158
|
-
# statement.
|
159
|
-
def possibly_blocking?(ast)
|
160
|
-
if POSSIBLY_BLOCKING[ast["type"]]
|
161
|
-
CONTROL_FLOW[ast["type"]].all? {|key| ast[key] }
|
162
|
-
else
|
163
|
-
false
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
BOOLEAN_RETURNING_OPERATORS = {
|
168
|
-
"!" => true,
|
169
|
-
">" => true,
|
170
|
-
">=" => true,
|
171
|
-
"<" => true,
|
172
|
-
"<=" => true,
|
173
|
-
"==" => true,
|
174
|
-
"!=" => true,
|
175
|
-
"===" => true,
|
176
|
-
"!==" => true,
|
177
|
-
"in" => true,
|
178
|
-
"instanceof" => true,
|
179
|
-
"delete" => true,
|
180
|
-
}
|
181
|
-
|
182
|
-
POSSIBLY_BLOCKING = {
|
183
|
-
"IfStatement" => true,
|
184
|
-
"DoWhileStatement" => true,
|
185
|
-
"WithStatement" => true,
|
186
|
-
"LabeledStatement" => true,
|
187
|
-
"BlockStatement" => true,
|
188
|
-
}
|
189
|
-
|
190
|
-
CONTROL_FLOW = {
|
191
|
-
"IfStatement" => ["consequent", "alternate"],
|
192
|
-
"SwitchStatement" => ["cases"],
|
193
|
-
"SwitchCase" => ["consequent"],
|
194
|
-
"ForStatement" => ["body"],
|
195
|
-
"ForInStatement" => ["body"],
|
196
|
-
"WhileStatement" => ["body"],
|
197
|
-
"DoWhileStatement" => ["body"],
|
198
|
-
"TryStatement" => ["block", "handlers", "finalizer"],
|
199
|
-
"CatchClause" => ["body"],
|
200
|
-
"WithStatement" => ["body"],
|
201
|
-
"LabeledStatement" => ["body"],
|
202
|
-
"BlockStatement" => ["body"],
|
203
|
-
}
|
204
|
-
end
|
205
|
-
|
206
|
-
end
|