jsduck 4.10.4 → 5.0.0.beta01
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +0 -1
- data/README.md +32 -6
- data/Rakefile +10 -18
- data/bin/compare +5 -5
- data/bin/jsduck +2 -3
- data/jsduck.gemspec +3 -4
- data/lib/jsduck/aggregator.rb +21 -80
- data/lib/jsduck/app.rb +7 -14
- data/lib/jsduck/app_data.rb +4 -5
- data/lib/jsduck/assets.rb +4 -7
- data/lib/jsduck/base_type.rb +53 -0
- data/lib/jsduck/batch_parser.rb +8 -87
- data/lib/jsduck/batch_processor.rb +77 -0
- data/lib/jsduck/categories/auto.rb +83 -0
- data/lib/jsduck/categories/class_name.rb +63 -0
- data/lib/jsduck/categories/factory.rb +113 -0
- data/lib/jsduck/categories/file.rb +75 -0
- data/lib/jsduck/class.rb +3 -9
- data/lib/jsduck/class_doc_expander.rb +1 -1
- data/lib/jsduck/css/lexer.rb +203 -0
- data/lib/jsduck/css/parser.rb +121 -0
- data/lib/jsduck/doc/comment.rb +40 -0
- data/lib/jsduck/doc/map.rb +23 -0
- data/lib/jsduck/doc/parser.rb +128 -0
- data/lib/jsduck/doc/processor.rb +52 -0
- data/lib/jsduck/doc/scanner.rb +76 -0
- data/lib/jsduck/doc/standard_tag_parser.rb +154 -0
- data/lib/jsduck/doc/subproperties.rb +64 -0
- data/lib/jsduck/docs_code_comparer.rb +31 -0
- data/lib/jsduck/export_writer.rb +2 -2
- data/lib/jsduck/exporter/app.rb +16 -4
- data/lib/jsduck/exporter/full.rb +2 -2
- data/lib/jsduck/format/batch.rb +58 -0
- data/lib/jsduck/format/class.rb +62 -0
- data/lib/jsduck/format/doc.rb +172 -0
- data/lib/jsduck/format/html_stack.rb +109 -0
- data/lib/jsduck/format/shortener.rb +55 -0
- data/lib/jsduck/format/subproperties.rb +64 -0
- data/lib/jsduck/guides.rb +32 -14
- data/lib/jsduck/index_html.rb +3 -1
- data/lib/jsduck/inline/auto_link.rb +2 -2
- data/lib/jsduck/inline/link.rb +4 -3
- data/lib/jsduck/inline/link_renderer.rb +2 -2
- data/lib/jsduck/inline/video.rb +8 -2
- data/lib/jsduck/js/ast.rb +361 -0
- data/lib/jsduck/js/esprima.rb +39 -0
- data/lib/jsduck/{esprima → js/esprima}/esprima.js +0 -0
- data/lib/jsduck/js/evaluator.rb +70 -0
- data/lib/jsduck/js/ext_patterns.rb +70 -0
- data/lib/jsduck/js/function.rb +206 -0
- data/lib/jsduck/js/node.rb +194 -0
- data/lib/jsduck/js/node_array.rb +36 -0
- data/lib/jsduck/js/parser.rb +223 -0
- data/lib/jsduck/js/serializer.rb +263 -0
- data/lib/jsduck/js/utils.rb +21 -0
- data/lib/jsduck/logger.rb +3 -13
- data/lib/jsduck/members_index.rb +3 -4
- data/lib/jsduck/merger.rb +25 -145
- data/lib/jsduck/options.rb +29 -132
- data/lib/jsduck/parser.rb +76 -0
- data/lib/jsduck/process/accessors.rb +133 -0
- data/lib/jsduck/process/circular_deps.rb +58 -0
- data/lib/jsduck/process/enums.rb +91 -0
- data/lib/jsduck/process/ext4_events.rb +43 -0
- data/lib/jsduck/process/global_members.rb +36 -0
- data/lib/jsduck/process/ignored_classes.rb +16 -0
- data/lib/jsduck/process/importer.rb +58 -0
- data/lib/jsduck/process/inherit_doc.rb +197 -0
- data/lib/jsduck/process/lint.rb +135 -0
- data/lib/jsduck/process/overrides.rb +99 -0
- data/lib/jsduck/process/return_values.rb +72 -0
- data/lib/jsduck/process/versions.rb +102 -0
- data/lib/jsduck/relations.rb +5 -0
- data/lib/jsduck/render/class.rb +144 -0
- data/lib/jsduck/render/sidebar.rb +97 -0
- data/lib/jsduck/render/signature.rb +94 -0
- data/lib/jsduck/render/subproperties.rb +99 -0
- data/lib/jsduck/render/tags.rb +38 -0
- data/lib/jsduck/search_data.rb +19 -13
- data/lib/jsduck/source/file.rb +8 -17
- data/lib/jsduck/tag/abstract.rb +4 -7
- data/lib/jsduck/tag/accessor.rb +10 -0
- data/lib/jsduck/tag/alias.rb +61 -0
- data/lib/jsduck/tag/alternate_class_names.rb +17 -0
- data/lib/jsduck/tag/aside.rb +28 -31
- data/lib/jsduck/tag/author.rb +9 -5
- data/lib/jsduck/tag/boolean_tag.rb +24 -0
- data/lib/jsduck/tag/cfg.rb +45 -0
- data/lib/jsduck/tag/chainable.rb +5 -7
- data/lib/jsduck/tag/class.rb +28 -0
- data/lib/jsduck/tag/class_list_tag.rb +40 -0
- data/lib/jsduck/tag/constructor.rb +24 -0
- data/lib/jsduck/tag/css_mixin.rb +17 -0
- data/lib/jsduck/tag/css_var.rb +29 -0
- data/lib/jsduck/tag/default.rb +31 -0
- data/lib/jsduck/tag/deprecated.rb +13 -27
- data/lib/jsduck/tag/deprecated_tag.rb +58 -0
- data/lib/jsduck/tag/doc.rb +32 -0
- data/lib/jsduck/tag/docauthor.rb +4 -5
- data/lib/jsduck/tag/enum.rb +70 -0
- data/lib/jsduck/tag/event.rb +28 -0
- data/lib/jsduck/tag/evented.rb +10 -0
- data/lib/jsduck/tag/extends.rb +45 -0
- data/lib/jsduck/tag/ftype.rb +18 -0
- data/lib/jsduck/tag/hide.rb +4 -11
- data/lib/jsduck/tag/ignore.rb +6 -7
- data/lib/jsduck/tag/inheritable.rb +10 -0
- data/lib/jsduck/tag/inheritdoc.rb +48 -0
- data/lib/jsduck/tag/markdown.rb +8 -6
- data/lib/jsduck/tag/member.rb +24 -0
- data/lib/jsduck/tag/method.rb +35 -0
- data/lib/jsduck/tag/mixins.rb +26 -0
- data/lib/jsduck/tag/name.rb +36 -0
- data/lib/jsduck/tag/new.rb +13 -27
- data/lib/jsduck/tag/override.rb +37 -0
- data/lib/jsduck/tag/overrides.rb +29 -0
- data/lib/jsduck/tag/param.rb +87 -0
- data/lib/jsduck/tag/preventable.rb +19 -10
- data/lib/jsduck/tag/private.rb +28 -13
- data/lib/jsduck/tag/property.rb +39 -0
- data/lib/jsduck/tag/protected.rb +5 -7
- data/lib/jsduck/tag/ptype.rb +18 -0
- data/lib/jsduck/tag/readonly.rb +4 -7
- data/lib/jsduck/tag/removed.rb +21 -29
- data/lib/jsduck/tag/required.rb +11 -9
- data/lib/jsduck/tag/requires.rb +12 -0
- data/lib/jsduck/tag/return.rb +47 -0
- data/lib/jsduck/tag/since.rb +19 -11
- data/lib/jsduck/tag/singleton.rb +15 -0
- data/lib/jsduck/tag/static.rb +5 -7
- data/lib/jsduck/tag/subproperties.rb +23 -0
- data/lib/jsduck/tag/tag.rb +208 -0
- data/lib/jsduck/tag/template.rb +14 -9
- data/lib/jsduck/tag/throws.rb +38 -0
- data/lib/jsduck/tag/type.rb +48 -0
- data/lib/jsduck/tag/uses.rb +12 -0
- data/lib/jsduck/tag/xtype.rb +30 -0
- data/lib/jsduck/tag_loader.rb +39 -0
- data/lib/jsduck/tag_registry.rb +189 -0
- data/lib/jsduck/type_parser.rb +3 -3
- data/lib/jsduck/web_writer.rb +2 -2
- data/lib/jsduck/welcome.rb +1 -1
- metadata +578 -538
- data/lib/jsduck/accessors.rb +0 -136
- data/lib/jsduck/ast.rb +0 -524
- data/lib/jsduck/auto_categories.rb +0 -80
- data/lib/jsduck/batch_formatter.rb +0 -60
- data/lib/jsduck/categories.rb +0 -73
- data/lib/jsduck/categories_class_name.rb +0 -37
- data/lib/jsduck/circular_deps.rb +0 -56
- data/lib/jsduck/class_formatter.rb +0 -102
- data/lib/jsduck/columns.rb +0 -56
- data/lib/jsduck/css_lexer.rb +0 -201
- data/lib/jsduck/css_parser.rb +0 -119
- data/lib/jsduck/doc_ast.rb +0 -319
- data/lib/jsduck/doc_formatter.rb +0 -142
- data/lib/jsduck/doc_parser.rb +0 -611
- data/lib/jsduck/doc_type.rb +0 -59
- data/lib/jsduck/enum.rb +0 -73
- data/lib/jsduck/esprima.rb +0 -51
- data/lib/jsduck/evaluator.rb +0 -69
- data/lib/jsduck/ext_patterns.rb +0 -58
- data/lib/jsduck/file_categories.rb +0 -76
- data/lib/jsduck/function_ast.rb +0 -206
- data/lib/jsduck/guide_anchors.rb +0 -32
- data/lib/jsduck/guide_toc.rb +0 -49
- data/lib/jsduck/html_stack.rb +0 -105
- data/lib/jsduck/importer.rb +0 -121
- data/lib/jsduck/inherit_doc.rb +0 -193
- data/lib/jsduck/js_parser.rb +0 -221
- data/lib/jsduck/lint.rb +0 -133
- data/lib/jsduck/meta_tag.rb +0 -88
- data/lib/jsduck/meta_tag_loader.rb +0 -67
- data/lib/jsduck/meta_tag_registry.rb +0 -111
- data/lib/jsduck/meta_tag_renderer.rb +0 -34
- data/lib/jsduck/news.rb +0 -128
- data/lib/jsduck/override.rb +0 -87
- data/lib/jsduck/renderer.rb +0 -361
- data/lib/jsduck/return_values.rb +0 -72
- data/lib/jsduck/serializer.rb +0 -262
- data/lib/jsduck/shortener.rb +0 -58
- data/lib/jsduck/signature_renderer.rb +0 -91
- data/lib/jsduck/source/file_parser.rb +0 -72
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'jsduck/logger'
|
2
|
+
require 'jsduck/util/json'
|
3
|
+
|
4
|
+
module JsDuck
|
5
|
+
module Categories
|
6
|
+
|
7
|
+
# Reads categories info from config file
|
8
|
+
class File
|
9
|
+
def initialize(filename, relations)
|
10
|
+
@filename = filename
|
11
|
+
@relations = relations
|
12
|
+
end
|
13
|
+
|
14
|
+
# Parses categories in JSON file
|
15
|
+
def generate
|
16
|
+
@categories = Util::Json.read(@filename)
|
17
|
+
|
18
|
+
# Don't crash if old syntax is used.
|
19
|
+
if @categories.is_a?(Hash) && @categories["categories"]
|
20
|
+
Logger.warn(nil, 'Update categories file to contain just the array inside {"categories": [...]}', @filename)
|
21
|
+
@categories = @categories["categories"]
|
22
|
+
end
|
23
|
+
|
24
|
+
# Perform expansion on all class names containing * wildcard
|
25
|
+
@categories.each do |cat|
|
26
|
+
cat["groups"].each do |group|
|
27
|
+
group["classes"] = group["classes"].map do |name|
|
28
|
+
expand(name)
|
29
|
+
end.flatten
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
validate
|
34
|
+
|
35
|
+
@categories
|
36
|
+
end
|
37
|
+
|
38
|
+
# Expands class name like 'Foo.*' into multiple class names.
|
39
|
+
def expand(name)
|
40
|
+
re = Regexp.new("^" + name.split(/\*/, -1).map {|part| Regexp.escape(part) }.join('.*') + "$")
|
41
|
+
|
42
|
+
classes = @relations.to_a.find_all do |cls|
|
43
|
+
re =~ cls[:name] && !cls[:private] && !cls[:deprecated]
|
44
|
+
end.map {|cls| cls[:name] }.sort
|
45
|
+
|
46
|
+
if classes.length == 0
|
47
|
+
Logger.warn(:cat_no_match, "No class found matching a pattern '#{name}' in categories file", @filename)
|
48
|
+
end
|
49
|
+
classes
|
50
|
+
end
|
51
|
+
|
52
|
+
# Prints warnings for missing classes in categories file
|
53
|
+
def validate
|
54
|
+
# Build a map of all classes listed in categories
|
55
|
+
listed_classes = {}
|
56
|
+
@categories.each do |cat|
|
57
|
+
cat["groups"].each do |group|
|
58
|
+
group["classes"].each do |cls_name|
|
59
|
+
listed_classes[cls_name] = true
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Check that each existing non-private & non-deprecated class is listed
|
65
|
+
@relations.each do |cls|
|
66
|
+
unless listed_classes[cls[:name]] || cls[:private] || cls[:deprecated]
|
67
|
+
Logger.warn(:cat_class_missing, "Class '#{cls[:name]}' not found in categories file", @filename)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
end
|
data/lib/jsduck/class.rb
CHANGED
@@ -162,9 +162,9 @@ module JsDuck
|
|
162
162
|
end
|
163
163
|
|
164
164
|
if query[:static] == true
|
165
|
-
ms = ms.find_all {|m| m[:
|
165
|
+
ms = ms.find_all {|m| m[:static] }
|
166
166
|
elsif query[:static] == false
|
167
|
-
ms = ms.reject {|m| m[:
|
167
|
+
ms = ms.reject {|m| m[:static] }
|
168
168
|
end
|
169
169
|
|
170
170
|
ms
|
@@ -190,13 +190,7 @@ module JsDuck
|
|
190
190
|
def self.member_id(m)
|
191
191
|
# Sanitize $ in member names with something safer
|
192
192
|
name = m[:name].gsub(/\$/, 'S-')
|
193
|
-
"#{m[:
|
194
|
-
end
|
195
|
-
|
196
|
-
# Loops through all available member types,
|
197
|
-
# passing the tagname of the member to the block.
|
198
|
-
def self.each_member_type(&block)
|
199
|
-
[:cfg, :property, :method, :event, :css_var, :css_mixin].each(&block)
|
193
|
+
"#{m[:static] ? 'static-' : ''}#{m[:tagname]}-#{name}"
|
200
194
|
end
|
201
195
|
|
202
196
|
# True if the given member is a constructor method
|
@@ -0,0 +1,203 @@
|
|
1
|
+
require 'strscan'
|
2
|
+
|
3
|
+
module JsDuck
|
4
|
+
module Css
|
5
|
+
|
6
|
+
# Tokenizes CSS or SCSS code into lexical tokens.
|
7
|
+
#
|
8
|
+
# Each token has a type and value.
|
9
|
+
# Types and possible values for them are as follows:
|
10
|
+
#
|
11
|
+
# - :number -- "25.8"
|
12
|
+
# - :percentage -- "25%"
|
13
|
+
# - :dimension -- "2em"
|
14
|
+
# - :string -- '"Hello world"'
|
15
|
+
# - :ident -- "foo-bar"
|
16
|
+
# - :at_keyword -- "@mixin"
|
17
|
+
# - :hash -- "#00FF66"
|
18
|
+
# - :delim -- "{"
|
19
|
+
# - :doc_comment -- "/** My comment */"
|
20
|
+
#
|
21
|
+
# Notice that doc-comments are recognized as tokens while normal
|
22
|
+
# comments are ignored just as whitespace.
|
23
|
+
#
|
24
|
+
class Lexer
|
25
|
+
# Initializes lexer with input string.
|
26
|
+
def initialize(input)
|
27
|
+
@input = StringScanner.new(input)
|
28
|
+
@buffer = []
|
29
|
+
end
|
30
|
+
|
31
|
+
# Tests if given pattern matches the tokens that follow at current
|
32
|
+
# position.
|
33
|
+
#
|
34
|
+
# Takes list of strings and symbols. Symbols are compared to
|
35
|
+
# token type, while strings to token value. For example:
|
36
|
+
#
|
37
|
+
# look(:ident, ":", :dimension)
|
38
|
+
#
|
39
|
+
def look(*tokens)
|
40
|
+
buffer_tokens(tokens.length)
|
41
|
+
i = 0
|
42
|
+
tokens.all? do |t|
|
43
|
+
tok = @buffer[i]
|
44
|
+
i += 1
|
45
|
+
if !tok
|
46
|
+
false
|
47
|
+
elsif t.instance_of?(Symbol)
|
48
|
+
tok[:type] == t
|
49
|
+
else
|
50
|
+
tok[:value] == t
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Returns the value of next token, moving the current token cursor
|
56
|
+
# also to next token.
|
57
|
+
#
|
58
|
+
# When full=true, returns full token as hash like so:
|
59
|
+
#
|
60
|
+
# {:type => :ident, :value => "foo"}
|
61
|
+
#
|
62
|
+
# For doc-comments the full token also contains the field :linenr,
|
63
|
+
# pointing to the line where the doc-comment began.
|
64
|
+
#
|
65
|
+
def next(full=false)
|
66
|
+
buffer_tokens(1)
|
67
|
+
tok = @buffer.shift
|
68
|
+
# advance the scanpointer to the position after this token
|
69
|
+
@input.pos = tok[:pos]
|
70
|
+
full ? tok : tok[:value]
|
71
|
+
end
|
72
|
+
|
73
|
+
# True when no more tokens.
|
74
|
+
def empty?
|
75
|
+
buffer_tokens(1)
|
76
|
+
return !@buffer.first
|
77
|
+
end
|
78
|
+
|
79
|
+
# Ensures next n tokens are read in buffer
|
80
|
+
#
|
81
|
+
# At the end of buffering the initial position scanpointer is
|
82
|
+
# restored. Only the #next method will advance the scanpointer in
|
83
|
+
# a way that's visible outside this class.
|
84
|
+
def buffer_tokens(n)
|
85
|
+
prev_pos = @input.pos
|
86
|
+
@input.pos = @buffer.last[:pos] if @buffer.last
|
87
|
+
(n - @buffer.length).times do
|
88
|
+
@previous_token = tok = next_token
|
89
|
+
if tok
|
90
|
+
# remember scanpointer position after each token
|
91
|
+
tok[:pos] = @input.pos
|
92
|
+
@buffer << tok
|
93
|
+
end
|
94
|
+
end
|
95
|
+
@input.pos = prev_pos
|
96
|
+
end
|
97
|
+
|
98
|
+
# Parses out next token from input stream.
|
99
|
+
def next_token
|
100
|
+
while !@input.eos? do
|
101
|
+
skip_white
|
102
|
+
if @input.check(IDENT)
|
103
|
+
return {
|
104
|
+
:type => :ident,
|
105
|
+
:value => @input.scan(IDENT)
|
106
|
+
}
|
107
|
+
elsif @input.check(/'/)
|
108
|
+
return {
|
109
|
+
:type => :string,
|
110
|
+
:value => @input.scan(/'([^'\\]|\\.)*('|\z)/m)
|
111
|
+
}
|
112
|
+
elsif @input.check(/"/)
|
113
|
+
return {
|
114
|
+
:type => :string,
|
115
|
+
:value => @input.scan(/"([^"\\]|\\.)*("|\z)/m)
|
116
|
+
}
|
117
|
+
elsif @input.check(/\//)
|
118
|
+
# Several things begin with dash:
|
119
|
+
# - comments, regexes, division-operators
|
120
|
+
if @input.check(/\/\*\*[^\/]/)
|
121
|
+
return {
|
122
|
+
:type => :doc_comment,
|
123
|
+
# Calculate current line number, starting with 1
|
124
|
+
:linenr => @input.string[0...@input.pos].count("\n") + 1,
|
125
|
+
:value => @input.scan_until(/\*\/|\z/).sub(/\A\/\*\*/, "").sub(/\*\/\z/, "")
|
126
|
+
}
|
127
|
+
elsif @input.check(/\/\*/)
|
128
|
+
# skip multiline comment
|
129
|
+
@input.scan_until(/\*\/|\z/)
|
130
|
+
elsif @input.check(/\/\//)
|
131
|
+
# skip line comment
|
132
|
+
@input.scan_until(/\n|\z/)
|
133
|
+
else
|
134
|
+
return {
|
135
|
+
:type => :operator,
|
136
|
+
:value => @input.scan(/\//)
|
137
|
+
}
|
138
|
+
end
|
139
|
+
elsif @input.check(NUM)
|
140
|
+
nr = @input.scan(NUM)
|
141
|
+
if @input.check(/%/)
|
142
|
+
return {
|
143
|
+
:type => :percentage,
|
144
|
+
:value => nr + @input.scan(/%/)
|
145
|
+
}
|
146
|
+
elsif @input.check(IDENT)
|
147
|
+
return {
|
148
|
+
:type => :dimension,
|
149
|
+
:value => nr + @input.scan(IDENT)
|
150
|
+
}
|
151
|
+
else
|
152
|
+
return {
|
153
|
+
:type => :number,
|
154
|
+
:value => nr
|
155
|
+
}
|
156
|
+
end
|
157
|
+
elsif @input.check(/@/)
|
158
|
+
return maybe(:at_keyword, /@/, IDENT)
|
159
|
+
elsif @input.check(/#/)
|
160
|
+
return maybe(:hash, /#/, NAME)
|
161
|
+
elsif @input.check(/\$/)
|
162
|
+
return maybe(:var, /\$/, IDENT)
|
163
|
+
elsif @input.check(/./)
|
164
|
+
return {
|
165
|
+
:type => :delim,
|
166
|
+
:value => @input.scan(/./)
|
167
|
+
}
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
# Returns token of given type when both regexes match.
|
173
|
+
# Otherwise returns :delim token with value of first regex match.
|
174
|
+
# First regex must always match.
|
175
|
+
def maybe(token_type, before_re, after_re)
|
176
|
+
before = @input.scan(before_re)
|
177
|
+
if @input.check(after_re)
|
178
|
+
return {
|
179
|
+
:type => token_type,
|
180
|
+
:value => before + @input.scan(after_re)
|
181
|
+
}
|
182
|
+
else
|
183
|
+
return {
|
184
|
+
:type => :delim,
|
185
|
+
:value => before
|
186
|
+
}
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
def skip_white
|
191
|
+
@input.scan(/\s+/)
|
192
|
+
end
|
193
|
+
|
194
|
+
# Simplified token syntax based on:
|
195
|
+
# http://www.w3.org/TR/CSS21/syndata.html
|
196
|
+
IDENT = /-?[_a-z][_a-z0-9-]*/i
|
197
|
+
NAME = /[_a-z0-9-]+/i
|
198
|
+
NUM = /[0-9]*\.[0-9]+|[0-9]+/
|
199
|
+
|
200
|
+
end
|
201
|
+
|
202
|
+
end
|
203
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require 'jsduck/css/lexer'
|
2
|
+
|
3
|
+
module JsDuck
|
4
|
+
module Css
|
5
|
+
|
6
|
+
class Parser
|
7
|
+
def initialize(input, options = {})
|
8
|
+
@lex = Css::Lexer.new(input)
|
9
|
+
@docs = []
|
10
|
+
end
|
11
|
+
|
12
|
+
# Parses the whole CSS block and returns same kind of structure
|
13
|
+
# that JavaScript parser does.
|
14
|
+
def parse
|
15
|
+
while !@lex.empty? do
|
16
|
+
if look(:doc_comment)
|
17
|
+
comment = @lex.next(true)
|
18
|
+
@docs << {
|
19
|
+
:comment => comment[:value],
|
20
|
+
:linenr => comment[:linenr],
|
21
|
+
:code => code_block,
|
22
|
+
:type => :doc_comment,
|
23
|
+
}
|
24
|
+
else
|
25
|
+
@lex.next
|
26
|
+
end
|
27
|
+
end
|
28
|
+
@docs
|
29
|
+
end
|
30
|
+
|
31
|
+
# <code-block> := <mixin-declaration> | <var-declaration> | <property>
|
32
|
+
def code_block
|
33
|
+
if look("@mixin")
|
34
|
+
mixin_declaration
|
35
|
+
elsif look(:var, ":")
|
36
|
+
var_declaration
|
37
|
+
else
|
38
|
+
# Default to property like in Js::Parser.
|
39
|
+
{:tagname => :property}
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# <mixin-declaration> := "@mixin" <ident>
|
44
|
+
def mixin_declaration
|
45
|
+
match("@mixin")
|
46
|
+
return {
|
47
|
+
:tagname => :css_mixin,
|
48
|
+
:name => look(:ident) ? match(:ident) : nil,
|
49
|
+
}
|
50
|
+
end
|
51
|
+
|
52
|
+
# <var-declaration> := <var> ":" <css-value>
|
53
|
+
def var_declaration
|
54
|
+
name = match(:var)
|
55
|
+
match(":")
|
56
|
+
value_list = css_value
|
57
|
+
return {
|
58
|
+
:tagname => :css_var,
|
59
|
+
:name => name,
|
60
|
+
:default => value_list.map {|v| v[:value] }.join(" "),
|
61
|
+
:type => value_type(value_list),
|
62
|
+
}
|
63
|
+
end
|
64
|
+
|
65
|
+
# <css-value> := ...anything up to... [ ";" | "}" | "!default" ]
|
66
|
+
def css_value
|
67
|
+
val = []
|
68
|
+
while !look(";") && !look("}") && !look("!", "default")
|
69
|
+
val << @lex.next(true)
|
70
|
+
end
|
71
|
+
val
|
72
|
+
end
|
73
|
+
|
74
|
+
# Determines type of CSS value
|
75
|
+
def value_type(val)
|
76
|
+
case val[0][:type]
|
77
|
+
when :number
|
78
|
+
"number"
|
79
|
+
when :dimension
|
80
|
+
"length"
|
81
|
+
when :percentage
|
82
|
+
"percentage"
|
83
|
+
when :string
|
84
|
+
"string"
|
85
|
+
when :hash
|
86
|
+
"color"
|
87
|
+
when :ident
|
88
|
+
case val[0][:value]
|
89
|
+
when "true", "false"
|
90
|
+
return "boolean"
|
91
|
+
when "rgb", "rgba", "hsl", "hsla"
|
92
|
+
return "color"
|
93
|
+
when "black", "silver", "gray", "white", "maroon",
|
94
|
+
"red", "purple", "fuchsia", "green", "lime", "olive",
|
95
|
+
"yellow", "navy", "blue", "teal", "aqua", "orange"
|
96
|
+
return "color"
|
97
|
+
when "transparent"
|
98
|
+
return "color"
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# Matches all arguments, returns the value of last match
|
104
|
+
# When the whole sequence doesn't match, throws exception
|
105
|
+
def match(*args)
|
106
|
+
if look(*args)
|
107
|
+
last = nil
|
108
|
+
args.length.times { last = @lex.next }
|
109
|
+
last
|
110
|
+
else
|
111
|
+
throw "Expected: " + args.join(", ")
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def look(*args)
|
116
|
+
@lex.look(*args)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module JsDuck
|
2
|
+
module Doc
|
3
|
+
|
4
|
+
# A simple helper to extract doc comment contents.
|
5
|
+
class Comment
|
6
|
+
|
7
|
+
# Extracts content inside /** ... */
|
8
|
+
def self.purify(input)
|
9
|
+
result = []
|
10
|
+
|
11
|
+
# We can have two types of lines:
|
12
|
+
# - those beginning with *
|
13
|
+
# - and those without it
|
14
|
+
indent = nil
|
15
|
+
input.each_line do |line|
|
16
|
+
line.chomp!
|
17
|
+
if line =~ /\A\s*\*\s?(.*)\z/
|
18
|
+
# When comment contains *-lines, switch indent-trimming off
|
19
|
+
indent = 0
|
20
|
+
result << $1
|
21
|
+
elsif line =~ /\A\s*\z/
|
22
|
+
# pass-through empty lines
|
23
|
+
result << line
|
24
|
+
elsif indent == nil && line =~ /\A(\s*)(.*?\z)/
|
25
|
+
# When indent not measured, measure it and remember
|
26
|
+
indent = $1.length
|
27
|
+
result << $2
|
28
|
+
else
|
29
|
+
# Trim away indent if available
|
30
|
+
result << line.sub(/\A\s{0,#{indent||0}}/, "")
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
result.join("\n")
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|