jsduck 4.0.1 → 4.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +14 -0
- data/esprima/esprima.js +210 -85
- data/jsduck.gemspec +3 -3
- data/lib/jsduck/accessors.rb +10 -8
- data/lib/jsduck/aggregator.rb +7 -7
- data/lib/jsduck/app.rb +24 -164
- data/lib/jsduck/app_data.rb +2 -4
- data/lib/jsduck/assets.rb +5 -2
- data/lib/jsduck/ast.rb +9 -4
- data/lib/jsduck/batch_formatter.rb +54 -0
- data/lib/jsduck/batch_parser.rb +106 -0
- data/lib/jsduck/categories.rb +5 -6
- data/lib/jsduck/class.rb +77 -239
- data/lib/jsduck/class_doc_expander.rb +0 -5
- data/lib/jsduck/class_formatter.rb +14 -10
- data/lib/jsduck/class_name.rb +23 -0
- data/lib/jsduck/class_writer.rb +9 -8
- data/lib/jsduck/doc_ast.rb +5 -6
- data/lib/jsduck/doc_formatter.rb +61 -272
- data/lib/jsduck/enum.rb +4 -4
- data/lib/jsduck/esprima.rb +10 -4
- data/lib/jsduck/examples.rb +5 -5
- data/lib/jsduck/export_writer.rb +62 -0
- data/lib/jsduck/exporter/app.rb +62 -0
- data/lib/jsduck/exporter/examples.rb +58 -0
- data/lib/jsduck/exporter/full.rb +60 -0
- data/lib/jsduck/file_categories.rb +7 -4
- data/lib/jsduck/function_ast.rb +99 -0
- data/lib/jsduck/grouped_asset.rb +27 -16
- data/lib/jsduck/guide_writer.rb +8 -7
- data/lib/jsduck/guides.rb +31 -29
- data/lib/jsduck/icons.rb +12 -1
- data/lib/jsduck/images.rb +3 -3
- data/lib/jsduck/importer.rb +7 -7
- data/lib/jsduck/index_html.rb +20 -6
- data/lib/jsduck/inherit_doc.rb +9 -12
- data/lib/jsduck/inline/example.rb +42 -0
- data/lib/jsduck/inline/img.rb +55 -0
- data/lib/jsduck/inline/link.rb +227 -0
- data/lib/jsduck/inline/video.rb +67 -0
- data/lib/jsduck/inline_examples.rb +7 -7
- data/lib/jsduck/js_parser.rb +5 -4
- data/lib/jsduck/lint.rb +14 -2
- data/lib/jsduck/logger.rb +5 -6
- data/lib/jsduck/members_index.rb +132 -0
- data/lib/jsduck/merger.rb +3 -9
- data/lib/jsduck/options.rb +39 -41
- data/lib/jsduck/override.rb +3 -7
- data/lib/jsduck/relations.rb +9 -9
- data/lib/jsduck/renderer.rb +3 -3
- data/lib/jsduck/return_values.rb +72 -0
- data/lib/jsduck/search_data.rb +16 -20
- data/lib/jsduck/shortener.rb +58 -0
- data/lib/jsduck/signature_renderer.rb +1 -2
- data/lib/jsduck/source/file.rb +98 -0
- data/lib/jsduck/source/file_parser.rb +72 -0
- data/lib/jsduck/source/writer.rb +89 -0
- data/lib/jsduck/tag/aside.rb +1 -1
- data/lib/jsduck/tag/since.rb +1 -1
- data/lib/jsduck/template_dir.rb +2 -2
- data/lib/jsduck/util/html.rb +27 -0
- data/lib/jsduck/util/io.rb +32 -0
- data/lib/jsduck/util/json.rb +60 -0
- data/lib/jsduck/util/null_object.rb +23 -0
- data/lib/jsduck/util/os.rb +14 -0
- data/lib/jsduck/util/parallel.rb +34 -0
- data/lib/jsduck/util/singleton.rb +35 -0
- data/lib/jsduck/util/stdout.rb +33 -0
- data/lib/jsduck/videos.rb +5 -5
- data/lib/jsduck/web_writer.rb +79 -0
- data/lib/jsduck/welcome.rb +6 -6
- data/spec/class_factory.rb +20 -0
- metadata +32 -20
- data/lib/jsduck/api_exporter.rb +0 -48
- data/lib/jsduck/app_exporter.rb +0 -60
- data/lib/jsduck/examples_exporter.rb +0 -56
- data/lib/jsduck/full_exporter.rb +0 -35
- data/lib/jsduck/html.rb +0 -25
- data/lib/jsduck/inline_img.rb +0 -53
- data/lib/jsduck/inline_video.rb +0 -58
- data/lib/jsduck/io.rb +0 -30
- data/lib/jsduck/json_duck.rb +0 -52
- data/lib/jsduck/lexer.rb +0 -251
- data/lib/jsduck/null_object.rb +0 -19
- data/lib/jsduck/os.rb +0 -11
- data/lib/jsduck/parallel_wrap.rb +0 -32
- data/lib/jsduck/source_file.rb +0 -97
- data/lib/jsduck/source_file_parser.rb +0 -70
- data/lib/jsduck/source_writer.rb +0 -87
- data/lib/jsduck/stats.rb +0 -103
- data/lib/jsduck/stdout.rb +0 -31
@@ -0,0 +1,42 @@
|
|
1
|
+
module JsDuck
|
2
|
+
module Inline
|
3
|
+
|
4
|
+
# Implementation of @example tag.
|
5
|
+
#
|
6
|
+
# Looks for @example tag at the beginning of code blocks. When
|
7
|
+
# found, adds an "inline-example" CSS class to the <pre> element.
|
8
|
+
#
|
9
|
+
# Unlike other Inline:: classes this doesn't implement an
|
10
|
+
# {@example} tag as could be expected. But it fits nicely along
|
11
|
+
# with other inline tags as it's processed inside DocFormatter, so
|
12
|
+
# it mostly fits here along with the others.
|
13
|
+
#
|
14
|
+
class Example
|
15
|
+
# Constructor takes opts parameter for consistency with other
|
16
|
+
# JsDuck::Inline::* classes.
|
17
|
+
def initialize(opts={})
|
18
|
+
@re = /<pre><code>\s*@example( +[^\n]*)?\s+/m
|
19
|
+
end
|
20
|
+
|
21
|
+
# Takes StringScanner instance.
|
22
|
+
#
|
23
|
+
# Looks for "<pre><code>@example" at the current scan pointer
|
24
|
+
# position, when found, moves scan pointer forward and performs
|
25
|
+
# the apporpriate replacement.
|
26
|
+
def replace(input)
|
27
|
+
if input.check(@re)
|
28
|
+
# Match possible classnames following @example and add them
|
29
|
+
# as CSS classes inside <pre> element.
|
30
|
+
input.scan(@re) =~ @re
|
31
|
+
css_classes = ($1 || "").strip
|
32
|
+
|
33
|
+
return "<pre class='inline-example #{css_classes}'><code>"
|
34
|
+
else
|
35
|
+
false
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'jsduck/util/html'
|
2
|
+
require 'jsduck/logger'
|
3
|
+
|
4
|
+
module JsDuck
|
5
|
+
module Inline
|
6
|
+
|
7
|
+
# Implementation of inline tag {@img}
|
8
|
+
class Img
|
9
|
+
# Base path to prefix images from {@img} tags.
|
10
|
+
# Defaults to no prefix.
|
11
|
+
attr_accessor :base_path
|
12
|
+
|
13
|
+
# This will hold list of all image paths gathered from {@img} tags.
|
14
|
+
attr_accessor :images
|
15
|
+
|
16
|
+
def initialize(opts={})
|
17
|
+
@tpl = opts[:img_tpl] || '<img src="%u" alt="%a"/>'
|
18
|
+
|
19
|
+
@re = /\{@img\s+(\S*?)(?:\s+(.+?))?\}/m
|
20
|
+
|
21
|
+
@base_path = nil
|
22
|
+
@images = []
|
23
|
+
end
|
24
|
+
|
25
|
+
# Takes StringScanner instance.
|
26
|
+
#
|
27
|
+
# Looks for inline tag at the current scan pointer position, when
|
28
|
+
# found, moves scan pointer forward and performs the apporpriate
|
29
|
+
# replacement.
|
30
|
+
def replace(input)
|
31
|
+
if input.check(@re)
|
32
|
+
input.scan(@re).sub(@re) { apply_tpl($1, $2) }
|
33
|
+
else
|
34
|
+
false
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# applies the image template
|
39
|
+
def apply_tpl(url, alt_text)
|
40
|
+
@images << url
|
41
|
+
@tpl.gsub(/(%\w)/) do
|
42
|
+
case $1
|
43
|
+
when '%u'
|
44
|
+
@base_path ? (@base_path + "/" + url) : url
|
45
|
+
when '%a'
|
46
|
+
Util::HTML.escape(alt_text||"")
|
47
|
+
else
|
48
|
+
$1
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,227 @@
|
|
1
|
+
require 'jsduck/util/html'
|
2
|
+
require 'jsduck/logger'
|
3
|
+
|
4
|
+
module JsDuck
|
5
|
+
module Inline
|
6
|
+
|
7
|
+
# Implementation of inline tag {@link}
|
8
|
+
#
|
9
|
+
# It also takes care of the auto-detection of links in text
|
10
|
+
# through the #create_magic_links method.
|
11
|
+
class Link
|
12
|
+
# Sets up instance to work in context of particular class, so
|
13
|
+
# that when {@link #blah} is encountered it knows that
|
14
|
+
# Context#blah is meant.
|
15
|
+
attr_accessor :class_context
|
16
|
+
|
17
|
+
# Sets up instance to work in context of particular doc object.
|
18
|
+
# Used for error reporting.
|
19
|
+
attr_accessor :doc_context
|
20
|
+
|
21
|
+
# JsDuck::Relations for looking up class names.
|
22
|
+
#
|
23
|
+
# When auto-creating class links from CamelCased names found from
|
24
|
+
# text, we check the relations object to see if a class with that
|
25
|
+
# name actually exists.
|
26
|
+
attr_accessor :relations
|
27
|
+
|
28
|
+
def initialize(opts={})
|
29
|
+
@class_context = ""
|
30
|
+
@doc_context = {}
|
31
|
+
@relations = {}
|
32
|
+
|
33
|
+
# Template HTML that replaces {@link Class#member anchor text}.
|
34
|
+
# Can contain placeholders:
|
35
|
+
#
|
36
|
+
# %c - full class name (e.g. "Ext.Panel")
|
37
|
+
# %m - class member name prefixed with member type (e.g. "method-urlEncode")
|
38
|
+
# %# - inserts "#" if member name present
|
39
|
+
# %- - inserts "-" if member name present
|
40
|
+
# %a - anchor text for link
|
41
|
+
@tpl = opts[:link_tpl] || '<a href="%c%#%m">%a</a>'
|
42
|
+
|
43
|
+
@re = /\{@link\s+(\S*?)(?:\s+(.+?))?\}/m
|
44
|
+
end
|
45
|
+
|
46
|
+
# Takes StringScanner instance.
|
47
|
+
#
|
48
|
+
# Looks for inline tag at the current scan pointer position, when
|
49
|
+
# found, moves scan pointer forward and performs the apporpriate
|
50
|
+
# replacement.
|
51
|
+
def replace(input)
|
52
|
+
if input.check(@re)
|
53
|
+
input.scan(@re).sub(@re) { apply_tpl($1, $2, $&) }
|
54
|
+
else
|
55
|
+
false
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# applies the link template
|
60
|
+
def apply_tpl(target, text, full_link)
|
61
|
+
if target =~ /^(.*)#(static-)?(?:(cfg|property|method|event|css_var|css_mixin)-)?(.*)$/
|
62
|
+
cls = $1.empty? ? @class_context : $1
|
63
|
+
static = $2 ? true : nil
|
64
|
+
type = $3 ? $3.intern : nil
|
65
|
+
member = $4
|
66
|
+
else
|
67
|
+
cls = target
|
68
|
+
static = nil
|
69
|
+
type = false
|
70
|
+
member = false
|
71
|
+
end
|
72
|
+
|
73
|
+
# Construct link text
|
74
|
+
if text
|
75
|
+
text = text
|
76
|
+
elsif member
|
77
|
+
text = (cls == @class_context) ? member : (cls + "." + member)
|
78
|
+
else
|
79
|
+
text = cls
|
80
|
+
end
|
81
|
+
|
82
|
+
file = @doc_context[:filename]
|
83
|
+
line = @doc_context[:linenr]
|
84
|
+
if !@relations[cls]
|
85
|
+
Logger.warn(:link, "#{full_link} links to non-existing class", file, line)
|
86
|
+
return text
|
87
|
+
elsif member
|
88
|
+
ms = find_members(cls, {:name => member, :tagname => type, :static => static})
|
89
|
+
if ms.length == 0
|
90
|
+
Logger.warn(:link, "#{full_link} links to non-existing member", file, line)
|
91
|
+
return text
|
92
|
+
end
|
93
|
+
|
94
|
+
if ms.length > 1
|
95
|
+
# When multiple public members, see if there remains just
|
96
|
+
# one when we ignore the static members. If there's more,
|
97
|
+
# report ambiguity. If there's only static members, also
|
98
|
+
# report ambiguity.
|
99
|
+
instance_ms = ms.find_all {|m| !m[:meta][:static] }
|
100
|
+
if instance_ms.length > 1
|
101
|
+
alternatives = instance_ms.map {|m| "#{m[:tagname]} in #{m[:owner]}" }.join(", ")
|
102
|
+
Logger.warn(:link_ambiguous, "#{full_link} is ambiguous: "+alternatives, file, line)
|
103
|
+
elsif instance_ms.length == 0
|
104
|
+
static_ms = ms.find_all {|m| m[:meta][:static] }
|
105
|
+
alternatives = static_ms.map {|m| "static " + m[:tagname].to_s }.join(", ")
|
106
|
+
Logger.warn(:link_ambiguous, "#{full_link} is ambiguous: "+alternatives, file, line)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
return link(cls, member, text, type, static)
|
111
|
+
else
|
112
|
+
return link(cls, false, text)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# Looks input text for patterns like:
|
117
|
+
#
|
118
|
+
# My.ClassName
|
119
|
+
# MyClass#method
|
120
|
+
# #someProperty
|
121
|
+
#
|
122
|
+
# and converts them to links, as if they were surrounded with
|
123
|
+
# {@link} tag. One notable exception is that Foo is not created to
|
124
|
+
# link, even when Foo class exists, but Foo.Bar is. This is to
|
125
|
+
# avoid turning normal words into links. For example:
|
126
|
+
#
|
127
|
+
# Math involves a lot of numbers. Ext JS is a JavaScript framework.
|
128
|
+
#
|
129
|
+
# In these sentences we don't want to link "Math" and "Ext" to the
|
130
|
+
# corresponding JS classes. And that's why we auto-link only
|
131
|
+
# class names containing a dot "."
|
132
|
+
#
|
133
|
+
def create_magic_links(input)
|
134
|
+
cls_re = "([A-Z][A-Za-z0-9.]*[A-Za-z0-9])"
|
135
|
+
member_re = "(?:#([A-Za-z0-9]+))"
|
136
|
+
|
137
|
+
input.gsub(/\b#{cls_re}#{member_re}?\b|#{member_re}\b/m) do
|
138
|
+
replace_magic_link($1, $2 || $3)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def replace_magic_link(cls, member)
|
143
|
+
if cls && member
|
144
|
+
if @relations[cls] && get_matching_member(cls, {:name => member})
|
145
|
+
return link(cls, member, cls+"."+member)
|
146
|
+
else
|
147
|
+
warn_magic_link("#{cls}##{member} links to non-existing " + (@relations[cls] ? "member" : "class"))
|
148
|
+
end
|
149
|
+
elsif cls && cls =~ /\./
|
150
|
+
if @relations[cls]
|
151
|
+
return link(cls, nil, cls)
|
152
|
+
else
|
153
|
+
cls2, member2 = split_to_cls_and_member(cls)
|
154
|
+
if @relations[cls2] && get_matching_member(cls2, {:name => member2})
|
155
|
+
return link(cls2, member2, cls2+"."+member2)
|
156
|
+
elsif cls =~ /\.(js|css|html|php)\Z/
|
157
|
+
# Ignore common filenames
|
158
|
+
else
|
159
|
+
warn_magic_link("#{cls} links to non-existing class")
|
160
|
+
end
|
161
|
+
end
|
162
|
+
elsif !cls && member
|
163
|
+
if get_matching_member(@class_context, {:name => member})
|
164
|
+
return link(@class_context, member, member)
|
165
|
+
elsif member =~ /\A([A-F0-9]{3}|[A-F0-9]{6})\Z/i || member =~ /\A[0-9]/
|
166
|
+
# Ignore HEX color codes and
|
167
|
+
# member names beginning with number
|
168
|
+
else
|
169
|
+
warn_magic_link("##{member} links to non-existing member")
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
return "#{cls}#{member ? '#' : ''}#{member}"
|
174
|
+
end
|
175
|
+
|
176
|
+
def split_to_cls_and_member(str)
|
177
|
+
parts = str.split(/\./)
|
178
|
+
return [parts.slice(0, parts.length-1).join("."), parts.last]
|
179
|
+
end
|
180
|
+
|
181
|
+
def warn_magic_link(msg)
|
182
|
+
Logger.warn(:link_auto, msg, @doc_context[:filename], @doc_context[:linenr])
|
183
|
+
end
|
184
|
+
|
185
|
+
# applies the link template
|
186
|
+
def link(cls, member, anchor_text, type=nil, static=nil)
|
187
|
+
# Use the canonical class name for link (not some alternateClassName)
|
188
|
+
cls = @relations[cls][:name]
|
189
|
+
# prepend type name to member name
|
190
|
+
member = member && get_matching_member(cls, {:name => member, :tagname => type, :static => static})
|
191
|
+
|
192
|
+
@tpl.gsub(/(%[\w#-])/) do
|
193
|
+
case $1
|
194
|
+
when '%c'
|
195
|
+
cls
|
196
|
+
when '%m'
|
197
|
+
member ? member[:id] : ""
|
198
|
+
when '%#'
|
199
|
+
member ? "#" : ""
|
200
|
+
when '%-'
|
201
|
+
member ? "-" : ""
|
202
|
+
when '%a'
|
203
|
+
Util::HTML.escape(anchor_text||"")
|
204
|
+
else
|
205
|
+
$1
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
def get_matching_member(cls, query)
|
211
|
+
ms = find_members(cls, query).find_all {|m| !m[:private] }
|
212
|
+
if ms.length > 1
|
213
|
+
instance_ms = ms.find_all {|m| !m[:meta][:static] }
|
214
|
+
instance_ms.length > 0 ? instance_ms[0] : ms.find_all {|m| m[:meta][:static] }[0]
|
215
|
+
else
|
216
|
+
ms[0]
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
def find_members(cls, query)
|
221
|
+
@relations[cls] ? @relations[cls].find_members(query) : []
|
222
|
+
end
|
223
|
+
|
224
|
+
end
|
225
|
+
|
226
|
+
end
|
227
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'jsduck/util/html'
|
2
|
+
require 'jsduck/logger'
|
3
|
+
|
4
|
+
module JsDuck
|
5
|
+
module Inline
|
6
|
+
|
7
|
+
# Implementation of inline tag {@video}
|
8
|
+
class Video
|
9
|
+
# Sets up instance to work in context of particular doc object.
|
10
|
+
# Used for error reporting.
|
11
|
+
attr_accessor :doc_context
|
12
|
+
|
13
|
+
def initialize(opts={})
|
14
|
+
@doc_context = {}
|
15
|
+
|
16
|
+
@templates = {
|
17
|
+
"html5" => '<video src="%u">%a</video>',
|
18
|
+
"vimeo" => [
|
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>',
|
27
|
+
].join
|
28
|
+
}
|
29
|
+
|
30
|
+
@re = /\{@video\s+(\w+)\s+(\S*?)(?:\s+(.+?))?\}/m
|
31
|
+
end
|
32
|
+
|
33
|
+
# Takes StringScanner instance.
|
34
|
+
#
|
35
|
+
# Looks for inline tag at the current scan pointer position, when
|
36
|
+
# found, moves scan pointer forward and performs the apporpriate
|
37
|
+
# replacement.
|
38
|
+
def replace(input)
|
39
|
+
if input.check(@re)
|
40
|
+
input.scan(@re).sub(@re) { apply_tpl($1, $2, $3) }
|
41
|
+
else
|
42
|
+
false
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# applies the video template of the specified type
|
47
|
+
def apply_tpl(type, url, alt_text)
|
48
|
+
unless @templates.has_key?(type)
|
49
|
+
ctx = @doc_context
|
50
|
+
Logger.warn(nil, "Unknown video type #{type}", ctx[:filename], ctx[:linenr])
|
51
|
+
end
|
52
|
+
|
53
|
+
@templates[type].gsub(/(%\w)/) do
|
54
|
+
case $1
|
55
|
+
when '%u'
|
56
|
+
url
|
57
|
+
when '%a'
|
58
|
+
Util::HTML.escape(alt_text||"")
|
59
|
+
else
|
60
|
+
$1
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
@@ -1,5 +1,5 @@
|
|
1
|
-
require 'jsduck/
|
2
|
-
require 'jsduck/html'
|
1
|
+
require 'jsduck/util/json'
|
2
|
+
require 'jsduck/util/html'
|
3
3
|
|
4
4
|
module JsDuck
|
5
5
|
|
@@ -16,9 +16,9 @@ module JsDuck
|
|
16
16
|
relations.each do |cls|
|
17
17
|
extract(cls[:doc]).each_with_index do |ex, i|
|
18
18
|
@examples << {
|
19
|
-
:id => cls
|
20
|
-
:name => cls
|
21
|
-
:href => '#!/api/' + cls
|
19
|
+
:id => cls[:name] + "-" + i.to_s,
|
20
|
+
:name => cls[:name] + " example #" + (i+1).to_s,
|
21
|
+
:href => '#!/api/' + cls[:name],
|
22
22
|
:code => ex[:code],
|
23
23
|
:options => ex[:options],
|
24
24
|
}
|
@@ -47,7 +47,7 @@ module JsDuck
|
|
47
47
|
|
48
48
|
# Writes all found examples to .js file
|
49
49
|
def write(filename)
|
50
|
-
|
50
|
+
Util::Json.write_jsonp(filename, "__inline_examples__", @examples)
|
51
51
|
end
|
52
52
|
|
53
53
|
# Extracts inline examples from HTML
|
@@ -65,7 +65,7 @@ module JsDuck
|
|
65
65
|
ex = s.scan_until(@end_example_re).sub(@end_example_re, '')
|
66
66
|
|
67
67
|
examples << {
|
68
|
-
:code => HTML.unescape(HTML.strip_tags(ex)),
|
68
|
+
:code => Util::HTML.unescape(Util::HTML.strip_tags(ex)),
|
69
69
|
:options => options,
|
70
70
|
}
|
71
71
|
else
|
data/lib/jsduck/js_parser.rb
CHANGED
@@ -25,7 +25,7 @@ module JsDuck
|
|
25
25
|
# }
|
26
26
|
#
|
27
27
|
def parse
|
28
|
-
@ast = Esprima.
|
28
|
+
@ast = Esprima.parse(@input)
|
29
29
|
|
30
30
|
@ast["comments"] = merge_comments(@ast["comments"])
|
31
31
|
locate_comments
|
@@ -62,10 +62,11 @@ module JsDuck
|
|
62
62
|
end
|
63
63
|
|
64
64
|
# Two comments can be merged if they are both line-comments and
|
65
|
-
# they are separated only by whitespace (
|
65
|
+
# they are separated only by whitespace (only one newline at the
|
66
|
+
# end of the first comment is allowed)
|
66
67
|
def mergeable?(c1, c2)
|
67
68
|
if c1["type"] == "Line" && c2["type"] == "Line"
|
68
|
-
/\A[ \t]*\Z/ =~ @input.slice((c1["range"][1])..(c2["range"][0]-1))
|
69
|
+
/\A(\r\n|\n|\r)?[ \t]*\Z/ =~ @input.slice((c1["range"][1])..(c2["range"][0]-1))
|
69
70
|
else
|
70
71
|
false
|
71
72
|
end
|
@@ -156,7 +157,7 @@ module JsDuck
|
|
156
157
|
properties = NODE_TYPES[node["type"]]
|
157
158
|
|
158
159
|
unless properties
|
159
|
-
Logger.
|
160
|
+
Logger.fatal("Unknown node type: "+node["type"])
|
160
161
|
exit(1)
|
161
162
|
end
|
162
163
|
|