jsduck 4.5.1 → 4.6.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -64,7 +64,7 @@ most sensible place to put it). Now you're ready to install JSDuck:
64
64
  > gem install jsduck
65
65
 
66
66
  [RVM]: https://rvm.io/
67
- [download page]: https://github.com/senchalabs/jsduck/downloads
67
+ [download page]: https://sourceforge.net/projects/jsduck/files/
68
68
  [libs download]: https://github.com/stereobooster/therubyracer/downloads
69
69
 
70
70
  Usage
@@ -172,6 +172,7 @@ Katherine Chu,
172
172
  [burnnat](https://github.com/burnnat),
173
173
  [vjetteam](https://github.com/vjetteam),
174
174
  [Chris Westbrook](https://github.com/cnstaging),
175
+ [Scott Whittaker](https://github.com/scottrobertwhittaker),
175
176
  and many-many others who reported bugs, submitted patches, and
176
177
  provided a lot of useful input.
177
178
 
data/Rakefile CHANGED
@@ -104,7 +104,7 @@ def compress
104
104
  dir = "template-min"
105
105
 
106
106
  # Create JSB3 file for Docs app
107
- system("sencha", "create", "jsb", "-a", "http://localhost/~renesaarsoo/docs/", "-p", "#{dir}/app.jsb3")
107
+ system("sencha", "create", "jsb", "-a", "http://localhost/docs/", "-p", "#{dir}/app.jsb3")
108
108
  # Concatenate files listed in JSB3 file
109
109
  system("sencha", "build", "-p", "#{dir}/app.jsb3", "-d", dir)
110
110
 
@@ -257,8 +257,6 @@ task :sdk => :sass do
257
257
  "--output", OUT_DIR,
258
258
  "--config", "#{SDK_DIR}/extjs/docs/config.json",
259
259
  "--examples-base-url", "extjs-build/examples/",
260
- "--import", "Ext 4.1.3:#{SDK_DIR}/../docs.sencha.com/exports/extjs-4.1.3",
261
- "--import", "Ext 4.2.0",
262
260
  "--seo"
263
261
  )
264
262
  runner.add_debug
@@ -2,8 +2,8 @@ Gem::Specification.new do |s|
2
2
  s.required_rubygems_version = ">= 1.3.5"
3
3
 
4
4
  s.name = 'jsduck'
5
- s.version = '4.5.1'
6
- s.date = '2012-12-07'
5
+ s.version = '4.6.0'
6
+ s.date = '2013-01-09'
7
7
  s.summary = "Simple JavaScript Duckumentation generator"
8
8
  s.description = "Documentation generator for Sencha JS frameworks"
9
9
  s.homepage = "https://github.com/senchalabs/jsduck"
@@ -22,7 +22,7 @@ Gem::Specification.new do |s|
22
22
  s.add_dependency 'rdiscount'
23
23
  s.add_dependency 'json'
24
24
  s.add_dependency 'parallel'
25
- s.add_dependency 'therubyracer', '= 0.10.1'
25
+ s.add_dependency 'therubyracer', '>= 0.10.0', '< 0.11.0'
26
26
 
27
27
  s.add_development_dependency 'rspec'
28
28
  s.add_development_dependency 'rake'
@@ -9,6 +9,7 @@ require 'jsduck/inherit_doc'
9
9
  require 'jsduck/importer'
10
10
  require 'jsduck/return_values'
11
11
  require 'jsduck/lint'
12
+ require 'jsduck/circular_deps'
12
13
 
13
14
  module JsDuck
14
15
 
@@ -95,6 +96,7 @@ module JsDuck
95
96
 
96
97
  # Do all kinds of post-processing on relations.
97
98
  def apply_extra_processing
99
+ CircularDeps.new(@relations).check_all
98
100
  InheritDoc.new(@relations).resolve_all
99
101
  Importer.import(@opts.imports, @relations, @opts.new_since)
100
102
  ReturnValues.auto_detect(@relations)
@@ -1,7 +1,24 @@
1
+ require 'jsduck/logger'
2
+
1
3
  module JsDuck
2
4
 
3
5
  # Checks for circular dependencies
4
6
  class CircularDeps
7
+ def initialize(classes)
8
+ @classes = classes
9
+ end
10
+
11
+ # Checks all classes for circular dependencies.
12
+ #
13
+ # When found, exits with a fatal error message.
14
+ def check_all
15
+ @classes.each do |cls|
16
+ if chain = check(cls)
17
+ Logger.fatal("Class #{cls[:name]} has a circular dependency: #{chain}")
18
+ exit 1
19
+ end
20
+ end
21
+ end
5
22
 
6
23
  # Checks class for circular dependencies.
7
24
  #
@@ -2,6 +2,7 @@ require 'jsduck/type_parser'
2
2
  require 'jsduck/logger'
3
3
  require 'jsduck/meta_tag_registry'
4
4
  require 'jsduck/shortener'
5
+ require 'jsduck/util/html'
5
6
 
6
7
  module JsDuck
7
8
 
@@ -80,7 +81,7 @@ module JsDuck
80
81
  else
81
82
  Logger.warn(:type_name, "Unknown type #{type}", context[:filename], context[:linenr])
82
83
  end
83
- type
84
+ Util::HTML.escape(type)
84
85
  end
85
86
  end
86
87
 
@@ -257,9 +257,10 @@ module JsDuck
257
257
  end
258
258
 
259
259
  def detect_return(doc_map)
260
+ has_return_tag = !!extract(doc_map, :return)
260
261
  ret = extract(doc_map, :return) || {}
261
262
  return {
262
- :type => ret[:type] || "undefined",
263
+ :type => ret[:type] || (has_return_tag ? "Object" : "undefined"),
263
264
  :name => ret[:name] || "return",
264
265
  :doc => ret[:doc] || "",
265
266
  :properties => doc_map[:return] ? detect_subproperties(:return, doc_map[:return]) : []
@@ -1,6 +1,7 @@
1
1
  require 'rubygems'
2
2
  require 'strscan'
3
3
  require 'rdiscount'
4
+ require 'jsduck/html_stack'
4
5
  require 'jsduck/inline/link'
5
6
  require 'jsduck/inline/img'
6
7
  require 'jsduck/inline/video'
@@ -15,10 +16,12 @@ module JsDuck
15
16
  # command line. For the actual effect of the options see
16
17
  # Inline::* classes.
17
18
  def initialize(opts={})
19
+ @opts = opts
18
20
  @inline_link = Inline::Link.new(opts)
19
21
  @inline_img = Inline::Img.new(opts)
20
22
  @inline_video = Inline::Video.new(opts)
21
23
  @inline_example = Inline::Example.new(opts)
24
+ @doc_context = {}
22
25
  end
23
26
 
24
27
  # Sets base path to prefix images from {@img} tags.
@@ -41,13 +44,14 @@ module JsDuck
41
44
  # Sets up instance to work in context of particular doc object.
42
45
  # Used for error reporting.
43
46
  def doc_context=(doc)
47
+ @doc_context = doc
44
48
  @inline_video.doc_context = doc
45
49
  @inline_link.doc_context = doc
46
50
  end
47
51
 
48
52
  # Returns the current documentation context
49
53
  def doc_context
50
- @inline_link.doc_context
54
+ @doc_context
51
55
  end
52
56
 
53
57
  # JsDuck::Relations for looking up class names.
@@ -94,10 +98,10 @@ module JsDuck
94
98
  s = StringScanner.new(input)
95
99
  out = ""
96
100
 
97
- # Keep track of the nesting level of <a> tags. We're not
98
- # auto-detecting class names when inside <a>. Normally links
99
- # shouldn't be nested, but just to be extra safe.
100
- open_a_tags = 0
101
+ # Keep track of open HTML tags. We're not auto-detecting class
102
+ # names when inside <a>. Also we want to close down the unclosed
103
+ # tags.
104
+ tags = HtmlStack.new(@opts[:ignore_html] || {}, @doc_context)
101
105
 
102
106
  while !s.eos? do
103
107
  if substitute = @inline_link.replace(s)
@@ -111,26 +115,24 @@ module JsDuck
111
115
  out += s.scan(/[{]/)
112
116
  elsif substitute = @inline_example.replace(s)
113
117
  out += substitute
114
- elsif s.check(/<a\b/)
115
- # Increment number of open <a> tags.
116
- open_a_tags += 1
117
- out += s.scan_until(/>|\Z/)
118
- elsif s.check(/<\/a>/)
119
- # <a> closed, auto-detection may continue when no more <a> tags open.
120
- open_a_tags -= 1
121
- out += s.scan(/<\/a>/)
118
+ elsif s.check(/<\w/)
119
+ # Open HTML tag
120
+ out += s.scan(/</) + tags.open(s.scan(/\w+/)) + s.scan_until(/>|\Z/)
121
+ elsif s.check(/<\/\w+>/)
122
+ # Close HTML tag
123
+ out += s.scan(/<\//) + tags.close(s.scan(/\w+/)) + s.scan(/>/)
122
124
  elsif s.check(/</)
123
- # Ignore all other HTML tags
124
- out += s.scan_until(/>|\Z/)
125
+ # Ignore plain '<' char.
126
+ out += s.scan(/</)
125
127
  else
126
128
  # Replace class names in the following text up to next "<" or "{"
127
129
  # but only when we're not inside <a>...</a>
128
130
  text = s.scan(/[^{<]+/)
129
- out += open_a_tags > 0 ? text : @inline_link.create_magic_links(text)
131
+ out += tags.open?("a") ? text : @inline_link.create_magic_links(text)
130
132
  end
131
133
  end
132
134
 
133
- out
135
+ out + tags.close_unfinished
134
136
  end
135
137
 
136
138
  # Creates a link based on the link template.
@@ -506,7 +506,7 @@ module JsDuck
506
506
  # roll back to beginning and simply grab anything up to closing "]".
507
507
  def default_value
508
508
  start_pos = @input.pos
509
- value = parse_balanced(/\[/, /\]/, /[^\[\]]*/)
509
+ value = parse_balanced(/\[/, /\]/, /[^\[\]'"]*/)
510
510
  if look(/\]/)
511
511
  value
512
512
  else
@@ -519,7 +519,7 @@ module JsDuck
519
519
  def typedef
520
520
  match(/\{/)
521
521
 
522
- name = parse_balanced(/\{/, /\}/, /[^{}]*/)
522
+ name = parse_balanced(/\{/, /\}/, /[^{}'"]*/)
523
523
 
524
524
  if name =~ /=$/
525
525
  name = name.chop
@@ -538,18 +538,37 @@ module JsDuck
538
538
  #
539
539
  # @param re_open The beginning brace regex
540
540
  # @param re_close The closing brace regex
541
- # @param re_rest Regex to match text without any braces
541
+ # @param re_rest Regex to match text without any braces and strings
542
542
  def parse_balanced(re_open, re_close, re_rest)
543
- result = match(re_rest)
543
+ result = parse_with_strings(re_rest)
544
544
  while look(re_open)
545
545
  result += match(re_open)
546
546
  result += parse_balanced(re_open, re_close, re_rest)
547
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(/'/)
548
560
  result += match(re_rest)
549
561
  end
550
562
  result
551
563
  end
552
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
+
553
572
  # matches <ident_chain> <ident_chain> ... until line end
554
573
  def class_list
555
574
  skip_horiz_white
@@ -59,8 +59,7 @@ module JsDuck
59
59
 
60
60
  begin
61
61
  @formatter.doc_context = {:filename => guide_file, :linenr => 0}
62
- name = File.basename(guide["url"])
63
- @formatter.img_path = "guides/#{name}"
62
+ @formatter.img_path = "guides/#{guide["name"]}"
64
63
 
65
64
  return add_toc(guide, @formatter.format(Util::IO.read(guide_file)))
66
65
  rescue
@@ -0,0 +1,91 @@
1
+ require 'jsduck/logger'
2
+
3
+ module JsDuck
4
+
5
+ # Tracks opening and closing of HTML tags, with the purpose of
6
+ # closing down the unfinished tags.
7
+ #
8
+ # Synopsis:
9
+ #
10
+ # tags = HtmlStack.new
11
+ # # open and close a bunch of tags
12
+ # tags.open("a")
13
+ # tags.open("b")
14
+ # tags.close("b")
15
+ #
16
+ # # ask which tags still need to be closed
17
+ # tags.close_unfinished --> "</a>"
18
+ #
19
+ class HtmlStack
20
+
21
+ # Initializes the stack with two optional parameters:
22
+ #
23
+ # @param ignore_html A hash of additional HTML tags that don't need closing.
24
+ # @param doc_context Filename and linenr of the current doc-comment.
25
+ def initialize(ignore_html={}, doc_context={})
26
+ @ignore_html = ignore_html
27
+ @doc_context = doc_context
28
+ @open_tags = []
29
+ end
30
+
31
+ # Registers opening of a tag. Returns the tag.
32
+ def open(tag)
33
+ @open_tags.unshift(tag) unless void?(tag)
34
+ tag
35
+ end
36
+
37
+ # Registers closing of a tag. Returns the tag.
38
+ def close(tag)
39
+ if @open_tags.include?(tag)
40
+ # delete the most recent unclosed tag in our tags stack
41
+ @open_tags.delete_at(@open_tags.index(tag))
42
+ end
43
+ tag
44
+ end
45
+
46
+ # True when the tag is currently open.
47
+ def open?(tag)
48
+ @open_tags.include?(tag)
49
+ end
50
+
51
+ # Returns HTML for closing the still open tags.
52
+ # Also prints warnings for all the unclosed tags.
53
+ def close_unfinished
54
+ return "" if @open_tags.length == 0
55
+
56
+ warn_unfinished
57
+
58
+ @open_tags.map {|tag| "</#{tag}>" }.join
59
+ end
60
+
61
+ private
62
+
63
+ def warn_unfinished
64
+ ctx = @doc_context
65
+ tag_list = @open_tags.map {|tag| "<#{tag}>" }.join(", ")
66
+ Logger.warn(:html, "Unclosed HTML tag: #{tag_list}", ctx[:filename], ctx[:linenr])
67
+ end
68
+
69
+ def void?(tag)
70
+ VOID_TAGS[tag] || @ignore_html[tag]
71
+ end
72
+
73
+ # Tags that don't require closing
74
+ VOID_TAGS = {
75
+ "base" => true,
76
+ "link" => true,
77
+ "meta" => true,
78
+ "hr" => true,
79
+ "br" => true,
80
+ "wbr" => true,
81
+ "area" => true,
82
+ "img" => true,
83
+ "param" => true,
84
+ "input" => true,
85
+ "isindex" => true,
86
+ "option" => true,
87
+ }
88
+
89
+ end
90
+
91
+ end
@@ -1,6 +1,5 @@
1
1
  require 'jsduck/logger'
2
2
  require 'jsduck/class'
3
- require 'jsduck/circular_deps'
4
3
 
5
4
  module JsDuck
6
5
 
@@ -21,7 +20,6 @@ module JsDuck
21
20
  warn_duplicate_members
22
21
  warn_singleton_statics
23
22
  warn_empty_enums
24
- fail_on_circular_dependencies
25
23
  end
26
24
 
27
25
  # print warning for each member or parameter with no name
@@ -119,17 +117,6 @@ module JsDuck
119
117
  end
120
118
  end
121
119
 
122
- # Print fatal error message for circular dependency.
123
- def fail_on_circular_dependencies
124
- circular_deps = CircularDeps.new
125
- @relations.each do |cls|
126
- if chain = circular_deps.check(cls)
127
- Logger.fatal("Class #{cls[:name]} has a circular dependency: #{chain}")
128
- exit 1
129
- end
130
- end
131
- end
132
-
133
120
  # Loops through all members of all classes
134
121
  def each_member(&block)
135
122
  @relations.each {|cls| cls.all_local_members.each(&block) }
@@ -20,6 +20,7 @@ module JsDuck
20
20
  [:link, "{@link} to unknown class or member"],
21
21
  [:link_ambiguous, "{@link} is ambiguous"],
22
22
  [:link_auto, "Auto-detected link to unknown class or member"],
23
+ [:html, "Unclosed HTML tag."],
23
24
 
24
25
  [:alt_name, "Name used as both classname and alternate classname"],
25
26
  [:name_missing, "Member or parameter has no name"],
@@ -39,6 +39,7 @@ module JsDuck
39
39
  attr_accessor :tests
40
40
  attr_accessor :comments_url
41
41
  attr_accessor :comments_domain
42
+ attr_accessor :ignore_html
42
43
 
43
44
  # Debugging
44
45
  attr_accessor :template_dir
@@ -90,7 +91,7 @@ module JsDuck
90
91
  @ext4_events = nil
91
92
  @meta_tag_paths = []
92
93
 
93
- @version = "4.5.1"
94
+ @version = "4.6.0"
94
95
 
95
96
  # Customizing output
96
97
  @title = "Documentation - JSDuck"
@@ -116,6 +117,7 @@ module JsDuck
116
117
  @tests = false
117
118
  @comments_url = nil
118
119
  @comments_domain = nil
120
+ @ignore_html = {}
119
121
 
120
122
  # Debugging
121
123
  @root_dir = File.dirname(File.dirname(File.dirname(__FILE__)))
@@ -539,6 +541,21 @@ module JsDuck
539
541
  @touch_examples_ui = true
540
542
  end
541
543
 
544
+ opts.on('--ignore-html=TAG',
545
+ "Ignore a particular unclosed HTML tag.",
546
+ "",
547
+ "Normally all tags like <foo> that aren't followed at some",
548
+ "point with </foo> will get automatically closed by JSDuck",
549
+ "and a warning will be generated. Except standard void tags",
550
+ "like <img> and <br>. Use this option to specify additional",
551
+ "tags not requirering a closing tag.",
552
+ "",
553
+ "Useful for ignoring the ExtJS preprocessor directives",
554
+ "<locale> and <debug> which would otherwise be reported",
555
+ "as unclosed tags.") do |tag|
556
+ @ignore_html[tag] = true
557
+ end
558
+
542
559
  opts.separator ""
543
560
  opts.separator "Debugging:"
544
561
  opts.separator ""