jsduck 3.4.1 → 3.5.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.
@@ -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