jsduck 4.5.1 → 4.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 ""