jsduck 3.0.pre2 → 3.0.pre3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. data/README.md +14 -7
  2. data/Rakefile +277 -24
  3. data/bin/compare +163 -0
  4. data/bin/stats +92 -0
  5. data/jsduck.gemspec +3 -3
  6. data/lib/jsduck/accessors.rb +64 -8
  7. data/lib/jsduck/aggregator.rb +10 -6
  8. data/lib/jsduck/aliases.rb +3 -2
  9. data/lib/jsduck/app.rb +51 -44
  10. data/lib/jsduck/author_tag.rb +11 -0
  11. data/lib/jsduck/categories.rb +14 -8
  12. data/lib/jsduck/class.rb +2 -1
  13. data/lib/jsduck/class_formatter.rb +5 -4
  14. data/lib/jsduck/doc_author_tag.rb +11 -0
  15. data/lib/jsduck/doc_formatter.rb +17 -37
  16. data/lib/jsduck/doc_parser.rb +39 -11
  17. data/lib/jsduck/exporter.rb +11 -0
  18. data/lib/jsduck/guides.rb +3 -3
  19. data/lib/jsduck/images.rb +72 -0
  20. data/lib/jsduck/js_parser.rb +20 -4
  21. data/lib/jsduck/lexer.rb +2 -8
  22. data/lib/jsduck/lint.rb +3 -2
  23. data/lib/jsduck/logger.rb +24 -5
  24. data/lib/jsduck/merger.rb +38 -8
  25. data/lib/jsduck/meta_tag.rb +49 -0
  26. data/lib/jsduck/meta_tag_loader.rb +48 -0
  27. data/lib/jsduck/options.rb +37 -25
  28. data/lib/jsduck/os.rb +11 -0
  29. data/lib/jsduck/renderer.rb +37 -34
  30. data/lib/jsduck/search_data.rb +1 -1
  31. data/lib/jsduck/source_file.rb +13 -8
  32. data/template-min/app.js +1 -1
  33. data/template-min/{egIframe.html → extIframe.html} +3 -4
  34. data/template-min/extjs/ext-all-debug.js +3107 -2026
  35. data/template-min/extjs/ext-all.js +1 -1
  36. data/template-min/extjs/resources/css/ext-all.css +1 -1
  37. data/template-min/resources/css/app.css +1 -1
  38. data/template-min/resources/images/down-arr.png +0 -0
  39. data/template-min/resources/images/gettingstarted.jpg +0 -0
  40. data/template-min/resources/images/ipad-l.jpg +0 -0
  41. data/template-min/resources/images/ipad-p.jpg +0 -0
  42. data/template-min/resources/images/iphone-l.jpg +0 -0
  43. data/template-min/resources/images/iphone-p.jpg +0 -0
  44. data/template-min/resources/images/iphone-small-l.jpg +0 -0
  45. data/template-min/resources/images/iphone-small-p.jpg +0 -0
  46. data/template-min/resources/images/link-arrow-next.png +0 -0
  47. data/template-min/template.html +5 -1
  48. data/template-min/touch-welcome.html +122 -0
  49. data/template-min/touchIframe.html +85 -0
  50. data/template-min/welcome.html +2 -0
  51. metadata +25 -8
  52. data/lib/jsduck/page.rb +0 -118
  53. data/lib/jsduck/timer.rb +0 -44
data/bin/stats ADDED
@@ -0,0 +1,92 @@
1
+ #!/usr/bin/env ruby
2
+ # Print stats for JSON export
3
+
4
+ # For running when gem not installed
5
+ $:.unshift File.dirname(File.dirname(__FILE__)) + "/lib"
6
+
7
+ require "rubygems"
8
+ require "jsduck/json_duck"
9
+
10
+ def read_all_classes(dir)
11
+ classes = []
12
+ Dir[dir+"/*.json"].each do |filename|
13
+ print "."
14
+ STDOUT.flush
15
+ classes << JsDuck::JsonDuck.read(filename)
16
+ end
17
+ puts "OK"
18
+ classes
19
+ end
20
+
21
+ def count_members(classes, group, type)
22
+ classes.map do |c|
23
+ c[group][type].find_all {|m| m["owner"] == c["name"] }
24
+ end.flatten.length
25
+ end
26
+
27
+ # Strips HTML and counts words in text
28
+ def wc(string)
29
+ string.gsub(/<\/?[^>]*>/, "").scan(/\w+/).size
30
+ end
31
+
32
+ def property_wc(property)
33
+ cnt = wc(property["doc"])
34
+ (property["properties"] || []).each {|p| cnt += property_wc(p) }
35
+ cnt
36
+ end
37
+
38
+ def class_wc(cls)
39
+ cnt = wc(cls["doc"])
40
+ ["members", "statics"].each do |group|
41
+ cls[group].each_value do |members|
42
+ members.find_all {|m| m["owner"] == cls["name"] }.each do |m|
43
+ cnt += wc(m["doc"])
44
+ (m["params"] || []).each {|p| cnt += property_wc(p) }
45
+ (m["properties"] || []).each {|p| cnt += property_wc(p) }
46
+ cnt += wc(m["return"]["doc"]) if m["return"]
47
+ end
48
+ end
49
+ end
50
+ cnt
51
+ end
52
+
53
+ classes = read_all_classes(ARGV[0])
54
+
55
+ puts "%d classes in total" % classes.length
56
+ puts "%d public classes" % classes.find_all {|c| !c["private"] }.length
57
+ puts "%d private classes" % classes.find_all {|c| c["private"] }.length
58
+ puts
59
+
60
+ mem = count_members(classes, "members", "cfg")
61
+ sta = count_members(classes, "statics", "cfg")
62
+ puts "%d public cfgs" % (mem+sta)
63
+ puts " %d instance" % mem
64
+ puts " %d static" % sta
65
+
66
+ mem = count_members(classes, "members", "property")
67
+ sta = count_members(classes, "statics", "property")
68
+ puts "%d public properties" % (mem+sta)
69
+ puts " %d instance" % mem
70
+ puts " %d static" % sta
71
+
72
+ mem = count_members(classes, "members", "method")
73
+ sta = count_members(classes, "statics", "method")
74
+ puts "%d public methods" % (mem+sta)
75
+ puts " %d instance" % mem
76
+ puts " %d static" % sta
77
+
78
+ mem = count_members(classes, "members", "event")
79
+ sta = count_members(classes, "statics", "event")
80
+ puts "%d public events" % (mem+sta)
81
+ puts " %d instance" % mem
82
+ puts " %d static" % sta
83
+
84
+ puts
85
+ puts "Word counts"
86
+ puts "-----------"
87
+ classes.map {|cls| [cls, class_wc(cls)] }.sort {|a,b| a[1] <=> b[1] }.each do |pair|
88
+ puts "%d %s" % [pair[1], pair[0]["name"]]
89
+ end
90
+
91
+ puts
92
+ puts "%d total words in documentation" % classes.map {|cls| class_wc(cls) }.inject(0) {|a,b| a+b }
data/jsduck.gemspec CHANGED
@@ -2,10 +2,10 @@ Gem::Specification.new do |s|
2
2
  s.required_rubygems_version = ">= 1.3.7"
3
3
 
4
4
  s.name = 'jsduck'
5
- s.version = '3.0.pre2'
6
- s.date = '2011-09-20'
5
+ s.version = '3.0.pre3'
6
+ s.date = '2011-10-17'
7
7
  s.summary = "Simple JavaScript Duckumentation generator"
8
- s.description = "Documentation generator for ExtJS 4"
8
+ s.description = "Documentation generator for Sencha JS frameworks"
9
9
  s.homepage = "https://github.com/senchalabs/jsduck"
10
10
  s.authors = ["Rene Saarsoo", "Nick Poulden"]
11
11
  s.email = "rene.saarsoo@sencha.com"
@@ -9,13 +9,11 @@ module JsDuck
9
9
  # not added.
10
10
  def create(cls)
11
11
  # Grab all configs tagged as @accessor
12
- accessors = cls[:members][:cfg].find_all {|cfg| cfg[:accessor] }
12
+ accessors = cls[:members][:cfg].find_all {|cfg| cfg[:accessor] && !cfg[:private] }
13
13
 
14
- # Build lookup table of method names
15
- methods = {}
16
- cls[:members][:method].each do |m|
17
- methods[m[:name]] = m;
18
- end
14
+ # Build lookup tables of method and event names
15
+ methods = build_lookup_table(cls[:members][:method])
16
+ events = build_lookup_table(cls[:members][:event])
19
17
 
20
18
  accessors.each do |cfg|
21
19
  # add getter if no method with same name exists
@@ -28,13 +26,28 @@ module JsDuck
28
26
  if !methods[set[:name]]
29
27
  cls[:members][:method] << set
30
28
  end
29
+ # for evented accessors
30
+ if cfg[:evented]
31
+ # add event if no event with same name exists
32
+ ev = create_event(cfg)
33
+ if !events[ev[:name]]
34
+ cls[:members][:event] << ev
35
+ end
36
+ end
31
37
  end
32
38
  end
33
39
 
40
+ def build_lookup_table(members)
41
+ map = {}
42
+ members.each {|m| map[m[:name]] = m }
43
+ map
44
+ end
45
+
34
46
  def create_getter(cfg)
47
+ name = "get" + upcase_first(cfg[:name])
35
48
  return {
36
49
  :tagname => :method,
37
- :name => "get" + upcase_first(cfg[:name]),
50
+ :name => name,
38
51
  :doc => "Returns the value of {@link #cfg-#{cfg[:name]}}.",
39
52
  :params => [],
40
53
  :return => {
@@ -42,13 +55,17 @@ module JsDuck
42
55
  :doc => "",
43
56
  },
44
57
  :owner => cfg[:owner],
58
+ :files => cfg[:files],
59
+ :id => "method-" + name,
60
+ :deprecated => cfg[:deprecated],
45
61
  }
46
62
  end
47
63
 
48
64
  def create_setter(cfg)
65
+ name = "set" + upcase_first(cfg[:name]);
49
66
  return {
50
67
  :tagname => :method,
51
- :name => "set" + upcase_first(cfg[:name]),
68
+ :name => name,
52
69
  :doc => "Sets the value of {@link #cfg-#{cfg[:name]}}.",
53
70
  :params => [{
54
71
  :type => cfg[:type],
@@ -60,6 +77,45 @@ module JsDuck
60
77
  :doc => "",
61
78
  },
62
79
  :owner => cfg[:owner],
80
+ :files => cfg[:files],
81
+ :id => "method-" + name,
82
+ :deprecated => cfg[:deprecated],
83
+ }
84
+ end
85
+
86
+ def create_event(cfg)
87
+ name = cfg[:name].downcase + "change"
88
+ setter_name = "set" + upcase_first(cfg[:name]);
89
+ return {
90
+ :tagname => :event,
91
+ :name => name,
92
+ :doc =>
93
+ "Fires when the {@link ##{cfg[:id]}} configuration is changed by {@link #method-#{setter_name}}." +
94
+ "\n\n" +
95
+ "Note that this event is fired *before* the value of {@link ##{cfg[:id]}} has been updated, " +
96
+ "and that you can return false from any listener to the #{name} event " +
97
+ "to cancel the change.",
98
+ :params => [
99
+ {
100
+ :name => "this",
101
+ :type => cfg[:owner],
102
+ :doc => "The #{cfg[:owner]} instance."
103
+ },
104
+ {
105
+ :name => "value",
106
+ :type => cfg[:type],
107
+ :doc => "The new value being set."
108
+ },
109
+ {
110
+ :name => "oldValue",
111
+ :type => cfg[:type],
112
+ :doc => "The existing value."
113
+ },
114
+ ],
115
+ :owner => cfg[:owner],
116
+ :files => cfg[:files],
117
+ :id => "event-" + name,
118
+ :deprecated => cfg[:deprecated],
63
119
  }
64
120
  end
65
121
 
@@ -51,14 +51,19 @@ module JsDuck
51
51
 
52
52
  # Merges new class-doc into old one.
53
53
  def merge_classes(old, new)
54
+ # Merge booleans
54
55
  [:extends, :singleton, :private, :protected].each do |tag|
55
56
  old[tag] = old[tag] || new[tag]
56
57
  end
57
- [:mixins, :alternateClassNames].each do |tag|
58
+ # Merge arrays
59
+ [:mixins, :alternateClassNames, :files].each do |tag|
58
60
  old[tag] = old[tag] + new[tag]
59
61
  end
60
- new[:xtypes].each_pair do |key, xtypes|
61
- old[:xtypes][key] = (old[:xtypes][key] || []) + xtypes
62
+ # Merge hashes of arrays
63
+ [:xtypes, :meta].each do |tag|
64
+ new[tag].each_pair do |key, contents|
65
+ old[tag][key] = (old[tag][key] || []) + contents
66
+ end
62
67
  end
63
68
  old[:doc] = old[:doc].length > 0 ? old[:doc] : new[:doc]
64
69
  # Additionally the doc-comment can contain configs and constructor
@@ -144,9 +149,8 @@ module JsDuck
144
149
  :alternateClassNames => [],
145
150
  :members => Class.default_members_hash,
146
151
  :statics => Class.default_members_hash,
147
- :filename => "",
148
- :html_filename => "",
149
- :linenr => 0,
152
+ :meta => {},
153
+ :files => [{:filename => "", :linenr => 0}],
150
154
  })
151
155
  end
152
156
 
@@ -28,16 +28,17 @@ module JsDuck
28
28
  # Given aliased member, finds the original member.
29
29
  # If the original also happens to be an alias, continue recursively.
30
30
  def find_original(al)
31
+ context = al[:files][0]
31
32
  al_def = al[:alias]
32
33
 
33
34
  orig = @relations[al_def[:cls]]
34
35
  unless orig
35
- Logger.instance.warn("Class #{al_def[:cls]} not found in #{al[:filename]} line #{al[:linenr]}")
36
+ Logger.instance.warn("Class #{al_def[:cls]} not found", context[:filename], context[:linenr])
36
37
  return al
37
38
  end
38
39
  orig = orig.get_member(al_def[:member], al_def[:type] || al[:tagname])
39
40
  unless orig
40
- Logger.instance.warn("Member #{al_def[:cls]}##{al_def[:member]} not found in #{al[:filename]} line #{al[:linenr]}")
41
+ Logger.instance.warn("Member #{al_def[:cls]}##{al_def[:member]} not found", context[:filename], context[:linenr])
41
42
  return al
42
43
  end
43
44
 
data/lib/jsduck/app.rb CHANGED
@@ -11,7 +11,6 @@ require 'jsduck/relations'
11
11
  require 'jsduck/aliases'
12
12
  require 'jsduck/exporter'
13
13
  require 'jsduck/renderer'
14
- require 'jsduck/timer'
15
14
  require 'jsduck/parallel_wrap'
16
15
  require 'jsduck/logger'
17
16
  require 'jsduck/welcome'
@@ -19,6 +18,7 @@ require 'jsduck/guides'
19
18
  require 'jsduck/videos'
20
19
  require 'jsduck/examples'
21
20
  require 'jsduck/categories'
21
+ require 'jsduck/images'
22
22
  require 'jsduck/json_duck'
23
23
  require 'jsduck/lint'
24
24
  require 'fileutils'
@@ -30,7 +30,6 @@ module JsDuck
30
30
  # Initializes app with JsDuck::Options object
31
31
  def initialize(opts)
32
32
  @opts = opts
33
- @timer = Timer.new
34
33
  # Sets the nr of parallel processes to use.
35
34
  # Set to 0 to disable parallelization completely.
36
35
  @parallel = ParallelWrap.new(:in_processes => @opts.processes)
@@ -43,47 +42,47 @@ module JsDuck
43
42
 
44
43
  # Call this after input parameters set
45
44
  def run
46
- parsed_files = @timer.time(:parsing) { parallel_parse(@opts.input_files) }
47
- result = @timer.time(:aggregating) { aggregate(parsed_files) }
48
- @relations = @timer.time(:aggregating) { filter_classes(result) }
45
+ parsed_files = parallel_parse(@opts.input_files)
46
+ result = aggregate(parsed_files)
47
+ @relations = filter_classes(result)
49
48
  Aliases.new(@relations).resolve_all
50
49
  Lint.new(@relations).run
51
50
 
51
+ @images = Images.new(@opts.images)
52
+
52
53
  @welcome = Welcome.new
53
54
  if @opts.welcome
54
- @timer.time(:parsing) { @welcome.parse(@opts.welcome) }
55
+ @welcome.parse(@opts.welcome)
55
56
  end
56
57
 
57
58
  @guides = Guides.new(get_doc_formatter)
58
59
  if @opts.guides
59
- @timer.time(:parsing) { @guides.parse(@opts.guides) }
60
+ @guides.parse(@opts.guides)
60
61
  end
61
62
 
62
63
  @videos = Videos.new
63
64
  if @opts.videos
64
- @timer.time(:parsing) { @videos.parse(@opts.videos) }
65
+ @videos.parse(@opts.videos)
65
66
  end
66
67
 
67
68
  @examples = Examples.new
68
69
  if @opts.examples
69
- @timer.time(:parsing) { @examples.parse(@opts.examples) }
70
+ @examples.parse(@opts.examples)
70
71
  end
71
72
 
72
73
  @categories = Categories.new(get_doc_formatter, @relations)
73
74
  if @opts.categories_path
74
- @timer.time(:parsing) do
75
- @categories.parse(@opts.categories_path)
76
- @categories.validate
77
- end
75
+ @categories.parse(@opts.categories_path)
76
+ @categories.validate
78
77
  end
79
78
 
80
79
  clear_output_dir unless @opts.export == :stdout
81
80
  if @opts.export == :stdout
82
- @timer.time(:generating) { puts JsonDuck.generate(@relations.classes) }
81
+ puts JsonDuck.generate(@relations.classes)
83
82
  elsif @opts.export == :json
84
83
  FileUtils.mkdir(@opts.output_dir)
85
- @timer.time(:generating) { format_classes }
86
- @timer.time(:generating) { write_classes }
84
+ format_classes
85
+ write_classes
87
86
  else
88
87
  if @opts.template_links
89
88
  link_template
@@ -96,22 +95,22 @@ module JsDuck
96
95
  FileUtils.rm(@opts.output_dir+"/index.php")
97
96
  FileUtils.cp(@opts.output_dir+"/template.html", @opts.output_dir+"/index.html")
98
97
  end
99
- @timer.time(:generating) { write_src(parsed_files) }
100
- @timer.time(:generating) { format_classes }
101
- @timer.time(:generating) { write_app_data }
102
- @timer.time(:generating) { write_classes }
103
- @timer.time(:generating) { @guides.write(@opts.output_dir+"/guides") }
104
- @timer.time(:generating) { @videos.write(@opts.output_dir+"/videos") }
105
- @timer.time(:generating) { @examples.write(@opts.output_dir+"/examples") }
98
+ write_src(parsed_files)
99
+ format_classes
100
+ write_app_data
101
+ write_classes
102
+ @guides.write(@opts.output_dir+"/guides")
103
+ @videos.write(@opts.output_dir+"/videos")
104
+ @examples.write(@opts.output_dir+"/examples")
105
+ @images.copy(@opts.output_dir+"/images")
106
106
  end
107
107
 
108
- @timer.report
109
108
  end
110
109
 
111
110
  # Parses the files in parallel using as many processes as available CPU-s
112
111
  def parallel_parse(filenames)
113
112
  @parallel.map(filenames) do |fname|
114
- Logger.instance.log("Parsing #{fname} ...")
113
+ Logger.instance.log("Parsing", fname)
115
114
  SourceFile.new(IO.read(fname), fname, @opts)
116
115
  end
117
116
  end
@@ -120,7 +119,7 @@ module JsDuck
120
119
  def aggregate(parsed_files)
121
120
  agr = Aggregator.new
122
121
  parsed_files.each do |file|
123
- Logger.instance.log("Aggregating #{file.filename} ...")
122
+ Logger.instance.log("Aggregating", file.filename)
124
123
  agr.aggregate(file)
125
124
  end
126
125
  agr.classify_orphans
@@ -140,9 +139,8 @@ module JsDuck
140
139
  else
141
140
  type = d[:tagname].to_s
142
141
  name = d[:name]
143
- file = d[:filename]
144
- line = d[:linenr]
145
- Logger.instance.warn("Ignoring #{type}: #{name} in #{file} line #{line}")
142
+ file = d[:files][0]
143
+ Logger.instance.warn("Ignoring #{type}: #{name}", file[:filename], file[:linenr])
146
144
  end
147
145
  end
148
146
  Relations.new(classes, @opts.external_classes)
@@ -150,16 +148,22 @@ module JsDuck
150
148
 
151
149
  # Formats each class
152
150
  def format_classes
153
- formatter = ClassFormatter.new(@relations, get_doc_formatter)
151
+ doc_formatter = get_doc_formatter
152
+ doc_formatter.img_path = "images"
153
+ class_formatter = ClassFormatter.new(@relations, doc_formatter)
154
154
  # Don't format types when exporting
155
- formatter.include_types = !@opts.export
155
+ class_formatter.include_types = !@opts.export
156
156
  # Format all doc-objects in parallel
157
- formatted_docs = @parallel.map(@relations.classes) do |cls|
158
- formatter.format(cls.internal_doc)
157
+ formatted_classes = @parallel.map(@relations.classes) do |cls|
158
+ {
159
+ :doc => class_formatter.format(cls.internal_doc),
160
+ :images => doc_formatter.images
161
+ }
159
162
  end
160
163
  # Then merge the data back to classes sequentially
161
- formatted_docs.each do |doc|
162
- @relations[doc[:name]].internal_doc = doc
164
+ formatted_classes.each do |cls|
165
+ @relations[cls[:doc][:name]].internal_doc = cls[:doc]
166
+ cls[:images].each {|img| @images.add(img) }
163
167
  end
164
168
  end
165
169
 
@@ -178,11 +182,16 @@ module JsDuck
178
182
  # Writes JSON export or JsonP file for each class
179
183
  def write_classes
180
184
  exporter = Exporter.new(@relations)
181
- renderer = Renderer.new(@opts)
185
+ renderer = Renderer.new
186
+ # Inject formatter to all meta-tags.
187
+ doc_formatter = get_doc_formatter
188
+ @opts.meta_tags.each {|tag| tag.formatter = doc_formatter }
189
+ renderer.meta_tags = @opts.meta_tags
190
+
182
191
  dir = @opts.output_dir + (@opts.export ? "" : "/output")
183
192
  @parallel.each(@relations.classes) do |cls|
184
193
  filename = dir + "/" + cls[:name] + (@opts.export ? ".json" : ".js")
185
- Logger.instance.log("Writing to #{filename} ...")
194
+ Logger.instance.log("Writing docs", filename)
186
195
  data = exporter.export(cls)
187
196
  if @opts.export
188
197
  JsonDuck.write_json(filename, data)
@@ -201,7 +210,7 @@ module JsDuck
201
210
  # updates all the doc-objects related to the file
202
211
  parsed_files.each do |file|
203
212
  html_filename = src.write(file.to_html, file.filename)
204
- Logger.instance.log("Writing to #{html_filename} ...")
213
+ Logger.instance.log("Writing source", html_filename)
205
214
  file.html_filename = File.basename(html_filename)
206
215
  end
207
216
  end
@@ -212,20 +221,17 @@ module JsDuck
212
221
  formatter.link_tpl = @opts.link_tpl if @opts.link_tpl
213
222
  formatter.img_tpl = @opts.img_tpl if @opts.img_tpl
214
223
  formatter.relations = @relations
215
- if @opts.inline_examples_dir
216
- formatter.get_example = lambda {|path| IO.read(@opts.inline_examples_dir + "/" + path) }
217
- end
218
224
  formatter
219
225
  end
220
226
 
221
227
  def copy_template
222
- Logger.instance.log("Copying template files to #{@opts.output_dir}...")
228
+ Logger.instance.log("Copying template files to", @opts.output_dir)
223
229
  FileUtils.cp_r(@opts.template_dir, @opts.output_dir)
224
230
  init_output_dirs
225
231
  end
226
232
 
227
233
  def link_template
228
- Logger.instance.log("Linking template files to #{@opts.output_dir}...")
234
+ Logger.instance.log("Linking template files to", @opts.output_dir)
229
235
  FileUtils.mkdir(@opts.output_dir)
230
236
  Dir.glob(@opts.template_dir + "/*").each do |file|
231
237
  File.symlink(File.expand_path(file), @opts.output_dir+"/"+File.basename(file))
@@ -252,6 +258,7 @@ module JsDuck
252
258
  "{extjs_path}" => @opts.extjs_path,
253
259
  "{local_storage_db}" => @opts.local_storage_db,
254
260
  "{show_print_button}" => @opts.seo ? "true" : "false",
261
+ "{touch_examples_ui}" => @opts.touch_examples_ui ? "true" : "false",
255
262
  "{welcome}" => @welcome.to_html,
256
263
  "{categories}" => @categories.to_html,
257
264
  "{guides}" => @guides.to_html,
@@ -271,7 +278,7 @@ module JsDuck
271
278
  def write_template(filename, replacements)
272
279
  in_file = @opts.template_dir + '/' + filename
273
280
  out_file = @opts.output_dir + '/' + filename
274
- Logger.instance.log("Creating #{out_file}...")
281
+ Logger.instance.log("Writing", out_file)
275
282
  html = IO.read(in_file)
276
283
  html.gsub!(/\{\w+\}/) do |key|
277
284
  replacements[key] ? replacements[key] : key
@@ -0,0 +1,11 @@
1
+ require "jsduck/meta_tag"
2
+
3
+ module JsDuck
4
+ # Implementation of hidden @author tag
5
+ class AuthorTag < MetaTag
6
+ def initialize
7
+ @name = "author"
8
+ end
9
+ end
10
+ end
11
+
@@ -13,7 +13,13 @@ module JsDuck
13
13
 
14
14
  # Parses categories in JSON file
15
15
  def parse(path)
16
- @categories = JsonDuck.read(path)["categories"]
16
+ @categories = JsonDuck.read(path)
17
+
18
+ # Don't crash if old syntax is used.
19
+ if @categories.is_a?(Hash) && @categories["categories"]
20
+ Logger.instance.warn('Update categories file to contain just the array inside {"categories": [...]}')
21
+ @categories = @categories["categories"]
22
+ end
17
23
 
18
24
  # Perform expansion on all class names containing * wildcard
19
25
  @categories.each do |cat|
@@ -28,26 +34,26 @@ module JsDuck
28
34
  # Expands class name like 'Foo.*' into multiple class names.
29
35
  def expand(name)
30
36
  re = Regexp.new("^" + name.split(/\*/, -1).map {|part| Regexp.escape(part) }.join('.*') + "$")
31
- @relations.to_a.find_all {|cls| re =~ cls[:name] && !cls[:private] }.map {|cls| cls[:name] }.sort
37
+ classes = @relations.to_a.find_all {|cls| re =~ cls[:name] && !cls[:private] }.map {|cls| cls[:name] }.sort
38
+ if classes.length == 0
39
+ Logger.instance.warn("No class found matching a pattern '#{name}' in categories file.")
40
+ end
41
+ classes
32
42
  end
33
43
 
34
44
  # Prints warnings for missing classes in categories file
35
45
  def validate
46
+ # Build a map of all classes listed in categories
36
47
  listed_classes = {}
37
-
38
- # Check that each class listed in overview file exists
39
48
  @categories.each do |cat|
40
49
  cat["groups"].each do |group|
41
50
  group["classes"].each do |cls_name|
42
- unless @relations[cls_name]
43
- Logger.instance.warn("Class '#{cls_name}' in category '#{cat['name']}/#{group['name']}' not found")
44
- end
45
51
  listed_classes[cls_name] = true
46
52
  end
47
53
  end
48
54
  end
49
55
 
50
- # Check that each existing non-private class is listed in overview file
56
+ # Check that each existing non-private class is listed
51
57
  @relations.each do |cls|
52
58
  unless listed_classes[cls[:name]] || cls[:private]
53
59
  Logger.instance.warn("Class '#{cls[:name]}' not found in categories file")
data/lib/jsduck/class.rb CHANGED
@@ -61,7 +61,8 @@ module JsDuck
61
61
  if @relations[classname]
62
62
  @relations[classname]
63
63
  elsif !@relations.ignore?(classname)
64
- Logger.instance.warn("Class #{classname} not found in #{@doc[:filename]} line #{@doc[:linenr]}")
64
+ context = @doc[:files][0]
65
+ Logger.instance.warn("Class #{classname} not found", context[:filename], context[:linenr])
65
66
  nil
66
67
  end
67
68
  end
@@ -14,6 +14,7 @@ module JsDuck
14
14
  @relations = relations
15
15
  @formatter = formatter
16
16
  @include_types = true
17
+ @meta_tags = []
17
18
  end
18
19
 
19
20
  # Runs the formatter on doc object of a class.
@@ -21,7 +22,7 @@ module JsDuck
21
22
  def format(cls)
22
23
  @cls = cls
23
24
  @formatter.class_context = cls[:name]
24
- @formatter.doc_context = cls
25
+ @formatter.doc_context = cls[:files][0]
25
26
  cls[:doc] = @formatter.format(cls[:doc]) if cls[:doc]
26
27
  cls[:members].each_pair do |type, members|
27
28
  cls[:members][type] = members.reject {|m| m[:private] }.map {|m| format_member(m) }
@@ -33,7 +34,7 @@ module JsDuck
33
34
  end
34
35
 
35
36
  def format_member(m)
36
- @formatter.doc_context = m
37
+ @formatter.doc_context = m[:files][0]
37
38
  m[:doc] = @formatter.format(m[:doc]) if m[:doc]
38
39
  m[:deprecated][:text] = @formatter.format(m[:deprecated][:text]) if m[:deprecated]
39
40
  if expandable?(m) || @formatter.too_long?(m[:doc])
@@ -68,9 +69,9 @@ module JsDuck
68
69
  else
69
70
  context = @formatter.doc_context
70
71
  if tp.error == :syntax
71
- Logger.instance.warn("Incorrect type syntax #{type} in #{context[:filename]} line #{context[:linenr]}")
72
+ Logger.instance.warn("Incorrect type syntax #{type}", context[:filename], context[:linenr])
72
73
  else
73
- Logger.instance.warn("Unknown type #{type} in #{context[:filename]} line #{context[:linenr]}")
74
+ Logger.instance.warn("Unknown type #{type}", context[:filename], context[:linenr])
74
75
  end
75
76
  type
76
77
  end
@@ -0,0 +1,11 @@
1
+ require "jsduck/meta_tag"
2
+
3
+ module JsDuck
4
+ # Implementation of hidden @docauthor tag
5
+ class DocAuthorTag < MetaTag
6
+ def initialize
7
+ @name = "docauthor"
8
+ end
9
+ end
10
+ end
11
+