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.
Files changed (183) hide show
  1. data/.travis.yml +0 -1
  2. data/README.md +32 -6
  3. data/Rakefile +10 -18
  4. data/bin/compare +5 -5
  5. data/bin/jsduck +2 -3
  6. data/jsduck.gemspec +3 -4
  7. data/lib/jsduck/aggregator.rb +21 -80
  8. data/lib/jsduck/app.rb +7 -14
  9. data/lib/jsduck/app_data.rb +4 -5
  10. data/lib/jsduck/assets.rb +4 -7
  11. data/lib/jsduck/base_type.rb +53 -0
  12. data/lib/jsduck/batch_parser.rb +8 -87
  13. data/lib/jsduck/batch_processor.rb +77 -0
  14. data/lib/jsduck/categories/auto.rb +83 -0
  15. data/lib/jsduck/categories/class_name.rb +63 -0
  16. data/lib/jsduck/categories/factory.rb +113 -0
  17. data/lib/jsduck/categories/file.rb +75 -0
  18. data/lib/jsduck/class.rb +3 -9
  19. data/lib/jsduck/class_doc_expander.rb +1 -1
  20. data/lib/jsduck/css/lexer.rb +203 -0
  21. data/lib/jsduck/css/parser.rb +121 -0
  22. data/lib/jsduck/doc/comment.rb +40 -0
  23. data/lib/jsduck/doc/map.rb +23 -0
  24. data/lib/jsduck/doc/parser.rb +128 -0
  25. data/lib/jsduck/doc/processor.rb +52 -0
  26. data/lib/jsduck/doc/scanner.rb +76 -0
  27. data/lib/jsduck/doc/standard_tag_parser.rb +154 -0
  28. data/lib/jsduck/doc/subproperties.rb +64 -0
  29. data/lib/jsduck/docs_code_comparer.rb +31 -0
  30. data/lib/jsduck/export_writer.rb +2 -2
  31. data/lib/jsduck/exporter/app.rb +16 -4
  32. data/lib/jsduck/exporter/full.rb +2 -2
  33. data/lib/jsduck/format/batch.rb +58 -0
  34. data/lib/jsduck/format/class.rb +62 -0
  35. data/lib/jsduck/format/doc.rb +172 -0
  36. data/lib/jsduck/format/html_stack.rb +109 -0
  37. data/lib/jsduck/format/shortener.rb +55 -0
  38. data/lib/jsduck/format/subproperties.rb +64 -0
  39. data/lib/jsduck/guides.rb +32 -14
  40. data/lib/jsduck/index_html.rb +3 -1
  41. data/lib/jsduck/inline/auto_link.rb +2 -2
  42. data/lib/jsduck/inline/link.rb +4 -3
  43. data/lib/jsduck/inline/link_renderer.rb +2 -2
  44. data/lib/jsduck/inline/video.rb +8 -2
  45. data/lib/jsduck/js/ast.rb +361 -0
  46. data/lib/jsduck/js/esprima.rb +39 -0
  47. data/lib/jsduck/{esprima → js/esprima}/esprima.js +0 -0
  48. data/lib/jsduck/js/evaluator.rb +70 -0
  49. data/lib/jsduck/js/ext_patterns.rb +70 -0
  50. data/lib/jsduck/js/function.rb +206 -0
  51. data/lib/jsduck/js/node.rb +194 -0
  52. data/lib/jsduck/js/node_array.rb +36 -0
  53. data/lib/jsduck/js/parser.rb +223 -0
  54. data/lib/jsduck/js/serializer.rb +263 -0
  55. data/lib/jsduck/js/utils.rb +21 -0
  56. data/lib/jsduck/logger.rb +3 -13
  57. data/lib/jsduck/members_index.rb +3 -4
  58. data/lib/jsduck/merger.rb +25 -145
  59. data/lib/jsduck/options.rb +29 -132
  60. data/lib/jsduck/parser.rb +76 -0
  61. data/lib/jsduck/process/accessors.rb +133 -0
  62. data/lib/jsduck/process/circular_deps.rb +58 -0
  63. data/lib/jsduck/process/enums.rb +91 -0
  64. data/lib/jsduck/process/ext4_events.rb +43 -0
  65. data/lib/jsduck/process/global_members.rb +36 -0
  66. data/lib/jsduck/process/ignored_classes.rb +16 -0
  67. data/lib/jsduck/process/importer.rb +58 -0
  68. data/lib/jsduck/process/inherit_doc.rb +197 -0
  69. data/lib/jsduck/process/lint.rb +135 -0
  70. data/lib/jsduck/process/overrides.rb +99 -0
  71. data/lib/jsduck/process/return_values.rb +72 -0
  72. data/lib/jsduck/process/versions.rb +102 -0
  73. data/lib/jsduck/relations.rb +5 -0
  74. data/lib/jsduck/render/class.rb +144 -0
  75. data/lib/jsduck/render/sidebar.rb +97 -0
  76. data/lib/jsduck/render/signature.rb +94 -0
  77. data/lib/jsduck/render/subproperties.rb +99 -0
  78. data/lib/jsduck/render/tags.rb +38 -0
  79. data/lib/jsduck/search_data.rb +19 -13
  80. data/lib/jsduck/source/file.rb +8 -17
  81. data/lib/jsduck/tag/abstract.rb +4 -7
  82. data/lib/jsduck/tag/accessor.rb +10 -0
  83. data/lib/jsduck/tag/alias.rb +61 -0
  84. data/lib/jsduck/tag/alternate_class_names.rb +17 -0
  85. data/lib/jsduck/tag/aside.rb +28 -31
  86. data/lib/jsduck/tag/author.rb +9 -5
  87. data/lib/jsduck/tag/boolean_tag.rb +24 -0
  88. data/lib/jsduck/tag/cfg.rb +45 -0
  89. data/lib/jsduck/tag/chainable.rb +5 -7
  90. data/lib/jsduck/tag/class.rb +28 -0
  91. data/lib/jsduck/tag/class_list_tag.rb +40 -0
  92. data/lib/jsduck/tag/constructor.rb +24 -0
  93. data/lib/jsduck/tag/css_mixin.rb +17 -0
  94. data/lib/jsduck/tag/css_var.rb +29 -0
  95. data/lib/jsduck/tag/default.rb +31 -0
  96. data/lib/jsduck/tag/deprecated.rb +13 -27
  97. data/lib/jsduck/tag/deprecated_tag.rb +58 -0
  98. data/lib/jsduck/tag/doc.rb +32 -0
  99. data/lib/jsduck/tag/docauthor.rb +4 -5
  100. data/lib/jsduck/tag/enum.rb +70 -0
  101. data/lib/jsduck/tag/event.rb +28 -0
  102. data/lib/jsduck/tag/evented.rb +10 -0
  103. data/lib/jsduck/tag/extends.rb +45 -0
  104. data/lib/jsduck/tag/ftype.rb +18 -0
  105. data/lib/jsduck/tag/hide.rb +4 -11
  106. data/lib/jsduck/tag/ignore.rb +6 -7
  107. data/lib/jsduck/tag/inheritable.rb +10 -0
  108. data/lib/jsduck/tag/inheritdoc.rb +48 -0
  109. data/lib/jsduck/tag/markdown.rb +8 -6
  110. data/lib/jsduck/tag/member.rb +24 -0
  111. data/lib/jsduck/tag/method.rb +35 -0
  112. data/lib/jsduck/tag/mixins.rb +26 -0
  113. data/lib/jsduck/tag/name.rb +36 -0
  114. data/lib/jsduck/tag/new.rb +13 -27
  115. data/lib/jsduck/tag/override.rb +37 -0
  116. data/lib/jsduck/tag/overrides.rb +29 -0
  117. data/lib/jsduck/tag/param.rb +87 -0
  118. data/lib/jsduck/tag/preventable.rb +19 -10
  119. data/lib/jsduck/tag/private.rb +28 -13
  120. data/lib/jsduck/tag/property.rb +39 -0
  121. data/lib/jsduck/tag/protected.rb +5 -7
  122. data/lib/jsduck/tag/ptype.rb +18 -0
  123. data/lib/jsduck/tag/readonly.rb +4 -7
  124. data/lib/jsduck/tag/removed.rb +21 -29
  125. data/lib/jsduck/tag/required.rb +11 -9
  126. data/lib/jsduck/tag/requires.rb +12 -0
  127. data/lib/jsduck/tag/return.rb +47 -0
  128. data/lib/jsduck/tag/since.rb +19 -11
  129. data/lib/jsduck/tag/singleton.rb +15 -0
  130. data/lib/jsduck/tag/static.rb +5 -7
  131. data/lib/jsduck/tag/subproperties.rb +23 -0
  132. data/lib/jsduck/tag/tag.rb +208 -0
  133. data/lib/jsduck/tag/template.rb +14 -9
  134. data/lib/jsduck/tag/throws.rb +38 -0
  135. data/lib/jsduck/tag/type.rb +48 -0
  136. data/lib/jsduck/tag/uses.rb +12 -0
  137. data/lib/jsduck/tag/xtype.rb +30 -0
  138. data/lib/jsduck/tag_loader.rb +39 -0
  139. data/lib/jsduck/tag_registry.rb +189 -0
  140. data/lib/jsduck/type_parser.rb +3 -3
  141. data/lib/jsduck/web_writer.rb +2 -2
  142. data/lib/jsduck/welcome.rb +1 -1
  143. metadata +578 -538
  144. data/lib/jsduck/accessors.rb +0 -136
  145. data/lib/jsduck/ast.rb +0 -524
  146. data/lib/jsduck/auto_categories.rb +0 -80
  147. data/lib/jsduck/batch_formatter.rb +0 -60
  148. data/lib/jsduck/categories.rb +0 -73
  149. data/lib/jsduck/categories_class_name.rb +0 -37
  150. data/lib/jsduck/circular_deps.rb +0 -56
  151. data/lib/jsduck/class_formatter.rb +0 -102
  152. data/lib/jsduck/columns.rb +0 -56
  153. data/lib/jsduck/css_lexer.rb +0 -201
  154. data/lib/jsduck/css_parser.rb +0 -119
  155. data/lib/jsduck/doc_ast.rb +0 -319
  156. data/lib/jsduck/doc_formatter.rb +0 -142
  157. data/lib/jsduck/doc_parser.rb +0 -611
  158. data/lib/jsduck/doc_type.rb +0 -59
  159. data/lib/jsduck/enum.rb +0 -73
  160. data/lib/jsduck/esprima.rb +0 -51
  161. data/lib/jsduck/evaluator.rb +0 -69
  162. data/lib/jsduck/ext_patterns.rb +0 -58
  163. data/lib/jsduck/file_categories.rb +0 -76
  164. data/lib/jsduck/function_ast.rb +0 -206
  165. data/lib/jsduck/guide_anchors.rb +0 -32
  166. data/lib/jsduck/guide_toc.rb +0 -49
  167. data/lib/jsduck/html_stack.rb +0 -105
  168. data/lib/jsduck/importer.rb +0 -121
  169. data/lib/jsduck/inherit_doc.rb +0 -193
  170. data/lib/jsduck/js_parser.rb +0 -221
  171. data/lib/jsduck/lint.rb +0 -133
  172. data/lib/jsduck/meta_tag.rb +0 -88
  173. data/lib/jsduck/meta_tag_loader.rb +0 -67
  174. data/lib/jsduck/meta_tag_registry.rb +0 -111
  175. data/lib/jsduck/meta_tag_renderer.rb +0 -34
  176. data/lib/jsduck/news.rb +0 -128
  177. data/lib/jsduck/override.rb +0 -87
  178. data/lib/jsduck/renderer.rb +0 -361
  179. data/lib/jsduck/return_values.rb +0 -72
  180. data/lib/jsduck/serializer.rb +0 -262
  181. data/lib/jsduck/shortener.rb +0 -58
  182. data/lib/jsduck/signature_renderer.rb +0 -91
  183. data/lib/jsduck/source/file_parser.rb +0 -72
@@ -0,0 +1,39 @@
1
+ require 'v8'
2
+ require 'jsduck/util/json'
3
+ require 'jsduck/util/singleton'
4
+
5
+ module JsDuck
6
+ module Js
7
+
8
+ # Runs Esprima.js through V8.
9
+ #
10
+ # Initialized as singleton to avoid loading the esprima.js more
11
+ # than once - otherwise performace will severely suffer.
12
+ class Esprima
13
+ include Util::Singleton
14
+
15
+ def initialize
16
+ @v8 = V8::Context.new
17
+ esprima = File.dirname(File.expand_path(__FILE__))+"/esprima/esprima.js";
18
+
19
+ # Esprima attempts to assign to window.esprima, but our v8
20
+ # engine has no global window variable defined. So define our
21
+ # own and then grab esprima out from it again.
22
+ @v8.eval("var window = {};")
23
+ @v8.load(esprima)
24
+ @v8.eval("var esprima = window.esprima;")
25
+ end
26
+
27
+ # Parses JavaScript source code using Esprima.js
28
+ #
29
+ # Returns the resulting AST
30
+ def parse(input)
31
+ @v8['js'] = input
32
+ json = @v8.eval("JSON.stringify(esprima.parse(js, {comment: true, range: true, raw: true}))")
33
+ return Util::Json.parse(json, :max_nesting => false)
34
+ end
35
+
36
+ end
37
+
38
+ end
39
+ end
File without changes
@@ -0,0 +1,70 @@
1
+ module JsDuck
2
+ module Js
3
+
4
+ # Evaluates Esprima AST node into Ruby object
5
+ class Evaluator
6
+
7
+ # Converts AST node into a value.
8
+ #
9
+ # - String literals become Ruby strings
10
+ # - Number literals become Ruby numbers
11
+ # - Regex literals become :regexp symbols
12
+ # - Array expressions become Ruby arrays
13
+ # - etc
14
+ #
15
+ # For anything it doesn't know how to evaluate (like a function
16
+ # expression) it throws exception.
17
+ #
18
+ def to_value(ast)
19
+ case ast["type"]
20
+ when "ArrayExpression"
21
+ ast["elements"].map {|e| to_value(e) }
22
+ when "ObjectExpression"
23
+ h = {}
24
+ ast["properties"].each do |p|
25
+ key = key_value(p["key"])
26
+ value = to_value(p["value"])
27
+ h[key] = value
28
+ end
29
+ h
30
+ when "BinaryExpression"
31
+ if ast["operator"] == "+"
32
+ to_value(ast["left"]) + to_value(ast["right"])
33
+ else
34
+ throw "Unable to handle operator: " + ast["operator"]
35
+ end
36
+ when "MemberExpression"
37
+ if base_css_prefix?(ast)
38
+ "x-"
39
+ else
40
+ throw "Unable to handle this MemberExpression"
41
+ end
42
+ when "Literal"
43
+ if ast["raw"] =~ /\A\//
44
+ :regexp
45
+ else
46
+ ast["value"]
47
+ end
48
+ else
49
+ throw "Unknown node type: " + ast["type"]
50
+ end
51
+ end
52
+
53
+ # Turns object property key into string value
54
+ def key_value(key)
55
+ key["type"] == "Identifier" ? key["name"] : key["value"]
56
+ end
57
+
58
+ # True when MemberExpression == Ext.baseCSSPrefix
59
+ def base_css_prefix?(ast)
60
+ ast["computed"] == false &&
61
+ ast["object"]["type"] == "Identifier" &&
62
+ ast["object"]["name"] == "Ext" &&
63
+ ast["property"]["type"] == "Identifier" &&
64
+ ast["property"]["name"] == "baseCSSPrefix"
65
+ end
66
+
67
+ end
68
+
69
+ end
70
+ end
@@ -0,0 +1,70 @@
1
+ require "jsduck/util/singleton"
2
+
3
+ module JsDuck
4
+ module Js
5
+
6
+ # Identifies Ext JS builtins like Ext.define and Ext.extend, taking
7
+ # also into account the possibility of aliasing the Ext namespace.
8
+ #
9
+ # For example when the following command line option is used:
10
+ #
11
+ # --ext-namespaces=Ext,MyApp
12
+ #
13
+ # we need to identify both Ext.define and MyApp.define, but
14
+ # Ext.define is additionally aliased withing ExtJS as
15
+ # Ext.ClassManager.create, so we also need to recognize
16
+ # Ext.ClassManager.create and MyApp.ClassManager.create.
17
+ #
18
+ # The matches? method will take care of identifying all these four
19
+ # cases:
20
+ #
21
+ # ExtPatterns.set(["Ext", "MyApp"])
22
+ # ExtPatterns.matches?("Ext.define", "MyApp.define") --> true
23
+ #
24
+ class ExtPatterns
25
+ include Util::Singleton
26
+
27
+ def initialize
28
+ set(["Ext"])
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
+ # Reconfigures ExtPatterns with different set of namespaces.
40
+ # Called when --ext-namespaces option is passed to JSDuck.
41
+ def set(namespaces)
42
+ @patterns = {
43
+ "Ext.define" => build_patterns(namespaces, [".define", ".ClassManager.create"]),
44
+ "Ext.extend" => build_patterns(namespaces, [".extend"]),
45
+ "Ext.override" => build_patterns(namespaces, [".override"]),
46
+ "Ext.emptyFn" => build_patterns(namespaces, [".emptyFn"]),
47
+ }
48
+ end
49
+
50
+ private
51
+
52
+ # Given Array of alternate Ext namespaces builds list of patterns
53
+ # for detecting Ext.define or some other construct:
54
+ #
55
+ # build_patterns(["Ext", "Foo"], [".define"]) --> ["Ext.define", "Foo.define"]
56
+ #
57
+ def build_patterns(namespaces, suffixes)
58
+ patterns = []
59
+ namespaces.each do |ns|
60
+ suffixes.each do |suffix|
61
+ patterns << ns + suffix
62
+ end
63
+ end
64
+ patterns
65
+ end
66
+
67
+ end
68
+
69
+ end
70
+ end
@@ -0,0 +1,206 @@
1
+ require "jsduck/util/singleton"
2
+
3
+ module JsDuck
4
+ module Js
5
+
6
+ # Analyzes the AST of a FunctionDeclaration or FunctionExpression.
7
+ class Function
8
+ include Util::Singleton
9
+
10
+ # Detects possible return types of the given function.
11
+ #
12
+ # For now there are three possible detected return values:
13
+ #
14
+ # * :this - the code contins 'return this;'
15
+ #
16
+ # * "undefined" - the code finishes by returning undefined or
17
+ # without explicitly returning anything
18
+ #
19
+ # * :other - some other value is returned.
20
+ #
21
+ def return_types(ast)
22
+ h = return_types_hash(ast["body"]["body"])
23
+
24
+ # Replace the special :void value that signifies possibility of
25
+ # exiting without explicitly returning anything
26
+ if h[:void]
27
+ h["undefined"] = true
28
+ h.delete(:void)
29
+ end
30
+
31
+ h.keys
32
+ end
33
+
34
+ private
35
+
36
+ def return_types_hash(body)
37
+ rvalues = {}
38
+ body.each do |ast|
39
+ if return?(ast)
40
+ type = value_type(ast["argument"])
41
+ rvalues[type] = true
42
+ return rvalues
43
+ elsif possibly_blocking?(ast)
44
+ extract_bodies(ast).each do |b|
45
+ rvalues.merge!(return_types_hash(b))
46
+ end
47
+ if !rvalues[:void]
48
+ return rvalues
49
+ else
50
+ rvalues.delete(:void)
51
+ end
52
+ elsif control_flow?(ast)
53
+ extract_bodies(ast).each do |b|
54
+ rvalues.merge!(return_types_hash(b))
55
+ end
56
+ rvalues.delete(:void)
57
+ end
58
+ end
59
+
60
+ rvalues[:void] = true
61
+ return rvalues
62
+ end
63
+
64
+ def return?(ast)
65
+ ast["type"] == "ReturnStatement"
66
+ end
67
+
68
+ def value_type(ast)
69
+ if !ast
70
+ :void
71
+ elsif undefined?(ast) || void?(ast)
72
+ "undefined"
73
+ elsif this?(ast)
74
+ :this
75
+ elsif boolean?(ast)
76
+ "Boolean"
77
+ elsif string?(ast)
78
+ "String"
79
+ elsif regexp?(ast)
80
+ "RegExp"
81
+ else
82
+ :other
83
+ end
84
+ end
85
+
86
+ def undefined?(ast)
87
+ ast["type"] == "Identifier" && ast["name"] == "undefined"
88
+ end
89
+
90
+ def void?(ast)
91
+ ast["type"] == "UnaryExpression" && ast["operator"] == "void"
92
+ end
93
+
94
+ def this?(ast)
95
+ ast["type"] == "ThisExpression"
96
+ end
97
+
98
+ def boolean?(ast)
99
+ if boolean_literal?(ast)
100
+ true
101
+ elsif ast["type"] == "UnaryExpression" || ast["type"] == "BinaryExpression"
102
+ !!BOOLEAN_RETURNING_OPERATORS[ast["operator"]]
103
+ elsif ast["type"] == "LogicalExpression"
104
+ boolean?(ast["left"]) && boolean?(ast["right"])
105
+ elsif ast["type"] == "ConditionalExpression"
106
+ boolean?(ast["consequent"]) && boolean?(ast["alternate"])
107
+ elsif ast["type"] == "AssignmentExpression" && ast["operator"] == "="
108
+ boolean?(ast["right"])
109
+ else
110
+ false
111
+ end
112
+ end
113
+
114
+ def boolean_literal?(ast)
115
+ ast["type"] == "Literal" && (ast["value"] == true || ast["value"] == false)
116
+ end
117
+
118
+ def string?(ast)
119
+ if string_literal?(ast)
120
+ true
121
+ elsif ast["type"] == "BinaryExpression" && ast["operator"] == "+"
122
+ string?(ast["left"]) || string?(ast["right"])
123
+ elsif ast["type"] == "UnaryExpression" && ast["operator"] == "typeof"
124
+ true
125
+ else
126
+ false
127
+ end
128
+ end
129
+
130
+ def string_literal?(ast)
131
+ ast["type"] == "Literal" && ast["value"].is_a?(String)
132
+ end
133
+
134
+ def regexp?(ast)
135
+ ast["type"] == "Literal" && ast["raw"] =~ /^\//
136
+ end
137
+
138
+ def control_flow?(ast)
139
+ CONTROL_FLOW[ast["type"]]
140
+ end
141
+
142
+ def extract_bodies(ast)
143
+ body = []
144
+ CONTROL_FLOW[ast["type"]].each do |name|
145
+ statements = ast[name]
146
+ if statements.is_a?(Hash)
147
+ body << [statements]
148
+ else
149
+ body << Array(statements)
150
+ end
151
+ end
152
+ body
153
+ end
154
+
155
+ # True if the node is a control structure which will block further
156
+ # program flow when all its branches finish with a return
157
+ # statement.
158
+ def possibly_blocking?(ast)
159
+ if POSSIBLY_BLOCKING[ast["type"]]
160
+ CONTROL_FLOW[ast["type"]].all? {|key| ast[key] }
161
+ else
162
+ false
163
+ end
164
+ end
165
+
166
+ BOOLEAN_RETURNING_OPERATORS = {
167
+ "!" => true,
168
+ ">" => true,
169
+ ">=" => true,
170
+ "<" => true,
171
+ "<=" => true,
172
+ "==" => true,
173
+ "!=" => true,
174
+ "===" => true,
175
+ "!==" => true,
176
+ "in" => true,
177
+ "instanceof" => true,
178
+ "delete" => true,
179
+ }
180
+
181
+ POSSIBLY_BLOCKING = {
182
+ "IfStatement" => true,
183
+ "DoWhileStatement" => true,
184
+ "WithStatement" => true,
185
+ "LabeledStatement" => true,
186
+ "BlockStatement" => true,
187
+ }
188
+
189
+ CONTROL_FLOW = {
190
+ "IfStatement" => ["consequent", "alternate"],
191
+ "SwitchStatement" => ["cases"],
192
+ "SwitchCase" => ["consequent"],
193
+ "ForStatement" => ["body"],
194
+ "ForInStatement" => ["body"],
195
+ "WhileStatement" => ["body"],
196
+ "DoWhileStatement" => ["body"],
197
+ "TryStatement" => ["block", "handlers", "finalizer"],
198
+ "CatchClause" => ["body"],
199
+ "WithStatement" => ["body"],
200
+ "LabeledStatement" => ["body"],
201
+ "BlockStatement" => ["body"],
202
+ }
203
+ end
204
+
205
+ end
206
+ end
@@ -0,0 +1,194 @@
1
+ require "jsduck/js/serializer"
2
+ require "jsduck/js/evaluator"
3
+ require "jsduck/js/ext_patterns"
4
+ require "jsduck/js/node_array"
5
+
6
+ module JsDuck
7
+ module Js
8
+
9
+ # Wraps around AST node returned from Esprima, providing methods for
10
+ # investigating it.
11
+ class Node
12
+ # Factor method that creates either Node or NodeArray.
13
+ def self.create(node)
14
+ if node.is_a? Array
15
+ Js::NodeArray.new(node)
16
+ else
17
+ Js::Node.new(node)
18
+ end
19
+ end
20
+
21
+ # Initialized with a AST Hash from Esprima.
22
+ def initialize(node)
23
+ @node = node || {}
24
+ end
25
+
26
+ # Returns a child AST node as Node class.
27
+ def child(name)
28
+ Js::Node.create(@node[name])
29
+ end
30
+ # Shorthand for #child method
31
+ def [](name)
32
+ child(name)
33
+ end
34
+
35
+ # Returns the raw Exprima AST node this class wraps.
36
+ def raw
37
+ @node
38
+ end
39
+
40
+ # Serializes the node into string
41
+ def to_s
42
+ begin
43
+ Js::Serializer.new.to_s(@node)
44
+ rescue
45
+ nil
46
+ end
47
+ end
48
+
49
+ # Evaluates the node into basic JavaScript value.
50
+ def to_value
51
+ begin
52
+ Js::Evaluator.new.to_value(@node)
53
+ rescue
54
+ nil
55
+ end
56
+ end
57
+
58
+ # Converts object expression property key to string value
59
+ def key_value
60
+ Js::Evaluator.new.key_value(@node)
61
+ end
62
+
63
+ # Returns the type of node value.
64
+ def value_type
65
+ v = to_value
66
+ if v.is_a?(String)
67
+ "String"
68
+ elsif v.is_a?(Numeric)
69
+ "Number"
70
+ elsif v.is_a?(TrueClass) || v.is_a?(FalseClass)
71
+ "Boolean"
72
+ elsif v.is_a?(Array)
73
+ "Array"
74
+ elsif v.is_a?(Hash)
75
+ "Object"
76
+ elsif v == :regexp
77
+ "RegExp"
78
+ else
79
+ nil
80
+ end
81
+ end
82
+
83
+ # Iterates over keys and values in ObjectExpression. The keys
84
+ # are turned into strings, but values are left as is for further
85
+ # processing.
86
+ def each_property
87
+ return unless object_expression?
88
+
89
+ child("properties").each do |ast|
90
+ yield(ast["key"].key_value, ast["value"], ast)
91
+ end
92
+ end
93
+
94
+ # Returns line number in parsed source where the Node resides.
95
+ def linenr
96
+ # Get line number from third place at range array.
97
+ # This third item exists in forked EsprimaJS at
98
+ # https://github.com/nene/esprima/tree/linenr-in-range
99
+ @node["range"][2]
100
+ end
101
+
102
+ # Tests for higher level types which don't correspond directly to
103
+ # Esprima AST types.
104
+
105
+ def function?
106
+ function_declaration? || function_expression? || ext_empty_fn?
107
+ end
108
+
109
+ def fire_event?
110
+ call_expression? && child("callee").to_s == "this.fireEvent"
111
+ end
112
+
113
+ def string?
114
+ literal? && @node["value"].is_a?(String)
115
+ end
116
+
117
+ # Checks dependent on Ext namespace,
118
+ # which may not always be "Ext" but also something user-defined.
119
+
120
+ def ext_empty_fn?
121
+ member_expression? && ext_pattern?("Ext.emptyFn")
122
+ end
123
+
124
+ def ext_define?
125
+ call_expression? && child("callee").ext_pattern?("Ext.define")
126
+ end
127
+
128
+ def ext_extend?
129
+ call_expression? && child("callee").ext_pattern?("Ext.extend")
130
+ end
131
+
132
+ def ext_override?
133
+ call_expression? && child("callee").ext_pattern?("Ext.override")
134
+ end
135
+
136
+ def ext_pattern?(pattern)
137
+ Js::ExtPatterns.matches?(pattern, to_s)
138
+ end
139
+
140
+ # Simple shorthands for testing the type of node
141
+ # These have one-to-one mapping to Esprima node types.
142
+
143
+ def call_expression?
144
+ @node["type"] == "CallExpression"
145
+ end
146
+
147
+ def assignment_expression?
148
+ @node["type"] == "AssignmentExpression"
149
+ end
150
+
151
+ def object_expression?
152
+ @node["type"] == "ObjectExpression"
153
+ end
154
+
155
+ def array_expression?
156
+ @node["type"] == "ArrayExpression"
157
+ end
158
+
159
+ def function_expression?
160
+ @node["type"] == "FunctionExpression"
161
+ end
162
+
163
+ def member_expression?
164
+ @node["type"] == "MemberExpression"
165
+ end
166
+
167
+ def expression_statement?
168
+ @node["type"] == "ExpressionStatement"
169
+ end
170
+
171
+ def variable_declaration?
172
+ @node["type"] == "VariableDeclaration"
173
+ end
174
+
175
+ def function_declaration?
176
+ @node["type"] == "FunctionDeclaration"
177
+ end
178
+
179
+ def property?
180
+ @node["type"] == "Property"
181
+ end
182
+
183
+ def identifier?
184
+ @node["type"] == "Identifier"
185
+ end
186
+
187
+ def literal?
188
+ @node["type"] == "Literal"
189
+ end
190
+
191
+ end
192
+
193
+ end
194
+ end