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
@@ -1,142 +0,0 @@
1
- require 'strscan'
2
- require 'rdiscount'
3
- require 'jsduck/html_stack'
4
- require 'jsduck/inline/link'
5
- require 'jsduck/inline/auto_link'
6
- require 'jsduck/inline/link_renderer'
7
- require 'jsduck/inline/img'
8
- require 'jsduck/inline/video'
9
- require 'jsduck/inline/example'
10
-
11
- module JsDuck
12
-
13
- # Formats doc-comments
14
- class DocFormatter
15
-
16
- # Creates a formatter configured with options originating from
17
- # command line. For the actual effect of the options see
18
- # Inline::* classes.
19
- def initialize(relations={}, opts={})
20
- @opts = opts
21
- @link_renderer = Inline::LinkRenderer.new(relations, opts)
22
- @inline_link = Inline::Link.new(@link_renderer)
23
- @auto_link = Inline::AutoLink.new(@link_renderer)
24
- @inline_img = Inline::Img.new(opts)
25
- @inline_video = Inline::Video.new(opts)
26
- @inline_example = Inline::Example.new(opts)
27
- @doc_context = {}
28
- end
29
-
30
- # Accessors to the images attribute of Inline::Img
31
- def images=(images)
32
- @inline_img.images = images
33
- end
34
- def images
35
- @inline_img.images
36
- end
37
-
38
- # Sets up instance to work in context of particular class, so
39
- # that when {@link #blah} is encountered it knows that
40
- # Context#blah is meant.
41
- def class_context=(cls)
42
- @inline_link.class_context = cls
43
- @auto_link.class_context = cls
44
- end
45
-
46
- # Sets up instance to work in context of particular doc object.
47
- # Used for error reporting.
48
- def doc_context=(doc)
49
- @doc_context = doc
50
- @inline_video.doc_context = doc
51
- @inline_link.doc_context = doc
52
- @auto_link.doc_context = doc
53
- @inline_img.doc_context = doc
54
- end
55
-
56
- # Returns the current documentation context
57
- def doc_context
58
- @doc_context
59
- end
60
-
61
- # Formats doc-comment for placement into HTML.
62
- # Renders it with Markdown-formatter and replaces @link-s.
63
- def format(input)
64
- # In ExtJS source "<pre>" is often at the end of paragraph, not
65
- # on its own line. But in that case RDiscount doesn't recognize
66
- # it as the beginning of <pre>-block and goes on parsing it as
67
- # normal Markdown, which often causes nested <pre>-blocks.
68
- #
69
- # To prevent this, we always add extra newline before <pre>.
70
- input.gsub!(/([^\n])<pre>((<code>)?$)/, "\\1\n<pre>\\2")
71
-
72
- # But we remove trailing newline after <pre> to prevent
73
- # code-blocks beginning with empty line.
74
- input.gsub!(/<pre>(<code>)?\n?/, "<pre>\\1")
75
-
76
- replace(RDiscount.new(input).to_html)
77
- end
78
-
79
- # Replaces {@link} and {@img} tags, auto-generates links for
80
- # recognized classnames.
81
- #
82
- # Replaces {@link Class#member link text} in given string with
83
- # HTML from @link_tpl.
84
- #
85
- # Replaces {@img path/to/image.jpg Alt text} with HTML from @img_tpl.
86
- #
87
- # Adds 'inline-example' class to code examples beginning with @example.
88
- #
89
- # Additionally replaces strings recognized as ClassNames or
90
- # #members with links to these classes or members. So one doesn't
91
- # even need to use the @link tag to create a link.
92
- def replace(input)
93
- s = StringScanner.new(input)
94
- out = ""
95
-
96
- # Keep track of open HTML tags. We're not auto-detecting class
97
- # names when inside <a>. Also we want to close down the unclosed
98
- # tags.
99
- tags = HtmlStack.new(@opts[:ignore_html] || {}, @doc_context)
100
-
101
- while !s.eos? do
102
- if substitute = @inline_link.replace(s)
103
- out += substitute
104
- elsif substitute = @inline_img.replace(s)
105
- out += substitute
106
- elsif substitute = @inline_video.replace(s)
107
- out += substitute
108
- elsif s.check(/[{]/)
109
- # There might still be "{" that doesn't begin {@link} or {@img} - ignore it
110
- out += s.scan(/[{]/)
111
- elsif substitute = @inline_example.replace(s)
112
- tags.push_tag("pre")
113
- tags.push_tag("code")
114
- out += substitute
115
- elsif s.check(/<\w/)
116
- # Open HTML tag
117
- out += tags.open(s)
118
- elsif s.check(/<\/\w+>/)
119
- # Close HTML tag
120
- out += tags.close(s)
121
- elsif s.check(/</)
122
- # Ignore plain '<' char.
123
- out += s.scan(/</)
124
- else
125
- # Replace class names in the following text up to next "<" or "{"
126
- # but only when we're not inside <a>...</a>
127
- text = s.scan(/[^{<]+/)
128
- out += tags.open?("a") ? text : @auto_link.replace(text)
129
- end
130
- end
131
-
132
- out
133
- end
134
-
135
- # Creates a link based on the link template.
136
- def link(cls, member, anchor_text, type=nil, static=nil)
137
- @link_renderer.link(cls, member, anchor_text, type, static)
138
- end
139
-
140
- end
141
-
142
- end
@@ -1,611 +0,0 @@
1
- require 'strscan'
2
- require 'jsduck/meta_tag_registry'
3
- require 'jsduck/logger'
4
-
5
- module JsDuck
6
-
7
- # Parses doc-comment into array of @tags
8
- #
9
- # For each @tag it produces Hash like the following:
10
- #
11
- # {
12
- # :tagname => :cfg/:property/:type/:extends/...,
13
- # :doc => "Some documentation for this tag",
14
- # ...@tag specific stuff like :name, :type, and so on...
15
- # }
16
- #
17
- # When doc-comment begins with comment, not preceded by @tag, then
18
- # the comment will be placed into Hash with :tagname => :default.
19
- #
20
- # Unrecognized @tags are left as is into documentation as if they
21
- # were normal text.
22
- #
23
- # @see and {@link} are parsed separately in JsDuck::DocFormatter.
24
- #
25
- class DocParser
26
- def initialize
27
- @ident_pattern = /[$\w-]+/
28
- @ident_chain_pattern = /[$\w-]+(\.[$\w-]+)*/
29
- @meta_tags = MetaTagRegistry.instance
30
- end
31
-
32
- def parse(input, filename="", linenr=0)
33
- @filename = filename
34
- @linenr = linenr
35
- @tags = []
36
- @input = StringScanner.new(purify(input))
37
- parse_loop
38
- # The parsing process can leave whitespace at the ends of
39
- # doc-strings, here we get rid of it. Additionally null all empty docs
40
- @tags.each do |tag|
41
- tag[:doc].strip!
42
- tag[:doc] = nil if tag[:doc] == ""
43
- end
44
- # Get rid of empty default tag
45
- if @tags.first && @tags.first[:tagname] == :default && !@tags.first[:doc]
46
- @tags.shift
47
- end
48
- @tags
49
- end
50
-
51
- # Extracts content inside /** ... */
52
- def purify(input)
53
- result = []
54
- # We can have two types of lines:
55
- # - those beginning with *
56
- # - and those without it
57
- indent = nil
58
- input.each_line do |line|
59
- line.chomp!
60
- if line =~ /\A\s*\*\s?(.*)\Z/
61
- # When comment contains *-lines, switch indent-trimming off
62
- indent = 0
63
- result << $1
64
- elsif line =~ /\A\s*\Z/
65
- # pass-through empty lines
66
- result << line
67
- elsif indent == nil && line =~ /\A(\s*)(.*?\Z)/
68
- # When indent not measured, measure it and remember
69
- indent = $1.length
70
- result << $2
71
- else
72
- # Trim away indent if available
73
- result << line.sub(/\A\s{0,#{indent||0}}/, "")
74
- end
75
- end
76
- return result.join("\n")
77
- end
78
-
79
- def add_tag(tag)
80
- @tags << @current_tag = {:tagname => tag, :doc => ""}
81
- end
82
-
83
- def remove_last_tag
84
- @tags.pop
85
- @current_tag = @tags.last
86
- end
87
-
88
- def parse_loop
89
- add_tag(:default)
90
- while !@input.eos? do
91
- if look(/@class\b/)
92
- at_class
93
- elsif look(/@extends?\b/)
94
- at_extends
95
- elsif look(/@mixins?\b/)
96
- class_list_at_tag(/@mixins?/, :mixins)
97
- elsif look(/@alternateClassNames?\b/)
98
- class_list_at_tag(/@alternateClassNames?/, :alternateClassNames)
99
- elsif look(/@uses\b/)
100
- class_list_at_tag(/@uses/, :uses)
101
- elsif look(/@requires\b/)
102
- class_list_at_tag(/@requires/, :requires)
103
- elsif look(/@singleton\b/)
104
- boolean_at_tag(/@singleton/, :singleton)
105
- elsif look(/@event\b/)
106
- at_event
107
- elsif look(/@method\b/)
108
- at_method
109
- elsif look(/@constructor\b/)
110
- boolean_at_tag(/@constructor/, :constructor)
111
- elsif look(/@param\b/)
112
- at_param
113
- elsif look(/@returns?\b/)
114
- at_return
115
- elsif look(/@cfg\b/)
116
- at_cfg
117
- elsif look(/@property\b/)
118
- at_property
119
- elsif look(/@type\b/)
120
- at_type
121
- elsif look(/@xtype\b/)
122
- at_xtype(/@xtype/, "widget")
123
- elsif look(/@ftype\b/)
124
- at_xtype(/@ftype/, "feature")
125
- elsif look(/@ptype\b/)
126
- at_xtype(/@ptype/, "plugin")
127
- elsif look(/@member\b/)
128
- at_member
129
- elsif look(/@inherit[dD]oc\b/)
130
- at_inheritdoc
131
- elsif look(/@alias\s+([\w.]+)?#\w+/)
132
- # For backwards compatibility.
133
- # @alias tag was used as @inheritdoc before
134
- at_inheritdoc
135
- elsif look(/@alias/)
136
- at_alias
137
- elsif look(/@var\b/)
138
- at_var
139
- elsif look(/@throws\b/)
140
- at_throws
141
- elsif look(/@enum\b/)
142
- at_enum
143
- elsif look(/@override\b/)
144
- at_override
145
- elsif look(/@inheritable\b/)
146
- boolean_at_tag(/@inheritable/, :inheritable)
147
- elsif look(/@accessor\b/)
148
- boolean_at_tag(/@accessor/, :accessor)
149
- elsif look(/@evented\b/)
150
- boolean_at_tag(/@evented/, :evented)
151
- elsif look(/@/)
152
- other_at_tag
153
- elsif look(/[^@]/)
154
- skip_to_next_at_tag
155
- end
156
- end
157
- end
158
-
159
- # Skips until the beginning of next @tag.
160
- #
161
- # There must be space before the next @tag - this ensures that we
162
- # don't detect tags inside "foo@example.com" or "{@link}".
163
- #
164
- # Also check that the @tag is not part of an indented code block -
165
- # in which case we also ignore the tag.
166
- def skip_to_next_at_tag
167
- @current_tag[:doc] += match(/[^@]+/)
168
-
169
- while look(/@/) && (!prev_char_is_whitespace? || indented_as_code?)
170
- @current_tag[:doc] += match(/@+[^@]+/)
171
- end
172
- end
173
-
174
- def prev_char_is_whitespace?
175
- @current_tag[:doc][-1,1] =~ /\s/
176
- end
177
-
178
- def indented_as_code?
179
- @current_tag[:doc] =~ /^ {4,}[^\n]*\z/
180
- end
181
-
182
- # Processes anything else beginning with @-sign.
183
- #
184
- # - When @ is not followed by any word chards, do nothing.
185
- # - When it's one of the meta-tags, process it as such.
186
- # - When it's something else, print a warning.
187
- #
188
- def other_at_tag
189
- match(/@/)
190
-
191
- name = look(/\w+/)
192
- tag = @meta_tags[name]
193
-
194
- if tag
195
- meta_at_tag(tag)
196
- elsif name
197
- Logger.warn(:tag, "Unsupported tag: @#{name}", @filename, @linenr)
198
- @current_tag[:doc] += "@"
199
- end
200
- end
201
-
202
- # Matches the given meta-tag
203
- def meta_at_tag(tag)
204
- prev_tag = @current_tag
205
-
206
- add_tag(:meta)
207
- @current_tag[:name] = tag.key
208
- match(/\w+/)
209
- skip_horiz_white
210
-
211
- if tag.boolean
212
- # For boolean tags, only scan the tag name and switch context
213
- # back to previous tag.
214
- skip_white
215
- @current_tag = prev_tag
216
- elsif tag.multiline
217
- # For multiline tags we leave the tag open for :doc addition
218
- # just like with built-in multiline tags.
219
- else
220
- # Fors singleline tags, scan to the end of line and finish the
221
- # tag.
222
- @current_tag[:doc] = match(/.*$/).strip
223
- skip_white
224
- @current_tag = prev_tag
225
- end
226
- end
227
-
228
- # matches @class name ...
229
- def at_class
230
- match(/@class/)
231
- add_tag(:class)
232
- maybe_ident_chain(:name)
233
- skip_white
234
- end
235
-
236
- # matches @extends name ...
237
- def at_extends
238
- match(/@extends?/)
239
- add_tag(:extends)
240
- maybe_ident_chain(:extends)
241
- skip_white
242
- end
243
-
244
- # matches @<tagname> classname1 classname2 ...
245
- def class_list_at_tag(regex, tagname)
246
- match(regex)
247
- add_tag(tagname)
248
- skip_horiz_white
249
- @current_tag[tagname] = class_list
250
- skip_white
251
- end
252
-
253
- # matches @event name ...
254
- def at_event
255
- match(/@event/)
256
- add_tag(:event)
257
- maybe_name
258
- skip_white
259
- end
260
-
261
- # matches @method name ...
262
- def at_method
263
- match(/@method/)
264
- add_tag(:method)
265
- maybe_name
266
- skip_white
267
- end
268
-
269
- # matches @param {type} [name] (optional) ...
270
- def at_param
271
- match(/@param/)
272
- add_tag(:param)
273
- maybe_type
274
- maybe_name_with_default
275
- maybe_optional
276
- skip_white
277
- end
278
-
279
- # matches @return {type} [ return.name ] ...
280
- def at_return
281
- match(/@returns?/)
282
- add_tag(:return)
283
- maybe_type
284
- skip_white
285
- if look(/return\.\w/)
286
- @current_tag[:name] = ident_chain
287
- else
288
- @current_tag[:name] = "return"
289
- end
290
- skip_white
291
- end
292
-
293
- # matches @cfg {type} name ...
294
- def at_cfg
295
- match(/@cfg/)
296
- add_tag(:cfg)
297
- maybe_type
298
- maybe_name_with_default
299
- maybe_required
300
- skip_white
301
- end
302
-
303
- # matches @property {type} name ...
304
- #
305
- # ext-doc doesn't support {type} and name for @property - name is
306
- # inferred from source and @type is required to specify type,
307
- # jsdoc-toolkit on the other hand follows the sensible route, and
308
- # so do we.
309
- def at_property
310
- match(/@property/)
311
- add_tag(:property)
312
- maybe_type
313
- maybe_name_with_default
314
- skip_white
315
- end
316
-
317
- # matches @var {type} $name ...
318
- def at_var
319
- match(/@var/)
320
- add_tag(:css_var)
321
- maybe_type
322
- maybe_name_with_default
323
- skip_white
324
- end
325
-
326
- # matches @throws {type} ...
327
- def at_throws
328
- match(/@throws/)
329
- add_tag(:throws)
330
- maybe_type
331
- skip_white
332
- end
333
-
334
- # matches @enum {type} name ...
335
- def at_enum
336
- match(/@enum/)
337
- add_tag(:class)
338
- @current_tag[:enum] = true
339
- maybe_type
340
- maybe_name_with_default
341
- skip_white
342
- end
343
-
344
- # matches @override name ...
345
- def at_override
346
- match(/@override/)
347
- add_tag(:override)
348
- maybe_ident_chain(:class)
349
- skip_white
350
-
351
- # When @override not followed by class name, ignore the tag.
352
- # That's because the current ext codebase has some methods
353
- # tagged with @override to denote they override something.
354
- # But that's not what @override is meant for in JSDuck.
355
- unless @current_tag[:class]
356
- remove_last_tag
357
- end
358
- end
359
-
360
- # matches @type {type} or @type type
361
- #
362
- # The presence of @type implies that we are dealing with property.
363
- # ext-doc allows type name to be either inside curly braces or
364
- # without them at all.
365
- def at_type
366
- match(/@type/)
367
- add_tag(:type)
368
- skip_horiz_white
369
- if look(/\{/)
370
- tdf = typedef
371
- @current_tag[:type] = tdf[:type]
372
- @current_tag[:optional] = true if tdf[:optional]
373
- elsif look(/\S/)
374
- @current_tag[:type] = match(/\S+/)
375
- end
376
- skip_white
377
- end
378
-
379
- # matches @member name ...
380
- def at_member
381
- match(/@member/)
382
- add_tag(:member)
383
- maybe_ident_chain(:member)
384
- skip_white
385
- end
386
-
387
- # matches @xtype/ptype/ftype/... name
388
- def at_xtype(tag, namespace)
389
- match(tag)
390
- add_tag(:alias)
391
- skip_horiz_white
392
- @current_tag[:name] = namespace + "." + (ident_chain || "")
393
- skip_white
394
- end
395
-
396
- # matches @alias <ident-chain>
397
- def at_alias
398
- match(/@alias/)
399
- add_tag(:alias)
400
- skip_horiz_white
401
- @current_tag[:name] = ident_chain
402
- skip_white
403
- end
404
-
405
- # matches @inheritdoc class.name#static-type-member
406
- def at_inheritdoc
407
- match(/@inherit[dD]oc|@alias/)
408
-
409
- add_tag(:inheritdoc)
410
- skip_horiz_white
411
-
412
- if look(@ident_chain_pattern)
413
- @current_tag[:cls] = ident_chain
414
- end
415
-
416
- if look(/#\w/)
417
- match(/#/)
418
- if look(/static-/)
419
- @current_tag[:static] = true
420
- match(/static-/)
421
- end
422
- if look(/(cfg|property|method|event|css_var|css_mixin)-/)
423
- @current_tag[:type] = ident.to_sym
424
- match(/-/)
425
- end
426
- @current_tag[:member] = ident
427
- end
428
-
429
- skip_white
430
- end
431
-
432
- # Used to match @private, @ignore, @hide, ...
433
- def boolean_at_tag(regex, propname)
434
- match(regex)
435
- add_tag(propname)
436
- skip_white
437
- end
438
-
439
- # matches {type} if possible and sets it on @current_tag
440
- # Also checks for {optionality=} in type definition.
441
- def maybe_type
442
- skip_horiz_white
443
- if look(/\{/)
444
- tdf = typedef
445
- @current_tag[:type] = tdf[:type]
446
- @current_tag[:optional] = true if tdf[:optional]
447
- end
448
- end
449
-
450
- # matches: <ident-chain> | "[" <ident-chain> [ "=" <default-value> ] "]"
451
- def maybe_name_with_default
452
- skip_horiz_white
453
- if look(/\[/)
454
- match(/\[/)
455
- maybe_ident_chain(:name)
456
- skip_horiz_white
457
- if look(/=/)
458
- match(/=/)
459
- skip_horiz_white
460
- @current_tag[:default] = default_value
461
- end
462
- skip_horiz_white
463
- match(/\]/)
464
- @current_tag[:optional] = true
465
- else
466
- maybe_ident_chain(:name)
467
- end
468
- end
469
-
470
- # matches: "(optional)"
471
- def maybe_optional
472
- skip_horiz_white
473
- if look(/\(optional\)/i)
474
- match(/\(optional\)/i)
475
- @current_tag[:optional] = true
476
- end
477
- end
478
-
479
- # matches: "(required)"
480
- def maybe_required
481
- skip_horiz_white
482
- if look(/\(required\)/i)
483
- match(/\(required\)/i)
484
- @current_tag[:optional] = false
485
- end
486
- end
487
-
488
- # matches identifier name if possible and sets it on @current_tag
489
- def maybe_name
490
- skip_horiz_white
491
- if look(@ident_pattern)
492
- @current_tag[:name] = match(@ident_pattern)
493
- end
494
- end
495
-
496
- # matches ident.chain if possible and sets it on @current_tag
497
- def maybe_ident_chain(propname)
498
- skip_horiz_white
499
- if look(@ident_chain_pattern)
500
- @current_tag[propname] = ident_chain
501
- end
502
- end
503
-
504
- # Attempts to allow balanced braces in default value.
505
- # When the nested parsing doesn't finish at closing "]",
506
- # roll back to beginning and simply grab anything up to closing "]".
507
- def default_value
508
- start_pos = @input.pos
509
- value = parse_balanced(/\[/, /\]/, /[^\[\]'"]*/)
510
- if look(/\]/)
511
- value
512
- else
513
- @input.pos = start_pos
514
- match(/[^\]]*/)
515
- end
516
- end
517
-
518
- # matches {...=} and returns text inside brackets
519
- def typedef
520
- match(/\{/)
521
-
522
- name = parse_balanced(/\{/, /\}/, /[^{}'"]*/)
523
-
524
- if name =~ /=$/
525
- name = name.chop
526
- optional = true
527
- else
528
- optional = nil
529
- end
530
-
531
- match(/\}/)
532
-
533
- return {:type => name, :optional => optional}
534
- end
535
-
536
- # Helper method to parse a string up to a closing brace,
537
- # balancing opening-closing braces in between.
538
- #
539
- # @param re_open The beginning brace regex
540
- # @param re_close The closing brace regex
541
- # @param re_rest Regex to match text without any braces and strings
542
- def parse_balanced(re_open, re_close, re_rest)
543
- result = parse_with_strings(re_rest)
544
- while look(re_open)
545
- result += match(re_open)
546
- result += parse_balanced(re_open, re_close, re_rest)
547
- result += match(re_close)
548
- result += parse_with_strings(re_rest)
549
- end
550
- result
551
- end
552
-
553
- # Helper for parse_balanced to parse rest of the text between
554
- # braces, taking account the strings which might occur there.
555
- def parse_with_strings(re_rest)
556
- result = match(re_rest)
557
- while look(/['"]/)
558
- result += parse_string('"') if look(/"/)
559
- result += parse_string("'") if look(/'/)
560
- result += match(re_rest)
561
- end
562
- result
563
- end
564
-
565
- # Parses "..." or '...' including the escape sequence \' or '\"
566
- def parse_string(quote)
567
- re_quote = Regexp.new(quote)
568
- re_rest = Regexp.new("(?:[^"+quote+"\\\\]|\\\\.)*")
569
- match(re_quote) + match(re_rest) + (match(re_quote) || "")
570
- end
571
-
572
- # matches <ident_chain> <ident_chain> ... until line end
573
- def class_list
574
- skip_horiz_white
575
- classes = []
576
- while look(@ident_chain_pattern)
577
- classes << ident_chain
578
- skip_horiz_white
579
- end
580
- classes
581
- end
582
-
583
- # matches chained.identifier.name and returns it
584
- def ident_chain
585
- @input.scan(@ident_chain_pattern)
586
- end
587
-
588
- # matches identifier and returns its name
589
- def ident
590
- @input.scan(/\w+/)
591
- end
592
-
593
- def look(re)
594
- @input.check(re)
595
- end
596
-
597
- def match(re)
598
- @input.scan(re)
599
- end
600
-
601
- def skip_white
602
- @input.scan(/\s+/)
603
- end
604
-
605
- # skips horizontal whitespace (tabs and spaces)
606
- def skip_horiz_white
607
- @input.scan(/[ \t]+/)
608
- end
609
- end
610
-
611
- end