jsduck 3.4.1 → 3.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -20,7 +20,12 @@ module JsDuck
20
20
  h[:superclasses] = cls.superclasses.collect {|c| c.full_name }
21
21
  h[:subclasses] = @relations.subclasses(cls).collect {|c| c.full_name }
22
22
  h[:mixedInto] = @relations.mixed_into(cls).collect {|c| c.full_name }
23
- h[:allMixins] = cls.all_mixins.collect {|c| c.full_name }
23
+
24
+ h[:mixins] = cls.deps(:mixins).collect {|c| c.full_name }
25
+ h[:parentMixins] = cls.parent_deps(:mixins).collect {|c| c.full_name }
26
+ h[:requires] = cls.deps(:requires).collect {|c| c.full_name }
27
+ h[:uses] = cls.deps(:uses).collect {|c| c.full_name }
28
+
24
29
  h
25
30
  end
26
31
 
@@ -0,0 +1,41 @@
1
+ require 'jsduck/logger'
2
+
3
+ module JsDuck
4
+
5
+ # Parent class for assets that consist of groups.
6
+ # That is: guides, vides, examples.
7
+ #
8
+ # Subclasses must initialize @groups before calling any of the
9
+ # methods in this class.
10
+ class GroupedAsset
11
+ # Should be called from constructor after @groups have been read in,
12
+ # and after it's been ensured that all items in groupes have names.
13
+ def build_map_by_name(warning_msg)
14
+ @map_by_name = {}
15
+ each_item do |item|
16
+ if @map_by_name[item["name"]]
17
+ Logger.instance.warn(nil, "#{warning_msg} '#{item['name']}'")
18
+ end
19
+ @map_by_name[item["name"]] = item
20
+ end
21
+ end
22
+
23
+ # Accesses item by name
24
+ def [](name)
25
+ @map_by_name[name]
26
+ end
27
+
28
+ # Iterates over all items in all groups
29
+ def each_item
30
+ @groups.each do |group|
31
+ group["items"].each {|item| yield item }
32
+ end
33
+ end
34
+
35
+ # Returns all groups as array
36
+ def to_array
37
+ @groups
38
+ end
39
+ end
40
+
41
+ end
data/lib/jsduck/guides.rb CHANGED
@@ -1,35 +1,38 @@
1
1
  require 'jsduck/logger'
2
2
  require 'jsduck/json_duck'
3
3
  require 'jsduck/null_object'
4
+ require 'jsduck/logger'
5
+ require 'jsduck/grouped_asset'
4
6
  require 'fileutils'
5
7
 
6
8
  module JsDuck
7
9
 
8
10
  # Reads in guides and converts them to JsonP files
9
- class Guides
11
+ class Guides < GroupedAsset
10
12
  # Creates Guides object from filename and formatter
11
13
  def self.create(filename, formatter)
12
14
  if filename
13
15
  Guides.new(filename, formatter)
14
16
  else
15
- NullObject.new(:to_array => [], :to_html => "")
17
+ NullObject.new(:to_array => [], :to_html => "", :[] => nil)
16
18
  end
17
19
  end
18
20
 
19
21
  # Parses guides config file
20
22
  def initialize(filename, formatter)
21
23
  @path = File.dirname(filename)
22
- @guides = JsonDuck.read(filename)
24
+ @groups = JsonDuck.read(filename)
25
+ build_map_by_name("Two guides have the same name")
23
26
  @formatter = formatter
24
27
  end
25
28
 
26
29
  # Writes all guides to given dir in JsonP format
27
30
  def write(dir)
28
31
  FileUtils.mkdir(dir) unless File.exists?(dir)
29
- @guides.each {|group| group["items"].each {|g| write_guide(g, dir) } }
32
+ each_item {|guide| write_guide(guide, dir) }
30
33
  # Write the JSON to output dir, so it's available in released
31
34
  # version of docs and people can use it with JSDuck by themselves.
32
- JsonDuck.write_json(dir+"/guides.json", @guides)
35
+ JsonDuck.write_json(dir+"/guides.json", @groups)
33
36
  end
34
37
 
35
38
  def write_guide(guide, dir)
@@ -63,8 +66,9 @@ module JsDuck
63
66
  # Creates table of contents at the top of guide by looking for <h2> elements in HTML.
64
67
  def add_toc(guide, html)
65
68
  toc = [
69
+ "<div class='toc'>\n",
66
70
  "<p><strong>Contents</strong></p>\n",
67
- "<ul class='toc'>\n",
71
+ "<ol>\n",
68
72
  ]
69
73
  new_html = []
70
74
  i = 0
@@ -77,20 +81,20 @@ module JsDuck
77
81
  new_html << line
78
82
  end
79
83
  end
80
- toc << "</ul>\n"
81
- # Inject TOC at below first heading
82
- new_html.insert(1, toc)
83
- new_html.flatten.join
84
- end
85
-
86
- # Returns all guides as array
87
- def to_array
88
- @guides
84
+ toc << "</ol>\n"
85
+ toc << "</div>\n"
86
+ # Inject TOC at below first heading if at least 2 items in TOC
87
+ if i >= 2
88
+ new_html.insert(1, toc)
89
+ new_html.flatten.join
90
+ else
91
+ html
92
+ end
89
93
  end
90
94
 
91
95
  # Returns HTML listing of guides
92
96
  def to_html
93
- html = @guides.map do |group|
97
+ html = @groups.map do |group|
94
98
  [
95
99
  "<h3>#{group['title']}</h3>",
96
100
  "<ul>",
@@ -105,6 +109,12 @@ module JsDuck
105
109
  </div>
106
110
  EOHTML
107
111
  end
112
+
113
+ # Extracts guide icon URL from guide hash
114
+ def icon_url(guide)
115
+ "guides/" + guide["name"] + "/icon-lg.png"
116
+ end
117
+
108
118
  end
109
119
 
110
120
  end
@@ -5,11 +5,8 @@ module JsDuck
5
5
 
6
6
  # Deals with creation of main HTML or PHP files.
7
7
  class IndexHtml
8
- attr_accessor :welcome
9
- attr_accessor :categories
10
- attr_accessor :guides
11
-
12
- def initialize(opts)
8
+ def initialize(assets, opts)
9
+ @assets = assets
13
10
  @opts = opts
14
11
  end
15
12
 
@@ -34,9 +31,9 @@ module JsDuck
34
31
  "{header}" => @opts.header,
35
32
  "{footer}" => "<div id='footer-content' style='display: none'>#{@opts.footer}</div>",
36
33
  "{extjs_path}" => @opts.extjs_path,
37
- "{welcome}" => @welcome.to_html,
38
- "{categories}" => @categories.to_html,
39
- "{guides}" => @guides.to_html,
34
+ "{welcome}" => @assets.welcome.to_html,
35
+ "{categories}" => @assets.categories.to_html,
36
+ "{guides}" => @assets.guides.to_html,
40
37
  "{head_html}" => @opts.head_html,
41
38
  "{body_html}" => @opts.body_html,
42
39
  })
data/lib/jsduck/lexer.rb CHANGED
@@ -140,7 +140,7 @@ module JsDuck
140
140
  elsif @input.check(/\//)
141
141
  # Several things begin with dash:
142
142
  # - comments, regexes, division-operators
143
- if @input.check(/\/\*\*/)
143
+ if @input.check(/\/\*\*[^\/]/)
144
144
  return {
145
145
  :type => :doc_comment,
146
146
  # Calculate current line number, starting with 1
data/lib/jsduck/logger.rb CHANGED
@@ -15,7 +15,7 @@ module JsDuck
15
15
  @warning_docs = [
16
16
  [:global, "Member doesn't belong to any class"],
17
17
  [:inheritdoc, "@inheritdoc referring to unknown class or member"],
18
- [:extend, "@extend or @mixin referring to unknown class"],
18
+ [:extend, "@extend/mixin/requires/uses referring to unknown class"],
19
19
  [:link, "{@link} to unknown class or member"],
20
20
  [:link_ambiguous, "{@link} is ambiguous"],
21
21
  [:link_auto, "Auto-detected link to unknown class or member"],
@@ -37,6 +37,7 @@ module JsDuck
37
37
  [:cat_no_match, "Class pattern in categories file matches nothing"],
38
38
  [:cat_class_missing, "Class is missing from categories file"],
39
39
  [:guide, "Guide is missing from --guides dir"],
40
+ [:aside, "Problem with @aside tag"],
40
41
  ]
41
42
  # Turn off all warnings by default.
42
43
  # This is good for testing.
@@ -66,7 +67,7 @@ module JsDuck
66
67
  elsif @warnings.has_key?(type)
67
68
  @warnings[type] = enabled
68
69
  else
69
- warn(nil, "Warning of type '#{type} doesn't exist")
70
+ warn(nil, "Warning of type '#{type}' doesn't exist")
70
71
  end
71
72
  end
72
73
 
data/lib/jsduck/merger.rb CHANGED
@@ -290,14 +290,16 @@ module JsDuck
290
290
  def detect_extends(doc_map, code)
291
291
  if doc_map[:extends]
292
292
  cls = doc_map[:extends].first[:extends]
293
- # Ignore extending of the Object class
294
- cls == "Object" ? nil : cls
295
293
  elsif code[:type] == :assignment && code[:right] && code[:right][:type] == :ext_extend
296
- code[:right][:extend].join(".")
294
+ cls = code[:right][:extend].join(".")
297
295
  elsif code[:type] == :ext_define
298
296
  # Classes defined with Ext.define will automatically inherit from Ext.Base
299
- code[:extend] || "Ext.Base"
297
+ cls = code[:extend] || "Ext.Base"
298
+ else
299
+ cls = nil
300
300
  end
301
+ # Ignore extending of the Object class
302
+ cls == "Object" ? nil : cls
301
303
  end
302
304
 
303
305
  def detect_default(tagname, doc_map, code)
@@ -348,7 +350,7 @@ module JsDuck
348
350
  # it instead of creating a new hash.
349
351
  def build_aliases_hash(aliases, hash={})
350
352
  aliases.each do |a|
351
- if a =~ /^(.+)\.([^.]+)$/
353
+ if a =~ /^([^.]+)\.(.+)$/
352
354
  if hash[$1]
353
355
  hash[$1] << $2
354
356
  else
@@ -26,12 +26,20 @@ module JsDuck
26
26
  # existance of the tag.
27
27
  attr_reader :boolean
28
28
 
29
+ # Whether to render the tag before other content (:top) or after
30
+ # it (:bottom). Defaults to :bottom.
31
+ attr_accessor :position
32
+
29
33
  # Here the appropriate class or member will be injected,
30
34
  # so the to_value and to_html methods can for produce
31
35
  # different output based on whether the tag is inside class,
32
36
  # method, event, etc.
33
37
  attr_accessor :context
34
38
 
39
+ # Here the Assets object will be injected, so the Tag implementation
40
+ # can access guides, videos, etc when he needs to.
41
+ attr_accessor :assets
42
+
35
43
  # It gets passed an array of contents gathered from all meta-tags
36
44
  # of given type. It should return the value to be stored for this
37
45
  # meta-tag at :key. The returned value is also passed to #to_html
@@ -55,9 +55,11 @@ module JsDuck
55
55
 
56
56
  # Instanciates tag class.
57
57
  # When .key is missing, creates it from .name
58
+ # When .position is missing, defaults to :bottom
58
59
  def create_tag(cls)
59
60
  tag = cls.new
60
61
  tag.key = tag.name.to_sym unless tag.key
62
+ tag.position = :bottom unless tag.position
61
63
  tag
62
64
  end
63
65
  end
@@ -31,9 +31,10 @@ module JsDuck
31
31
  register_keys
32
32
  end
33
33
 
34
- # Returns array of all available tag instances
35
- def tags
36
- @tags
34
+ # Returns array of all available tag instances.
35
+ # When position provided, returns only tags in that position
36
+ def tags(position=nil)
37
+ position ? @tags.find_all {|t| t.position == position} : @tags
37
38
  end
38
39
 
39
40
  # Accesses tag by key or name
@@ -52,6 +53,11 @@ module JsDuck
52
53
  @tags.each {|tag| tag.formatter = doc_formatter }
53
54
  end
54
55
 
56
+ # Gives access to assets for all tags
57
+ def assets=(assets)
58
+ @tags.each {|tag| tag.assets = assets }
59
+ end
60
+
55
61
  # Returns array of attributes to be shown in member signatures
56
62
  # (and in order they should be shown in).
57
63
  def signatures
@@ -31,6 +31,7 @@ module JsDuck
31
31
  attr_accessor :export
32
32
  attr_accessor :seo
33
33
  attr_accessor :eg_iframe
34
+ attr_accessor :examples_base_url
34
35
 
35
36
  # Debugging
36
37
  attr_accessor :processes
@@ -71,7 +72,7 @@ module JsDuck
71
72
  ]
72
73
  @meta_tag_paths = []
73
74
 
74
- @version = "3.4.1"
75
+ @version = "3.5.0"
75
76
 
76
77
  # Customizing output
77
78
  @title = "Sencha Docs - Ext JS"
@@ -94,6 +95,7 @@ module JsDuck
94
95
  @export = nil
95
96
  @seo = false
96
97
  @eg_iframe = nil
98
+ @examples_base_url = "extjs/examples/"
97
99
 
98
100
  # Debugging
99
101
  # Turn multiprocessing off by default in Windows
@@ -276,6 +278,11 @@ module JsDuck
276
278
  @eg_iframe = canonical(path)
277
279
  end
278
280
 
281
+ opts.on('--examples-base-url=URL',
282
+ "Base URL for examples with relative URL-s.", " ") do |path|
283
+ @examples_base_url = path
284
+ end
285
+
279
286
  opts.separator "Debugging:"
280
287
  opts.separator ""
281
288
 
@@ -428,7 +435,7 @@ module JsDuck
428
435
  if File.directory?(fname)
429
436
  Dir[fname+"/**/*.{js,css,scss}"].each {|f| @input_files << f }
430
437
  elsif fname =~ /\.jsb3$/
431
- @input_files += extract_jsb_files(fname)
438
+ extract_jsb_files(fname).each {|fn| read_filenames(fn) }
432
439
  else
433
440
  @input_files << fname
434
441
  end
@@ -13,12 +13,13 @@ module JsDuck
13
13
  "<div>",
14
14
  render_sidebar,
15
15
  "<div class='doc-contents'>",
16
+ render_meta_data(@cls[:html_meta], :top),
16
17
  render_private_class_notice,
17
18
  @cls[:doc],
18
- render_meta_data(@cls[:html_meta]),
19
+ render_meta_data(@cls[:html_meta], :bottom),
19
20
  "</div>",
20
21
  "<div class='members'>",
21
- render_member_sections,
22
+ render_all_sections,
22
23
  "</div>",
23
24
  "</div>",
24
25
  ].flatten.compact.join
@@ -33,18 +34,21 @@ module JsDuck
33
34
  ]
34
35
  end
35
36
 
36
- def render_meta_data(meta_data)
37
+ def render_meta_data(meta_data, position)
37
38
  return if meta_data.size == 0
38
39
 
39
- MetaTagRegistry.instance.tags.map {|tag| meta_data[tag.key] }
40
+ MetaTagRegistry.instance.tags(position).map {|tag| meta_data[tag.key] }
40
41
  end
41
42
 
42
43
  def render_sidebar
43
44
  items = [
44
45
  render_alternate_class_names,
45
46
  render_tree,
46
- render_dependencies(:allMixins, "Mixins"),
47
+ render_dependencies(:mixins, "Mixins"),
48
+ render_dependencies(:parentMixins, "Inherited mixins"),
47
49
  render_dependencies(:requires, "Requires"),
50
+ render_dependencies(:subclasses, "Subclasses"),
51
+ render_dependencies(:mixedInto, "Mixed into"),
48
52
  render_dependencies(:uses, "Uses"),
49
53
  render_files,
50
54
  ]
@@ -59,7 +63,7 @@ module JsDuck
59
63
  return if @cls[:alternateClassNames].length == 0
60
64
  return [
61
65
  "<h4>Alternate names</h4>",
62
- @cls[:alternateClassNames].map {|name| "<div class='alternate-class-name'>#{name}</div>" },
66
+ @cls[:alternateClassNames].sort.map {|name| "<div class='alternate-class-name'>#{name}</div>" },
63
67
  ]
64
68
  end
65
69
 
@@ -67,7 +71,7 @@ module JsDuck
67
71
  return if !@cls[type] || @cls[type].length == 0
68
72
  return [
69
73
  "<h4>#{title}</h4>",
70
- @cls[type].map {|name| "<div class='dependency'>#{render_link(name)}</div>" },
74
+ @cls[type].sort.map {|name| "<div class='dependency'>#{name.exists? ? render_link(name) : name}</div>" },
71
75
  ]
72
76
  end
73
77
 
@@ -88,23 +92,21 @@ module JsDuck
88
92
  # We still create the tree, but without links in it.
89
93
  def render_tree
90
94
  return if !@cls[:extends] || @cls[:extends] == "Object"
91
- tree = ["<h4>Hierarchy</h4>"]
92
95
 
93
- if @cls[:superclasses].length > 0
94
- tree + render_class_tree(@cls[:superclasses].concat([@cls[:name]]), {:first => true, :links => true})
95
- else
96
- tree + render_class_tree([@cls[:extends], @cls[:name]], {:first => true})
97
- end
96
+ return [
97
+ "<h4>Hierarchy</h4>",
98
+ render_class_tree(@cls[:superclasses] + [@cls[:name]])
99
+ ]
98
100
  end
99
101
 
100
- def render_class_tree(superclasses, o)
101
- return "" if superclasses.length == 0
102
+ def render_class_tree(classes, i=0)
103
+ return "" if classes.length <= i
102
104
 
103
- name = superclasses[0]
105
+ name = classes[i]
104
106
  return [
105
- "<div class='subclass #{o[:first] ? 'first-child' : ''}'>",
106
- superclasses.length > 1 ? (o[:links] ? render_link(name) : name) : "<strong>#{name}</strong>",
107
- render_class_tree(superclasses.slice(1, superclasses.length-1), {:links => o[:links]}),
107
+ "<div class='subclass #{i == 0 ? 'first-child' : ''}'>",
108
+ classes.length-1 == i ? "<strong>#{name}</strong>" : (name.exists? ? render_link(name) : name),
109
+ render_class_tree(classes, i+1),
108
110
  "</div>",
109
111
  ]
110
112
  end
@@ -115,9 +117,8 @@ module JsDuck
115
117
  return "<a href='#!/api/#{id}' rel='#{id}' class='docClass'>#{label}</a>"
116
118
  end
117
119
 
118
- def render_member_sections
120
+ def render_all_sections
119
121
  sections = [
120
- {:type => :cfg, :title => "Config options"},
121
122
  {:type => :property, :title => "Properties"},
122
123
  {:type => :method, :title => "Methods"},
123
124
  {:type => :event, :title => "Events"},
@@ -125,22 +126,43 @@ module JsDuck
125
126
  {:type => :css_mixin, :title => "CSS Mixins"},
126
127
  ]
127
128
 
129
+ render_configs_section + sections.map {|sec| render_section(sec) }
130
+ end
131
+
132
+ def render_configs_section
133
+ configs = @cls[:members][:cfg] + @cls[:statics][:cfg]
134
+
135
+ if configs.length > 0
136
+ required, optional = configs.partition {|c| c[:meta][:required] }
137
+ return [
138
+ "<div class='members-section'>",
139
+ required.length == 0 ? "<div class='definedBy'>Defined By</div>" : "",
140
+ "<h3 class='members-title icon-cfg'>Config options</h3>",
141
+ render_subsection(required, "Required Config options"),
142
+ render_subsection(optional, required.length > 0 ? "Optional Config options" : nil),
143
+ "</div>",
144
+ ]
145
+ else
146
+ return []
147
+ end
148
+ end
149
+
150
+ def render_section(sec)
151
+ members = @cls[:members][sec[:type]]
152
+ statics = @cls[:statics][sec[:type]]
153
+
128
154
  # Skip rendering empty sections
129
- sections.map do |sec|
130
- members = @cls[:members][sec[:type]]
131
- statics = @cls[:statics][sec[:type]]
132
- if members.length > 0 || statics.length > 0
133
- [
134
- "<div class='members-section'>",
135
- statics.length == 0 ? "<div class='definedBy'>Defined By</div>" : "",
136
- "<h3 class='members-title icon-#{sec[:type]}'>#{sec[:title]}</h3>",
137
- render_subsection(members, statics.length > 0 ? "Instance #{sec[:title]}" : nil),
138
- render_subsection(statics, "Static #{sec[:title]}"),
139
- "</div>",
140
- ]
141
- else
142
- nil
143
- end
155
+ if members.length > 0 || statics.length > 0
156
+ return [
157
+ "<div class='members-section'>",
158
+ statics.length == 0 ? "<div class='definedBy'>Defined By</div>" : "",
159
+ "<h3 class='members-title icon-#{sec[:type]}'>#{sec[:title]}</h3>",
160
+ render_subsection(members, statics.length > 0 ? "Instance #{sec[:title]}" : nil),
161
+ render_subsection(statics, "Static #{sec[:title]}"),
162
+ "</div>",
163
+ ]
164
+ else
165
+ return []
144
166
  end
145
167
  end
146
168
 
@@ -236,13 +258,17 @@ module JsDuck
236
258
  end
237
259
 
238
260
  def render_long_doc(m)
239
- doc = [m[:doc]]
261
+ doc = []
262
+
263
+ doc << render_meta_data(m[:html_meta], :top)
264
+
265
+ doc << m[:doc]
240
266
 
241
267
  if m[:default] && m[:default] != "undefined"
242
268
  doc << "<p>Defaults to: <code>" + CGI.escapeHTML(m[:default]) + "</code></p>"
243
269
  end
244
270
 
245
- doc << render_meta_data(m[:html_meta])
271
+ doc << render_meta_data(m[:html_meta], :bottom)
246
272
 
247
273
  doc << render_params_and_return(m)
248
274