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,23 @@
|
|
1
|
+
module JsDuck
|
2
|
+
module Doc
|
3
|
+
|
4
|
+
# Helper for building at-tags lookup table.
|
5
|
+
class Map
|
6
|
+
|
7
|
+
# Builds map of at-tags for quick lookup
|
8
|
+
def self.build(docs)
|
9
|
+
map = {}
|
10
|
+
docs.each do |tag|
|
11
|
+
if map[tag[:tagname]]
|
12
|
+
map[tag[:tagname]] << tag
|
13
|
+
else
|
14
|
+
map[tag[:tagname]] = [tag]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
map
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
require 'strscan'
|
2
|
+
require 'jsduck/doc/comment'
|
3
|
+
require 'jsduck/doc/scanner'
|
4
|
+
require 'jsduck/tag_registry'
|
5
|
+
require 'jsduck/logger'
|
6
|
+
|
7
|
+
module JsDuck
|
8
|
+
module Doc
|
9
|
+
|
10
|
+
# Parses doc-comment into array of @tags
|
11
|
+
#
|
12
|
+
# For each @tag it produces Hash like the following:
|
13
|
+
#
|
14
|
+
# {
|
15
|
+
# :tagname => :cfg/:property/:type/:extends/...,
|
16
|
+
# :doc => "Some documentation for this tag",
|
17
|
+
# ...@tag specific stuff like :name, :type, and so on...
|
18
|
+
# }
|
19
|
+
#
|
20
|
+
# When doc-comment begins with comment, not preceded by @tag, then
|
21
|
+
# the comment will be placed into Hash with :tagname => :default.
|
22
|
+
#
|
23
|
+
# Unrecognized @tags are left as is into documentation as if they
|
24
|
+
# were normal text.
|
25
|
+
#
|
26
|
+
# @example, {@img}, {@link} and {@video} are parsed separately in
|
27
|
+
# JsDuck::DocFormatter.
|
28
|
+
#
|
29
|
+
class Parser < Doc::Scanner
|
30
|
+
def parse(input, filename="", linenr=0)
|
31
|
+
@filename = filename
|
32
|
+
@linenr = linenr
|
33
|
+
@tags = []
|
34
|
+
@input = StringScanner.new(Doc::Comment.purify(input))
|
35
|
+
|
36
|
+
parse_loop
|
37
|
+
|
38
|
+
strip_docs
|
39
|
+
@tags
|
40
|
+
end
|
41
|
+
|
42
|
+
# The parsing process can leave whitespace at the ends of
|
43
|
+
# doc-strings, here we get rid of it.
|
44
|
+
def strip_docs
|
45
|
+
@tags.each do |tag|
|
46
|
+
tag[:doc].strip! if tag[:doc]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# The main loop of the DocParser
|
51
|
+
def parse_loop
|
52
|
+
add_tag({:tagname => :doc, :doc => :multiline})
|
53
|
+
|
54
|
+
while !@input.eos? do
|
55
|
+
if look(/@/)
|
56
|
+
parse_at_tag
|
57
|
+
elsif look(/[^@]/)
|
58
|
+
skip_to_next_at_tag
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# Appends new @tag to parsed tags list
|
64
|
+
def add_tag(tag)
|
65
|
+
@tags << tag
|
66
|
+
|
67
|
+
if tag[:doc] == :multiline
|
68
|
+
tag[:doc] = ""
|
69
|
+
@multiline_tag = tag
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# Processes anything beginning with @-sign.
|
74
|
+
#
|
75
|
+
# - When @ is not followed by any word chars, do nothing.
|
76
|
+
# - When it's one of the builtin tags, process it as such.
|
77
|
+
# - When it's something else, print a warning.
|
78
|
+
#
|
79
|
+
def parse_at_tag
|
80
|
+
match(/@/)
|
81
|
+
name = look(/\w+/)
|
82
|
+
|
83
|
+
if !name
|
84
|
+
# ignore
|
85
|
+
elsif tag = TagRegistry.get_by_pattern(name)
|
86
|
+
match(/\w+/)
|
87
|
+
hw # Skip the whitespace right after the tag.
|
88
|
+
|
89
|
+
tags = tag.parse_doc(self)
|
90
|
+
if tags.is_a?(Hash)
|
91
|
+
add_tag(tags)
|
92
|
+
elsif tags.is_a?(Array)
|
93
|
+
tags.each {|t| add_tag(t) }
|
94
|
+
end
|
95
|
+
|
96
|
+
skip_white
|
97
|
+
else
|
98
|
+
Logger.warn(:tag, "Unsupported tag: @#{name}", @filename, @linenr)
|
99
|
+
@multiline_tag[:doc] += "@"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# Skips until the beginning of next @tag.
|
104
|
+
#
|
105
|
+
# There must be space before the next @tag - this ensures that we
|
106
|
+
# don't detect tags inside "foo@example.com" or "{@link}".
|
107
|
+
#
|
108
|
+
# Also check that the @tag is not part of an indented code block -
|
109
|
+
# in which case we also ignore the tag.
|
110
|
+
def skip_to_next_at_tag
|
111
|
+
@multiline_tag[:doc] += match(/[^@]+/)
|
112
|
+
|
113
|
+
while look(/@/) && (!prev_char_is_whitespace? || indented_as_code?)
|
114
|
+
@multiline_tag[:doc] += match(/@+[^@]+/)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def prev_char_is_whitespace?
|
119
|
+
@multiline_tag[:doc][-1,1] =~ /\s/
|
120
|
+
end
|
121
|
+
|
122
|
+
def indented_as_code?
|
123
|
+
@multiline_tag[:doc] =~ /^ {4,}[^\n]*\z/
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'jsduck/tag_registry'
|
2
|
+
|
3
|
+
module JsDuck
|
4
|
+
module Doc
|
5
|
+
|
6
|
+
# Processes @tag data detected from doc-comment, transforming it
|
7
|
+
# into a class/member hash which can be then later further merged
|
8
|
+
# with code hash.
|
9
|
+
#
|
10
|
+
# Its main work is done through calling the #process_doc method of
|
11
|
+
# all the Tag classes that have registered themselves to process a
|
12
|
+
# particular set of @tags through defining a .tagname attribute.
|
13
|
+
class Processor
|
14
|
+
# Allow passing in filename and line for error reporting
|
15
|
+
attr_accessor :filename
|
16
|
+
attr_accessor :linenr
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
@filename = ""
|
20
|
+
@linenr = 0
|
21
|
+
end
|
22
|
+
|
23
|
+
# Given tagname and map of tags from DocParser, produces docs
|
24
|
+
# of the type determined by tagname.
|
25
|
+
def process(tagname, doc_map)
|
26
|
+
hash = {
|
27
|
+
:tagname => tagname,
|
28
|
+
:doc => extract_doc(doc_map),
|
29
|
+
}
|
30
|
+
|
31
|
+
position = {:filename => @filename, :linenr => @linenr}
|
32
|
+
|
33
|
+
doc_map.each_pair do |name, value|
|
34
|
+
if tag = TagRegistry.get_by_name(name)
|
35
|
+
tag.process_doc(hash, value, position)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
return hash
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def extract_doc(doc_map)
|
45
|
+
tag = doc_map[:doc] ? doc_map[:doc].first : {}
|
46
|
+
return tag[:doc] || ""
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'jsduck/doc/standard_tag_parser'
|
2
|
+
|
3
|
+
module JsDuck
|
4
|
+
module Doc
|
5
|
+
|
6
|
+
# Abstract base class for parsing doc-comments.
|
7
|
+
#
|
8
|
+
# The methods of this class are to be called from implementations
|
9
|
+
# of concrete @tags. Although the @tag classes will get passed an
|
10
|
+
# instance of Doc::Parser, only methods of Doc::Scanner should be
|
11
|
+
# called by them.
|
12
|
+
#
|
13
|
+
class Scanner
|
14
|
+
def initialize
|
15
|
+
@ident_pattern = /[$\w-]+/
|
16
|
+
@ident_chain_pattern = /[$\w-]+(\.[$\w-]+)*/
|
17
|
+
|
18
|
+
@input = nil # set to StringScanner in subclass
|
19
|
+
end
|
20
|
+
|
21
|
+
# Provides access to StringScanner
|
22
|
+
attr_reader :input
|
23
|
+
|
24
|
+
# Parses standard pattern common in several builtin tags, which
|
25
|
+
# goes like this:
|
26
|
+
#
|
27
|
+
# @tag {Type} [some.name=default]
|
28
|
+
#
|
29
|
+
# See StandardTagParser#parse for details.
|
30
|
+
#
|
31
|
+
def standard_tag(cfg)
|
32
|
+
Doc::StandardTagParser.new(self).parse(cfg)
|
33
|
+
end
|
34
|
+
|
35
|
+
# matches chained.identifier.name and returns it
|
36
|
+
def ident_chain
|
37
|
+
@input.scan(@ident_chain_pattern)
|
38
|
+
end
|
39
|
+
|
40
|
+
# matches identifier and returns its name
|
41
|
+
def ident
|
42
|
+
@input.scan(@ident_pattern)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Looks for the existance of pattern. Returns the matching
|
46
|
+
# string on success, nil on failure, but doesn't advance the
|
47
|
+
# scan pointer.
|
48
|
+
def look(re)
|
49
|
+
@input.check(re)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Matches the given pattern and advances the scan pointer
|
53
|
+
# returning the string that matched. When the pattern doesn't
|
54
|
+
# match, nil is returned.
|
55
|
+
def match(re)
|
56
|
+
@input.scan(re)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Skips all whitespace. Moves scan pointer to next non-whitespace
|
60
|
+
# character.
|
61
|
+
def skip_white
|
62
|
+
@input.scan(/\s+/)
|
63
|
+
end
|
64
|
+
|
65
|
+
# Skips horizontal whitespace (tabs and spaces). Moves scan
|
66
|
+
# pointer to next non-whitespace character or to the end of line.
|
67
|
+
# Returns self to allow chaining.
|
68
|
+
def hw
|
69
|
+
@input.scan(/[ \t]+/)
|
70
|
+
self
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,154 @@
|
|
1
|
+
module JsDuck
|
2
|
+
module Doc
|
3
|
+
|
4
|
+
# Helper in parsing the standard tag pattern with type definition
|
5
|
+
# followed by name and default value:
|
6
|
+
#
|
7
|
+
# @tag {Type} [some.name=default]
|
8
|
+
#
|
9
|
+
class StandardTagParser
|
10
|
+
# Initialized with Doc::Scanner instance
|
11
|
+
def initialize(doc_scanner)
|
12
|
+
@ds = doc_scanner
|
13
|
+
end
|
14
|
+
|
15
|
+
# Parses the standard tag pattern.
|
16
|
+
#
|
17
|
+
# Takes as parameter a configuration hash which can contain the
|
18
|
+
# following keys:
|
19
|
+
#
|
20
|
+
# - :tagname => The :tagname of the hash to return.
|
21
|
+
#
|
22
|
+
# - :type => True to parse {Type} section.
|
23
|
+
# Produces :type and :optional keys.
|
24
|
+
#
|
25
|
+
# - :name => Trye to parse [some.name=default] section.
|
26
|
+
# Produces :name, :default and :optional keys.
|
27
|
+
#
|
28
|
+
# Returns tag definition hash containing the given :tagname and a
|
29
|
+
# set of other fields depending on whether :type and :name configs
|
30
|
+
# were specified and how their matching succeeded.
|
31
|
+
#
|
32
|
+
def parse(cfg)
|
33
|
+
tag = {:tagname => cfg[:tagname]}
|
34
|
+
add_type(tag) if cfg[:type]
|
35
|
+
add_name_with_default(tag) if cfg[:name]
|
36
|
+
tag
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
# matches {type} if possible and sets it on given tag hash.
|
42
|
+
# Also checks for {optionality=} in type definition.
|
43
|
+
def add_type(tag)
|
44
|
+
if hw.look(/\{/)
|
45
|
+
tdf = typedef
|
46
|
+
tag[:type] = tdf[:type]
|
47
|
+
tag[:optional] = true if tdf[:optional]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# matches {...=} and returns text inside brackets
|
52
|
+
def typedef
|
53
|
+
match(/\{/)
|
54
|
+
|
55
|
+
name = parse_balanced(/\{/, /\}/, /[^{}'"]*/)
|
56
|
+
|
57
|
+
if name =~ /=$/
|
58
|
+
name = name.chop
|
59
|
+
optional = true
|
60
|
+
else
|
61
|
+
optional = nil
|
62
|
+
end
|
63
|
+
|
64
|
+
match(/\}/)
|
65
|
+
|
66
|
+
return {:type => name, :optional => optional}
|
67
|
+
end
|
68
|
+
|
69
|
+
# matches: <ident-chain> | "[" <ident-chain> [ "=" <default-value> ] "]"
|
70
|
+
def add_name_with_default(tag)
|
71
|
+
if hw.match(/\[/)
|
72
|
+
tag[:name] = hw.ident_chain
|
73
|
+
if hw.match(/=/)
|
74
|
+
hw
|
75
|
+
tag[:default] = default_value
|
76
|
+
end
|
77
|
+
hw.match(/\]/)
|
78
|
+
tag[:optional] = true
|
79
|
+
else
|
80
|
+
tag[:name] = hw.ident_chain
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# Attempts to allow balanced braces in default value.
|
85
|
+
# When the nested parsing doesn't finish at closing "]",
|
86
|
+
# roll back to beginning and simply grab anything up to closing "]".
|
87
|
+
def default_value
|
88
|
+
start_pos = @ds.input.pos
|
89
|
+
value = parse_balanced(/\[/, /\]/, /[^\[\]'"]*/)
|
90
|
+
if look(/\]/)
|
91
|
+
value
|
92
|
+
else
|
93
|
+
@ds.input.pos = start_pos
|
94
|
+
match(/[^\]]*/)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# Helper method to parse a string up to a closing brace,
|
99
|
+
# balancing opening-closing braces in between.
|
100
|
+
#
|
101
|
+
# @param re_open The beginning brace regex
|
102
|
+
# @param re_close The closing brace regex
|
103
|
+
# @param re_rest Regex to match text without any braces and strings
|
104
|
+
def parse_balanced(re_open, re_close, re_rest)
|
105
|
+
result = parse_with_strings(re_rest)
|
106
|
+
while look(re_open)
|
107
|
+
result += match(re_open)
|
108
|
+
result += parse_balanced(re_open, re_close, re_rest)
|
109
|
+
result += match(re_close)
|
110
|
+
result += parse_with_strings(re_rest)
|
111
|
+
end
|
112
|
+
result
|
113
|
+
end
|
114
|
+
|
115
|
+
# Helper for parse_balanced to parse rest of the text between
|
116
|
+
# braces, taking account the strings which might occur there.
|
117
|
+
def parse_with_strings(re_rest)
|
118
|
+
result = match(re_rest)
|
119
|
+
while look(/['"]/)
|
120
|
+
result += parse_string('"') if look(/"/)
|
121
|
+
result += parse_string("'") if look(/'/)
|
122
|
+
result += match(re_rest)
|
123
|
+
end
|
124
|
+
result
|
125
|
+
end
|
126
|
+
|
127
|
+
# Parses "..." or '...' including the escape sequence \' or '\"
|
128
|
+
def parse_string(quote)
|
129
|
+
re_quote = Regexp.new(quote)
|
130
|
+
re_rest = Regexp.new("(?:[^"+quote+"\\\\]|\\\\.)*")
|
131
|
+
match(re_quote) + match(re_rest) + (match(re_quote) || "")
|
132
|
+
end
|
133
|
+
|
134
|
+
### Forward these calls to Doc::Scanner
|
135
|
+
|
136
|
+
def ident_chain
|
137
|
+
@ds.ident_chain
|
138
|
+
end
|
139
|
+
|
140
|
+
def look(re)
|
141
|
+
@ds.look(re)
|
142
|
+
end
|
143
|
+
|
144
|
+
def match(re)
|
145
|
+
@ds.match(re)
|
146
|
+
end
|
147
|
+
|
148
|
+
def hw
|
149
|
+
@ds.hw
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
154
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'jsduck/util/singleton'
|
2
|
+
require 'jsduck/logger'
|
3
|
+
|
4
|
+
module JsDuck
|
5
|
+
module Doc
|
6
|
+
|
7
|
+
# Detects nested structure of subproperties.
|
8
|
+
class Subproperties
|
9
|
+
include Util::Singleton
|
10
|
+
|
11
|
+
# Given array of e.g. @param tags from Doc::Parser with names
|
12
|
+
# containing dots:
|
13
|
+
#
|
14
|
+
# {:name => "foo"},
|
15
|
+
# {:name => "foo.bar"},
|
16
|
+
# {:name => "foo.baz"},
|
17
|
+
# {:name => "zap"},
|
18
|
+
#
|
19
|
+
# Produces nested structure:
|
20
|
+
#
|
21
|
+
# {:name => "foo", :properties => [
|
22
|
+
# {:name => "bar"},
|
23
|
+
# {:name => "baz"}]},
|
24
|
+
# {:name => "zap"},
|
25
|
+
#
|
26
|
+
# Secondly it takes a position argument which is used for
|
27
|
+
# logging warnings when bogus subproperty syntax is encountered.
|
28
|
+
def nest(raw_items, pos)
|
29
|
+
# First item can't be namespaced, if it is ignore the rest.
|
30
|
+
if raw_items[0] && raw_items[0][:name] =~ /\./
|
31
|
+
return [raw_items[0]]
|
32
|
+
end
|
33
|
+
|
34
|
+
# build name-index of all items
|
35
|
+
index = {}
|
36
|
+
raw_items.each {|it| index[it[:name]] = it }
|
37
|
+
|
38
|
+
# If item name has no dots, add it directly to items array.
|
39
|
+
# Otherwise look up the parent of item and add it as the
|
40
|
+
# property of that parent.
|
41
|
+
items = []
|
42
|
+
raw_items.each do |it|
|
43
|
+
if it[:name] =~ /^(.+)\.([^.]+)$/
|
44
|
+
it[:name] = $2
|
45
|
+
parent = index[$1]
|
46
|
+
if parent
|
47
|
+
parent[:properties] = [] unless parent[:properties]
|
48
|
+
parent[:properties] << it
|
49
|
+
else
|
50
|
+
msg = "Ignoring subproperty #{$1}.#{$2}, no parent found with name '#{$1}'."
|
51
|
+
Logger.warn(:subproperty, msg, pos[:filename], pos[:linenr])
|
52
|
+
end
|
53
|
+
else
|
54
|
+
items << it
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
return items
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|