jsduck 3.0.pre2 → 3.0.pre3

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.
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
+