jsduck 3.0.1 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,34 @@
1
+ require 'jsduck/json_duck'
2
+ require 'jsduck/icons'
3
+ require 'jsduck/search_data'
4
+ require 'jsduck/stats'
5
+
6
+ module JsDuck
7
+
8
+ # Creates big JS file with data for Docs app.
9
+ class AppData
10
+ attr_accessor :guides
11
+ attr_accessor :videos
12
+ attr_accessor :examples
13
+
14
+ def initialize(relations, opts)
15
+ @relations = relations
16
+ @opts = opts
17
+ end
18
+
19
+ # Writes classes, guides, videos, and search data to one big .js file
20
+ def write(filename)
21
+ js = "Docs.data = " + JsonDuck.generate({
22
+ :classes => Icons.new.create(@relations.classes),
23
+ :guides => @guides.to_array,
24
+ :videos => @videos.to_array,
25
+ :examples => @examples.to_array,
26
+ :search => SearchData.new.create(@relations.classes),
27
+ :stats => @opts.stats ? Stats.new.create(@relations.classes) : [],
28
+ }) + ";\n"
29
+ File.open(filename, 'w') {|f| f.write(js) }
30
+ end
31
+
32
+ end
33
+
34
+ end
@@ -1,29 +1,31 @@
1
+ require 'jsduck/full_exporter'
2
+ require 'jsduck/renderer'
3
+ require 'jsduck/doc_formatter'
4
+
1
5
  module JsDuck
2
6
 
3
- # Export class data as hash with :cfg being replace with :cfgs and
4
- # including all the inherited members too. Same for :properties,
5
- # :methods, and :events.
6
- class Exporter
7
- def initialize(relations)
8
- @relations = relations
7
+ # Exports data for Docs app.
8
+ class AppExporter < FullExporter
9
+ def initialize(relations, opts)
10
+ super(relations, opts)
11
+
12
+ @renderer = Renderer.new
13
+ # Inject formatter to all meta-tags.
14
+ doc_formatter = DocFormatter.new(relations, opts)
15
+ opts.meta_tags.each {|tag| tag.formatter = doc_formatter }
16
+ @renderer.meta_tags = opts.meta_tags
9
17
  end
10
18
 
11
- # Returns all data in Class object as hash.
19
+ # Returns compacted class data hash which contains an additional
20
+ # :html field with full HTML to show on class overview page.
12
21
  def export(cls)
13
- h = cls.to_hash
14
- h[:members] = {}
15
- Class.default_members_hash.each_key do |key|
16
- h[:members][key] = cls.members(key)
17
- h[:statics][key] = cls.members(key, :statics)
18
- end
19
- h[:component] = cls.inherits_from?("Ext.Component")
20
- h[:superclasses] = cls.superclasses.collect {|c| c.full_name }
21
- h[:subclasses] = @relations.subclasses(cls).collect {|c| c.full_name }
22
- h[:mixedInto] = @relations.mixed_into(cls).collect {|c| c.full_name }
23
- h[:allMixins] = cls.all_mixins.collect {|c| c.full_name }
24
- h
22
+ data = super(cls)
23
+ data[:html] = @renderer.render(data)
24
+ return compact(data)
25
25
  end
26
26
 
27
+ private
28
+
27
29
  # removes extra data from export
28
30
  def compact(cls)
29
31
  cls.delete(:doc)
@@ -1,81 +1,32 @@
1
1
  require 'jsduck/logger'
2
2
  require 'jsduck/json_duck'
3
+ require 'jsduck/file_categories'
3
4
  require 'jsduck/auto_categories'
4
5
 
5
6
  module JsDuck
6
7
 
7
8
  # Reads in categories and outputs them as HTML div
8
9
  class Categories
9
- def initialize(doc_formatter, relations={})
10
- @doc_formatter = doc_formatter
11
- @relations = relations
12
- @categories = []
13
- end
14
-
15
- # Automatically divides all available classes into categories
16
- def auto_generate
17
- @categories = AutoCategories.new(@relations).generate
18
- end
19
-
20
- # Parses categories in JSON file
21
- def parse(path)
22
- @categories = JsonDuck.read(path)
23
-
24
- # Don't crash if old syntax is used.
25
- if @categories.is_a?(Hash) && @categories["categories"]
26
- Logger.instance.warn('Update categories file to contain just the array inside {"categories": [...]}')
27
- @categories = @categories["categories"]
28
- end
29
-
30
- # Perform expansion on all class names containing * wildcard
31
- @categories.each do |cat|
32
- cat["groups"].each do |group|
33
- group["classes"] = group["classes"].map do |name|
34
- expand(name) # name =~ /\*/ ? expand(name) : name
35
- end.flatten
36
- end
37
- end
38
-
39
- validate
40
- end
41
-
42
- # Expands class name like 'Foo.*' into multiple class names.
43
- def expand(name)
44
- re = Regexp.new("^" + name.split(/\*/, -1).map {|part| Regexp.escape(part) }.join('.*') + "$")
45
- classes = @relations.to_a.find_all {|cls| re =~ cls[:name] && !cls[:private] }.map {|cls| cls[:name] }.sort
46
- if classes.length == 0
47
- Logger.instance.warn("No class found matching a pattern '#{name}' in categories file.")
10
+ def self.create(filename, doc_formatter, relations)
11
+ if filename
12
+ categories = FileCategories.new(filename, relations)
13
+ else
14
+ categories = AutoCategories.new(relations)
48
15
  end
49
- classes
16
+ Categories.new(categories.generate, doc_formatter, relations)
50
17
  end
51
18
 
52
- # Prints warnings for missing classes in categories file
53
- def validate
54
- # Build a map of all classes listed in categories
55
- listed_classes = {}
56
- @categories.each do |cat|
57
- cat["groups"].each do |group|
58
- group["classes"].each do |cls_name|
59
- listed_classes[cls_name] = true
60
- end
61
- end
62
- end
63
-
64
- # Check that each existing non-private class is listed
65
- @relations.each do |cls|
66
- unless listed_classes[cls[:name]] || cls[:private]
67
- Logger.instance.warn("Class '#{cls[:name]}' not found in categories file")
68
- end
69
- end
19
+ def initialize(categories, doc_formatter, relations={})
20
+ @categories = categories
21
+ @doc_formatter = doc_formatter
22
+ @relations = relations
70
23
  end
71
24
 
72
25
  # Returns HTML listing of classes divided into categories
73
26
  def to_html
74
- return "" if @categories.length == 0
75
-
76
27
  html = @categories.map do |category|
77
28
  [
78
- "<div class='section classes'>",
29
+ "<div class='section'>",
79
30
  "<h1>#{category['name']}</h1>",
80
31
  render_columns(category['groups']),
81
32
  "<div style='clear:both'></div>",
@@ -91,7 +42,7 @@ module JsDuck
91
42
  end
92
43
 
93
44
  def render_columns(groups)
94
- align = ["lft", "mid", "rgt"]
45
+ align = ["left-column", "middle-column", "right-column"]
95
46
  i = -1
96
47
  return split(groups, 3).map do |col|
97
48
  i += 1
data/lib/jsduck/class.rb CHANGED
@@ -62,7 +62,7 @@ module JsDuck
62
62
  @relations[classname]
63
63
  elsif !@relations.ignore?(classname)
64
64
  context = @doc[:files][0]
65
- Logger.instance.warn("Class #{classname} not found", context[:filename], context[:linenr])
65
+ Logger.instance.warn(:extend, "Class #{classname} not found", context[:filename], context[:linenr])
66
66
  nil
67
67
  end
68
68
  end
@@ -89,7 +89,8 @@ module JsDuck
89
89
  #
90
90
  # See members_hash for details.
91
91
  def members(type, context=:members)
92
- ms = members_hash(type, context).values.sort {|a,b| a[:name] <=> b[:name] }
92
+ ms = members_hash(type, context).values.find_all {|m| !m[:private] }
93
+ ms.sort! {|a,b| a[:name] <=> b[:name] }
93
94
  type == :method ? constructor_first(ms) : ms
94
95
  end
95
96
 
@@ -104,7 +105,7 @@ module JsDuck
104
105
  ms
105
106
  end
106
107
 
107
- # Returns hash of public members of class (and of parent classes
108
+ # Returns hash of all members in class (and of parent classes
108
109
  # and mixin classes). Members are methods, properties, cfgs,
109
110
  # events (member type is specified through 'type' parameter).
110
111
  #
@@ -115,7 +116,7 @@ module JsDuck
115
116
  if @doc[:singleton] && context == :statics
116
117
  # Warn if singleton has static members
117
118
  if @doc[context][type].length > 0
118
- Logger.instance.warn("Singleton class #{@doc[:name]} can't have static members, remove the @static tag.")
119
+ Logger.instance.warn(:sing_static, "Singleton class #{@doc[:name]} can't have static members, remove the @static tag.")
119
120
  end
120
121
  return {}
121
122
  end
@@ -148,7 +149,7 @@ module JsDuck
148
149
  def local_members_hash(type, context)
149
150
  local_members = {}
150
151
  (@doc[context][type] || []).each do |m|
151
- local_members[m[:name]] = m if !m[:private]
152
+ local_members[m[:name]] = m
152
153
  end
153
154
  local_members
154
155
  end
@@ -174,13 +175,26 @@ module JsDuck
174
175
  @members_map[type_name ? "#{type_name}-#{name}" : name]
175
176
  end
176
177
 
177
- # Loops through each member of the class, invoking block with each of them
178
- def each_member(&block)
178
+ # Returns all public members of class, including the inherited and mixed in ones
179
+ def all_members
180
+ all = []
179
181
  [:members, :statics].each do |group|
180
- @doc[group].each_value do |members|
181
- members.each(&block)
182
+ @doc[group].each_key do |type|
183
+ all += members(type, group)
182
184
  end
183
185
  end
186
+ all
187
+ end
188
+
189
+ # Returns all local public members of class
190
+ def all_local_members
191
+ all = []
192
+ [:members, :statics].each do |group|
193
+ @doc[group].each_value do |ms|
194
+ all += ms.find_all {|m| !m[:private] }
195
+ end
196
+ end
197
+ all
184
198
  end
185
199
 
186
200
  # A way to access full class name with similar syntax to
@@ -69,9 +69,9 @@ module JsDuck
69
69
  else
70
70
  context = @formatter.doc_context
71
71
  if tp.error == :syntax
72
- Logger.instance.warn("Incorrect type syntax #{type}", context[:filename], context[:linenr])
72
+ Logger.instance.warn(:type_syntax, "Incorrect type syntax #{type}", context[:filename], context[:linenr])
73
73
  else
74
- Logger.instance.warn("Unknown type #{type}", context[:filename], context[:linenr])
74
+ Logger.instance.warn(:type_name, "Unknown type #{type}", context[:filename], context[:linenr])
75
75
  end
76
76
  type
77
77
  end
@@ -0,0 +1,49 @@
1
+ require 'jsduck/parallel_wrap'
2
+ require 'jsduck/logger'
3
+ require 'jsduck/json_duck'
4
+ require 'fileutils'
5
+
6
+ module JsDuck
7
+
8
+ # Writes class data into files in JSON or JSONP format or to STDOUT.
9
+ class ClassWriter
10
+ def initialize(exporter_class, relations, opts)
11
+ @relations = relations
12
+ @exporter = exporter_class.new(relations, opts)
13
+ @parallel = ParallelWrap.new(:in_processes => opts.processes)
14
+ end
15
+
16
+ # Writes class data into given directory or STDOUT when dir == :stdout.
17
+ #
18
+ # Extension is either ".json" for normal JSON output
19
+ # or ".js" for JsonP output.
20
+ def write(dir, extension)
21
+ dir == :stdout ? write_stdout : write_dir(dir, extension)
22
+ end
23
+
24
+ private
25
+
26
+ def write_stdout
27
+ json = @parallel.map(@relations.classes) {|cls| @exporter.export(cls) }
28
+ puts JsonDuck.generate(json)
29
+ end
30
+
31
+ def write_dir(dir, extension)
32
+ FileUtils.mkdir(dir)
33
+ @parallel.each(@relations.classes) do |cls|
34
+ filename = dir + "/" + cls[:name] + extension
35
+ Logger.instance.log("Writing docs", filename)
36
+ json = @exporter.export(cls)
37
+ if extension == ".json"
38
+ JsonDuck.write_json(filename, json)
39
+ elsif extension == ".js"
40
+ JsonDuck.write_jsonp(filename, cls[:name].gsub(/\./, "_"), json)
41
+ else
42
+ throw "Unexpected file extension: #{extension}"
43
+ end
44
+ end
45
+ end
46
+
47
+ end
48
+
49
+ end
@@ -55,14 +55,14 @@ module JsDuck
55
55
  # name actually exists.
56
56
  attr_accessor :relations
57
57
 
58
- def initialize
58
+ def initialize(relations={}, opts={})
59
59
  @class_context = ""
60
60
  @doc_context = {}
61
61
  @max_length = 120
62
- @relations = {}
62
+ @relations = relations
63
63
  @images = []
64
- @link_tpl = '<a href="%c%#%m">%a</a>'
65
- @img_tpl = '<img src="%u" alt="%a"/>'
64
+ @link_tpl = opts[:link_tpl] || '<a href="%c%#%m">%a</a>'
65
+ @img_tpl = opts[:img_tpl] || '<img src="%u" alt="%a"/>'
66
66
  @link_re = /\{@link\s+(\S*?)(?:\s+(.+?))?\}/m
67
67
  @img_re = /\{@img\s+(\S*?)(?:\s+(.+?))?\}/m
68
68
  @example_annotation_re = /<pre><code>\s*@example( +[^\n]*)?\s+/m
@@ -130,10 +130,13 @@ module JsDuck
130
130
  file = @doc_context[:filename]
131
131
  line = @doc_context[:linenr]
132
132
  if !@relations[cls]
133
- Logger.instance.warn("#{input} links to non-existing class", file, line)
133
+ Logger.instance.warn(:link, "#{input} links to non-existing class", file, line)
134
134
  text
135
135
  elsif member && !get_member(cls, member, type)
136
- Logger.instance.warn("#{input} links to non-existing member", file, line)
136
+ Logger.instance.warn(:link, "#{input} links to non-existing member", file, line)
137
+ text
138
+ elsif member && !public_member?(cls, member, type)
139
+ Logger.instance.warn(:link, "#{input} links to private member", file, line)
137
140
  text
138
141
  else
139
142
  link(cls, member, text, type)
@@ -153,7 +156,7 @@ module JsDuck
153
156
  member = $4
154
157
  after = $5
155
158
 
156
- if @relations[cls] && (member ? get_member(cls, member) : cls =~ /\./)
159
+ if @relations[cls] && (member ? public_member?(cls, member) : cls =~ /\./)
157
160
  label = member ? cls+"."+member : cls
158
161
  before + link(cls, member, label) + after
159
162
  else
@@ -202,8 +205,13 @@ module JsDuck
202
205
  end
203
206
  end
204
207
 
208
+ def public_member?(cls, member, type=nil)
209
+ m = get_member(cls, member, type)
210
+ return m && !m[:private]
211
+ end
212
+
205
213
  def get_member(cls, member, type=nil)
206
- @relations[cls] && @relations[cls].get_member(member, type)
214
+ return @relations[cls] && @relations[cls].get_member(member, type)
207
215
  end
208
216
 
209
217
  # Formats doc-comment for placement into HTML.
@@ -93,9 +93,13 @@ module JsDuck
93
93
  elsif look(/@extends?\b/)
94
94
  at_extends
95
95
  elsif look(/@mixins?\b/)
96
- at_mixins
96
+ class_list_at_tag(/@mixins?/, :mixins)
97
97
  elsif look(/@alternateClassNames?\b/)
98
- at_alternateClassName
98
+ class_list_at_tag(/@alternateClassNames?/, :alternateClassNames)
99
+ elsif look(/@uses\b/)
100
+ class_list_at_tag(/@uses/, :uses)
101
+ elsif look(/@requires\b/)
102
+ class_list_at_tag(/@requires/, :requires)
99
103
  elsif look(/@singleton\b/)
100
104
  boolean_at_tag(/@singleton/, :singleton)
101
105
  elsif look(/@event\b/)
@@ -115,12 +119,20 @@ module JsDuck
115
119
  elsif look(/@type\b/)
116
120
  at_type
117
121
  elsif look(/@xtype\b/)
118
- at_xtype
122
+ at_xtype(/@xtype/, "widget")
119
123
  elsif look(/@ftype\b/)
120
- at_ftype
124
+ at_xtype(/@ftype/, "feature")
125
+ elsif look(/@ptype\b/)
126
+ at_xtype(/@ptype/, "plugin")
121
127
  elsif look(/@member\b/)
122
128
  at_member
123
- elsif look(/@alias\b/)
129
+ elsif look(/@inherit[dD]oc\b/)
130
+ at_inheritdoc
131
+ elsif look(/@alias\s+[\w.]+#\w+/)
132
+ # For backwards compatibility.
133
+ # @alias tag was used as @inheritdoc before
134
+ at_inheritdoc
135
+ elsif look(/@alias/)
124
136
  at_alias
125
137
  elsif look(/@deprecated\b/)
126
138
  at_deprecated
@@ -194,21 +206,12 @@ module JsDuck
194
206
  skip_white
195
207
  end
196
208
 
197
- # matches @mixins name1 name2 ...
198
- def at_mixins
199
- match(/@mixins?/)
200
- add_tag(:mixins)
201
- skip_horiz_white
202
- @current_tag[:mixins] = class_list
203
- skip_white
204
- end
205
-
206
- # matches @alternateClassName name1 name2 ...
207
- def at_alternateClassName
208
- match(/@alternateClassNames?/)
209
- add_tag(:alternateClassNames)
209
+ # matches @<tagname> classname1 classname2 ...
210
+ def class_list_at_tag(regex, tagname)
211
+ match(regex)
212
+ add_tag(tagname)
210
213
  skip_horiz_white
211
- @current_tag[:alternateClassNames] = class_list
214
+ @current_tag[tagname] = class_list
212
215
  skip_white
213
216
  end
214
217
 
@@ -302,22 +305,6 @@ module JsDuck
302
305
  skip_white
303
306
  end
304
307
 
305
- # matches @xtype name
306
- def at_xtype
307
- match(/@xtype/)
308
- add_tag(:xtype)
309
- maybe_ident_chain(:name)
310
- skip_white
311
- end
312
-
313
- # matches @ftype name
314
- def at_ftype
315
- match(/@ftype/)
316
- add_tag(:ftype)
317
- maybe_ident_chain(:name)
318
- skip_white
319
- end
320
-
321
308
  # matches @member name ...
322
309
  def at_member
323
310
  match(/@member/)
@@ -326,11 +313,30 @@ module JsDuck
326
313
  skip_white
327
314
  end
328
315
 
329
- # matches @alias class.name#type-member
316
+ # matches @xtype/ptype/ftype/... name
317
+ def at_xtype(tag, namespace)
318
+ match(tag)
319
+ add_tag(:alias)
320
+ skip_horiz_white
321
+ @current_tag[:name] = namespace + "." + (ident_chain || "")
322
+ skip_white
323
+ end
324
+
325
+ # matches @alias <ident-chain>
330
326
  def at_alias
331
327
  match(/@alias/)
332
328
  add_tag(:alias)
333
329
  skip_horiz_white
330
+ @current_tag[:name] = ident_chain
331
+ skip_white
332
+ end
333
+
334
+ # matches @inheritdoc class.name#type-member
335
+ def at_inheritdoc
336
+ match(/@inherit[dD]oc|@alias/)
337
+
338
+ add_tag(:inheritdoc)
339
+ skip_horiz_white
334
340
  if look(@ident_chain_pattern)
335
341
  @current_tag[:cls] = ident_chain
336
342
  if look(/#\w/)