jsduck 4.10.4 → 5.0.0.beta01

Sign up to get free protection for your applications and to get access to all the features.
Files changed (183) hide show
  1. data/.travis.yml +0 -1
  2. data/README.md +32 -6
  3. data/Rakefile +10 -18
  4. data/bin/compare +5 -5
  5. data/bin/jsduck +2 -3
  6. data/jsduck.gemspec +3 -4
  7. data/lib/jsduck/aggregator.rb +21 -80
  8. data/lib/jsduck/app.rb +7 -14
  9. data/lib/jsduck/app_data.rb +4 -5
  10. data/lib/jsduck/assets.rb +4 -7
  11. data/lib/jsduck/base_type.rb +53 -0
  12. data/lib/jsduck/batch_parser.rb +8 -87
  13. data/lib/jsduck/batch_processor.rb +77 -0
  14. data/lib/jsduck/categories/auto.rb +83 -0
  15. data/lib/jsduck/categories/class_name.rb +63 -0
  16. data/lib/jsduck/categories/factory.rb +113 -0
  17. data/lib/jsduck/categories/file.rb +75 -0
  18. data/lib/jsduck/class.rb +3 -9
  19. data/lib/jsduck/class_doc_expander.rb +1 -1
  20. data/lib/jsduck/css/lexer.rb +203 -0
  21. data/lib/jsduck/css/parser.rb +121 -0
  22. data/lib/jsduck/doc/comment.rb +40 -0
  23. data/lib/jsduck/doc/map.rb +23 -0
  24. data/lib/jsduck/doc/parser.rb +128 -0
  25. data/lib/jsduck/doc/processor.rb +52 -0
  26. data/lib/jsduck/doc/scanner.rb +76 -0
  27. data/lib/jsduck/doc/standard_tag_parser.rb +154 -0
  28. data/lib/jsduck/doc/subproperties.rb +64 -0
  29. data/lib/jsduck/docs_code_comparer.rb +31 -0
  30. data/lib/jsduck/export_writer.rb +2 -2
  31. data/lib/jsduck/exporter/app.rb +16 -4
  32. data/lib/jsduck/exporter/full.rb +2 -2
  33. data/lib/jsduck/format/batch.rb +58 -0
  34. data/lib/jsduck/format/class.rb +62 -0
  35. data/lib/jsduck/format/doc.rb +172 -0
  36. data/lib/jsduck/format/html_stack.rb +109 -0
  37. data/lib/jsduck/format/shortener.rb +55 -0
  38. data/lib/jsduck/format/subproperties.rb +64 -0
  39. data/lib/jsduck/guides.rb +32 -14
  40. data/lib/jsduck/index_html.rb +3 -1
  41. data/lib/jsduck/inline/auto_link.rb +2 -2
  42. data/lib/jsduck/inline/link.rb +4 -3
  43. data/lib/jsduck/inline/link_renderer.rb +2 -2
  44. data/lib/jsduck/inline/video.rb +8 -2
  45. data/lib/jsduck/js/ast.rb +361 -0
  46. data/lib/jsduck/js/esprima.rb +39 -0
  47. data/lib/jsduck/{esprima → js/esprima}/esprima.js +0 -0
  48. data/lib/jsduck/js/evaluator.rb +70 -0
  49. data/lib/jsduck/js/ext_patterns.rb +70 -0
  50. data/lib/jsduck/js/function.rb +206 -0
  51. data/lib/jsduck/js/node.rb +194 -0
  52. data/lib/jsduck/js/node_array.rb +36 -0
  53. data/lib/jsduck/js/parser.rb +223 -0
  54. data/lib/jsduck/js/serializer.rb +263 -0
  55. data/lib/jsduck/js/utils.rb +21 -0
  56. data/lib/jsduck/logger.rb +3 -13
  57. data/lib/jsduck/members_index.rb +3 -4
  58. data/lib/jsduck/merger.rb +25 -145
  59. data/lib/jsduck/options.rb +29 -132
  60. data/lib/jsduck/parser.rb +76 -0
  61. data/lib/jsduck/process/accessors.rb +133 -0
  62. data/lib/jsduck/process/circular_deps.rb +58 -0
  63. data/lib/jsduck/process/enums.rb +91 -0
  64. data/lib/jsduck/process/ext4_events.rb +43 -0
  65. data/lib/jsduck/process/global_members.rb +36 -0
  66. data/lib/jsduck/process/ignored_classes.rb +16 -0
  67. data/lib/jsduck/process/importer.rb +58 -0
  68. data/lib/jsduck/process/inherit_doc.rb +197 -0
  69. data/lib/jsduck/process/lint.rb +135 -0
  70. data/lib/jsduck/process/overrides.rb +99 -0
  71. data/lib/jsduck/process/return_values.rb +72 -0
  72. data/lib/jsduck/process/versions.rb +102 -0
  73. data/lib/jsduck/relations.rb +5 -0
  74. data/lib/jsduck/render/class.rb +144 -0
  75. data/lib/jsduck/render/sidebar.rb +97 -0
  76. data/lib/jsduck/render/signature.rb +94 -0
  77. data/lib/jsduck/render/subproperties.rb +99 -0
  78. data/lib/jsduck/render/tags.rb +38 -0
  79. data/lib/jsduck/search_data.rb +19 -13
  80. data/lib/jsduck/source/file.rb +8 -17
  81. data/lib/jsduck/tag/abstract.rb +4 -7
  82. data/lib/jsduck/tag/accessor.rb +10 -0
  83. data/lib/jsduck/tag/alias.rb +61 -0
  84. data/lib/jsduck/tag/alternate_class_names.rb +17 -0
  85. data/lib/jsduck/tag/aside.rb +28 -31
  86. data/lib/jsduck/tag/author.rb +9 -5
  87. data/lib/jsduck/tag/boolean_tag.rb +24 -0
  88. data/lib/jsduck/tag/cfg.rb +45 -0
  89. data/lib/jsduck/tag/chainable.rb +5 -7
  90. data/lib/jsduck/tag/class.rb +28 -0
  91. data/lib/jsduck/tag/class_list_tag.rb +40 -0
  92. data/lib/jsduck/tag/constructor.rb +24 -0
  93. data/lib/jsduck/tag/css_mixin.rb +17 -0
  94. data/lib/jsduck/tag/css_var.rb +29 -0
  95. data/lib/jsduck/tag/default.rb +31 -0
  96. data/lib/jsduck/tag/deprecated.rb +13 -27
  97. data/lib/jsduck/tag/deprecated_tag.rb +58 -0
  98. data/lib/jsduck/tag/doc.rb +32 -0
  99. data/lib/jsduck/tag/docauthor.rb +4 -5
  100. data/lib/jsduck/tag/enum.rb +70 -0
  101. data/lib/jsduck/tag/event.rb +28 -0
  102. data/lib/jsduck/tag/evented.rb +10 -0
  103. data/lib/jsduck/tag/extends.rb +45 -0
  104. data/lib/jsduck/tag/ftype.rb +18 -0
  105. data/lib/jsduck/tag/hide.rb +4 -11
  106. data/lib/jsduck/tag/ignore.rb +6 -7
  107. data/lib/jsduck/tag/inheritable.rb +10 -0
  108. data/lib/jsduck/tag/inheritdoc.rb +48 -0
  109. data/lib/jsduck/tag/markdown.rb +8 -6
  110. data/lib/jsduck/tag/member.rb +24 -0
  111. data/lib/jsduck/tag/method.rb +35 -0
  112. data/lib/jsduck/tag/mixins.rb +26 -0
  113. data/lib/jsduck/tag/name.rb +36 -0
  114. data/lib/jsduck/tag/new.rb +13 -27
  115. data/lib/jsduck/tag/override.rb +37 -0
  116. data/lib/jsduck/tag/overrides.rb +29 -0
  117. data/lib/jsduck/tag/param.rb +87 -0
  118. data/lib/jsduck/tag/preventable.rb +19 -10
  119. data/lib/jsduck/tag/private.rb +28 -13
  120. data/lib/jsduck/tag/property.rb +39 -0
  121. data/lib/jsduck/tag/protected.rb +5 -7
  122. data/lib/jsduck/tag/ptype.rb +18 -0
  123. data/lib/jsduck/tag/readonly.rb +4 -7
  124. data/lib/jsduck/tag/removed.rb +21 -29
  125. data/lib/jsduck/tag/required.rb +11 -9
  126. data/lib/jsduck/tag/requires.rb +12 -0
  127. data/lib/jsduck/tag/return.rb +47 -0
  128. data/lib/jsduck/tag/since.rb +19 -11
  129. data/lib/jsduck/tag/singleton.rb +15 -0
  130. data/lib/jsduck/tag/static.rb +5 -7
  131. data/lib/jsduck/tag/subproperties.rb +23 -0
  132. data/lib/jsduck/tag/tag.rb +208 -0
  133. data/lib/jsduck/tag/template.rb +14 -9
  134. data/lib/jsduck/tag/throws.rb +38 -0
  135. data/lib/jsduck/tag/type.rb +48 -0
  136. data/lib/jsduck/tag/uses.rb +12 -0
  137. data/lib/jsduck/tag/xtype.rb +30 -0
  138. data/lib/jsduck/tag_loader.rb +39 -0
  139. data/lib/jsduck/tag_registry.rb +189 -0
  140. data/lib/jsduck/type_parser.rb +3 -3
  141. data/lib/jsduck/web_writer.rb +2 -2
  142. data/lib/jsduck/welcome.rb +1 -1
  143. metadata +578 -538
  144. data/lib/jsduck/accessors.rb +0 -136
  145. data/lib/jsduck/ast.rb +0 -524
  146. data/lib/jsduck/auto_categories.rb +0 -80
  147. data/lib/jsduck/batch_formatter.rb +0 -60
  148. data/lib/jsduck/categories.rb +0 -73
  149. data/lib/jsduck/categories_class_name.rb +0 -37
  150. data/lib/jsduck/circular_deps.rb +0 -56
  151. data/lib/jsduck/class_formatter.rb +0 -102
  152. data/lib/jsduck/columns.rb +0 -56
  153. data/lib/jsduck/css_lexer.rb +0 -201
  154. data/lib/jsduck/css_parser.rb +0 -119
  155. data/lib/jsduck/doc_ast.rb +0 -319
  156. data/lib/jsduck/doc_formatter.rb +0 -142
  157. data/lib/jsduck/doc_parser.rb +0 -611
  158. data/lib/jsduck/doc_type.rb +0 -59
  159. data/lib/jsduck/enum.rb +0 -73
  160. data/lib/jsduck/esprima.rb +0 -51
  161. data/lib/jsduck/evaluator.rb +0 -69
  162. data/lib/jsduck/ext_patterns.rb +0 -58
  163. data/lib/jsduck/file_categories.rb +0 -76
  164. data/lib/jsduck/function_ast.rb +0 -206
  165. data/lib/jsduck/guide_anchors.rb +0 -32
  166. data/lib/jsduck/guide_toc.rb +0 -49
  167. data/lib/jsduck/html_stack.rb +0 -105
  168. data/lib/jsduck/importer.rb +0 -121
  169. data/lib/jsduck/inherit_doc.rb +0 -193
  170. data/lib/jsduck/js_parser.rb +0 -221
  171. data/lib/jsduck/lint.rb +0 -133
  172. data/lib/jsduck/meta_tag.rb +0 -88
  173. data/lib/jsduck/meta_tag_loader.rb +0 -67
  174. data/lib/jsduck/meta_tag_registry.rb +0 -111
  175. data/lib/jsduck/meta_tag_renderer.rb +0 -34
  176. data/lib/jsduck/news.rb +0 -128
  177. data/lib/jsduck/override.rb +0 -87
  178. data/lib/jsduck/renderer.rb +0 -361
  179. data/lib/jsduck/return_values.rb +0 -72
  180. data/lib/jsduck/serializer.rb +0 -262
  181. data/lib/jsduck/shortener.rb +0 -58
  182. data/lib/jsduck/signature_renderer.rb +0 -91
  183. data/lib/jsduck/source/file_parser.rb +0 -72
data/lib/jsduck/assets.rb CHANGED
@@ -4,9 +4,8 @@ require 'jsduck/welcome'
4
4
  require 'jsduck/guides'
5
5
  require 'jsduck/videos'
6
6
  require 'jsduck/examples'
7
- require 'jsduck/categories'
8
- require 'jsduck/doc_formatter'
9
- require 'jsduck/news'
7
+ require 'jsduck/categories/factory'
8
+ require 'jsduck/format/doc'
10
9
 
11
10
  module JsDuck
12
11
 
@@ -23,21 +22,19 @@ module JsDuck
23
22
  attr_reader :videos
24
23
  attr_reader :examples
25
24
  attr_reader :categories
26
- attr_reader :news
27
25
 
28
26
  def initialize(relations, opts)
29
27
  @relations = relations
30
28
  @opts = opts
31
29
 
32
- doc_formatter = DocFormatter.new(@relations, @opts)
30
+ doc_formatter = Format::Doc.new(@relations, @opts)
33
31
 
34
32
  @images = Img::DirSet.new(@opts.images, "images")
35
33
  @welcome = Welcome.create(@opts.welcome, doc_formatter)
36
34
  @guides = Guides.create(@opts.guides, doc_formatter, @opts)
37
35
  @videos = Videos.create(@opts.videos)
38
36
  @examples = Examples.create(@opts.examples, @opts)
39
- @categories = Categories.create(@opts.categories_path, doc_formatter, @relations)
40
- @news = News.create(@relations, doc_formatter, @opts)
37
+ @categories = Categories::Factory.create(@opts.categories_path, doc_formatter, @relations)
41
38
  end
42
39
 
43
40
  # Writes out the assets that can be written out separately:
@@ -0,0 +1,53 @@
1
+ require 'jsduck/tag_registry'
2
+
3
+ module JsDuck
4
+
5
+ # Detects the type of documentation object: class, method, cfg, etc
6
+ class BaseType
7
+ # Given parsed documentation and code, returns the tagname for
8
+ # documentation item.
9
+ #
10
+ # @param doc_map Result from DocParser turned into hash of tags.
11
+ # @param code Result from Ast#detect or CssParser#parse
12
+ # @returns :class or any of the member type symbols (:method, :event, ...).
13
+ #
14
+ def self.detect(doc_map, code)
15
+ if doc_map[:class] || doc_map[:override]
16
+ :class
17
+ elsif type = detect_member(doc_map)
18
+ type
19
+ elsif doc_map[:type]
20
+ # @type also results in property
21
+ :property
22
+ elsif code[:tagname] == :class
23
+ :class
24
+ elsif code[:tagname] == :css_mixin
25
+ :css_mixin
26
+ elsif doc_map[:cfg]
27
+ :cfg
28
+ elsif doc_map[:constructor]
29
+ :method
30
+ elsif doc_map[:params] || doc_map[:return]
31
+ :method
32
+ else
33
+ code[:tagname]
34
+ end
35
+ end
36
+
37
+ # Detects any of the members defined using a Tag class.
38
+ # Returns the detected member type on success.
39
+ # Otherwise nil.
40
+ def self.detect_member(doc_map)
41
+ type = TagRegistry.member_type_names.find {|type| doc_map[type] }
42
+
43
+ if type == :cfg
44
+ # Only detect a single @cfg as a :cfg.
45
+ # Multiple ones can be part of a class.
46
+ return (doc_map[:cfg].length == 1) ? :cfg : nil
47
+ else
48
+ type
49
+ end
50
+ end
51
+ end
52
+
53
+ end
@@ -1,46 +1,22 @@
1
1
  require 'jsduck/util/parallel'
2
2
  require 'jsduck/util/io'
3
+ require 'jsduck/parser'
3
4
  require 'jsduck/source/file'
4
- require 'jsduck/aggregator'
5
- require 'jsduck/class'
6
- require 'jsduck/relations'
7
5
  require 'jsduck/logger'
8
- require 'jsduck/inherit_doc'
9
- require 'jsduck/importer'
10
- require 'jsduck/return_values'
11
- require 'jsduck/lint'
12
- require 'jsduck/circular_deps'
13
6
 
14
7
  module JsDuck
15
8
 
16
- # Performs the parsing of all input files. Input files are read
17
- # from options object (originating from command line).
9
+ # Parses of all input files. Input files are read from options
10
+ # object (originating from command line).
18
11
  class BatchParser
19
- def initialize(opts)
20
- @opts = opts
21
- end
22
-
23
- # Array of Source::File objects.
24
- # Available after calling the #run method.
25
- attr_reader :parsed_files
26
-
27
- # Parses the files and returns instance of Relations class.
28
- def run
29
- @parsed_files = parallel_parse(@opts.input_files)
30
- result = aggregate(@parsed_files)
31
- @relations = filter_classes(result)
32
- apply_extra_processing
33
- return @relations
34
- end
35
12
 
36
- private
37
-
38
- # Parses the files in parallel using as many processes as available CPU-s
39
- def parallel_parse(filenames)
40
- Util::Parallel.map(filenames) do |fname|
13
+ def self.parse(opts)
14
+ Util::Parallel.map(opts.input_files) do |fname|
41
15
  Logger.log("Parsing", fname)
42
16
  begin
43
- Source::File.new(Util::IO.read(fname), fname, @opts)
17
+ source = Util::IO.read(fname)
18
+ docs = Parser.new.parse(source, fname, opts)
19
+ Source::File.new(source, docs, fname)
44
20
  rescue
45
21
  Logger.fatal_backtrace("Error while parsing #{fname}", $!)
46
22
  exit(1)
@@ -48,61 +24,6 @@ module JsDuck
48
24
  end
49
25
  end
50
26
 
51
- # Aggregates parsing results sequencially
52
- def aggregate(parsed_files)
53
- agr = Aggregator.new
54
- parsed_files.each do |file|
55
- Logger.log("Aggregating", file.filename)
56
- agr.aggregate(file)
57
- end
58
- agr.classify_orphans
59
- agr.create_global_class
60
- agr.remove_ignored_classes
61
- agr.create_accessors
62
- if @opts.ext4_events == true || (@opts.ext4_events == nil && agr.ext4?)
63
- agr.append_ext4_event_options
64
- end
65
- agr.process_enums
66
- # Ignore override classes after applying them to actual classes
67
- @opts.external_classes += agr.process_overrides.map {|o| o[:name] }
68
- agr.result
69
- end
70
-
71
- # Turns all aggregated data into Class objects.
72
- # Depending on --ignore-global either keeps or discards the global class.
73
- # Warnings for global members are printed regardless of that setting,
74
- # but of course can be turned off using --warnings=-global
75
- def filter_classes(docs)
76
- classes = []
77
- docs.each do |d|
78
- cls = Class.new(d)
79
- if d[:name] != "global"
80
- classes << cls
81
- else
82
- # add global class only if --ignore-global not specified
83
- classes << cls unless @opts.ignore_global
84
-
85
- # Print warning for each global member
86
- cls.all_local_members.each do |m|
87
- type = m[:tagname].to_s
88
- name = m[:name]
89
- file = m[:files][0]
90
- Logger.warn(:global, "Global #{type}: #{name}", file[:filename], file[:linenr])
91
- end
92
- end
93
- end
94
- Relations.new(classes, @opts.external_classes)
95
- end
96
-
97
- # Do all kinds of post-processing on relations.
98
- def apply_extra_processing
99
- CircularDeps.new(@relations).check_all
100
- InheritDoc.new(@relations).resolve_all
101
- Importer.import(@opts.imports, @relations, @opts.new_since)
102
- ReturnValues.auto_detect(@relations)
103
- Lint.new(@relations).run
104
- end
105
-
106
27
  end
107
28
 
108
29
  end
@@ -0,0 +1,77 @@
1
+ require 'jsduck/aggregator'
2
+ require 'jsduck/class'
3
+ require 'jsduck/relations'
4
+ require 'jsduck/logger'
5
+ require 'jsduck/util/singleton'
6
+ require 'jsduck/process/ignored_classes'
7
+ require 'jsduck/process/global_members'
8
+ require 'jsduck/process/enums'
9
+ require 'jsduck/process/accessors'
10
+ require 'jsduck/process/ext4_events'
11
+ require 'jsduck/process/overrides'
12
+ require 'jsduck/process/inherit_doc'
13
+ require 'jsduck/process/versions'
14
+ require 'jsduck/process/return_values'
15
+ require 'jsduck/process/lint'
16
+ require 'jsduck/process/circular_deps'
17
+
18
+ module JsDuck
19
+
20
+ # Processes the parsing results into Relations object.
21
+ class BatchProcessor
22
+ include Util::Singleton
23
+
24
+ # Processes array of Source::File objects from BatchParser and
25
+ # returns instance of Relations class.
26
+ def process(parsed_files, opts)
27
+ r = aggregate(parsed_files)
28
+ r = pre_process(r, opts)
29
+ r = to_class_objects(r, opts)
30
+ return post_process(r, opts)
31
+ end
32
+
33
+ private
34
+
35
+ # Aggregates parsing results sequencially
36
+ def aggregate(parsed_files)
37
+ agr = Aggregator.new
38
+ parsed_files.each do |file|
39
+ Logger.log("Aggregating", file.filename)
40
+ agr.aggregate(file)
41
+ end
42
+ agr.result
43
+ end
44
+
45
+ # Do all kinds of processing on the classes hash before turning it
46
+ # into Relations object.
47
+ def pre_process(classes_hash, opts)
48
+ Process::IgnoredClasses.new(classes_hash).process_all!
49
+ Process::GlobalMembers.new(classes_hash, opts).process_all!
50
+ Process::Accessors.new(classes_hash).process_all!
51
+ Process::Ext4Events.new(classes_hash, opts).process_all!
52
+ Process::Enums.new(classes_hash).process_all!
53
+ Process::Overrides.new(classes_hash, opts).process_all!
54
+
55
+ classes_hash.values
56
+ end
57
+
58
+ # Turns all aggregated data into Class objects and places the
59
+ # classes inside Relations container.
60
+ def to_class_objects(docs, opts)
61
+ classes = docs.map {|d| Class.new(d) }
62
+ Relations.new(classes, opts.external_classes)
63
+ end
64
+
65
+ # Do all kinds of post-processing on Relations object.
66
+ def post_process(relations, opts)
67
+ Process::CircularDeps.new(relations).process_all!
68
+ Process::InheritDoc.new(relations).process_all!
69
+ Process::Versions.new(relations, opts).process_all!
70
+ Process::ReturnValues.new(relations).process_all!
71
+ Process::Lint.new(relations).process_all!
72
+ relations
73
+ end
74
+
75
+ end
76
+
77
+ end
@@ -0,0 +1,83 @@
1
+ module JsDuck
2
+ module Categories
3
+
4
+ # Automatically divides all available classes into categories
5
+ class Auto
6
+ def initialize(relations)
7
+ @relations = relations
8
+ end
9
+
10
+ # Performs the generation
11
+ def generate
12
+ # list names of all public classes
13
+ class_names = @relations.to_a.find_all {|cls| !cls[:private] }.map {|cls| cls[:name] }
14
+
15
+ # divide classes into top-level categories by namespace
16
+ categories = categorize(class_names)
17
+
18
+ # in each category, create sub-categories
19
+ categories.each_pair do |ns, classes|
20
+ categories[ns] = categorize(classes, 1)
21
+ end
22
+
23
+ # Turn categories hash into array, sort everything
24
+ categories_array = []
25
+ categories.each_pair do |ns, groups|
26
+ groups_array = []
27
+ groups.each_pair do |gns, classes|
28
+ groups_array << {
29
+ "name" => gns,
30
+ "classes" => classes.sort
31
+ }
32
+ end
33
+ groups_array.sort! {|a, b| cat_compare(a, b) }
34
+ categories_array << {
35
+ "name" => ns,
36
+ "groups" => groups_array
37
+ }
38
+ end
39
+ categories_array.sort! {|a, b| cat_compare(a, b) }
40
+
41
+ return categories_array
42
+ end
43
+
44
+ # Divides classes into categories by namespace. Collapses
45
+ # categories having only one class into a category "Others..."
46
+ def categorize(class_names, level=0)
47
+ categories = {}
48
+ class_names.each do |name|
49
+ ns = name.split(/\./)[level] || name.split(/\./)[0]
50
+ categories[ns] = [] unless categories[ns]
51
+ categories[ns] << name
52
+ end
53
+
54
+ globals = []
55
+ categories.each_pair do |ns, classes|
56
+ if classes.length == 1
57
+ globals << classes[0]
58
+ categories.delete(ns)
59
+ end
60
+ end
61
+ if globals.length > 0
62
+ categories["Others..."] = globals
63
+ end
64
+
65
+ categories
66
+ end
67
+
68
+ # Comparison function for sorting categories that always places
69
+ # "Others..." category at the end.
70
+ def cat_compare(a, b)
71
+ if a["name"] == "Others..."
72
+ 1
73
+ elsif b["name"] == "Others..."
74
+ -1
75
+ else
76
+ a["name"] <=> b["name"]
77
+ end
78
+ end
79
+
80
+ end
81
+
82
+ end
83
+ end
@@ -0,0 +1,63 @@
1
+ module JsDuck
2
+ module Categories
3
+
4
+ # Renders class names for class categories page.
5
+ class ClassName
6
+ def initialize(doc_formatter, relations={})
7
+ @doc_formatter = doc_formatter
8
+ @relations = relations
9
+ end
10
+
11
+ # Renders the class name as a link or plain text.
12
+ #
13
+ # For new classes appends a star behind class name. For classes
14
+ # with new members appends list n small stars behind class name
15
+ # (reflecting the number of new members).
16
+ def render(name)
17
+ cls = @relations[name]
18
+ if cls
19
+ @doc_formatter.link(name, nil, name) + render_new_label(cls)
20
+ else
21
+ name
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ # Adds small star to new classes in the current version.
28
+ def render_new_label(cls)
29
+ if cls[:new]
30
+ "&nbsp;<span class='new-class' title='New class'>#{stars(1)}</span>"
31
+ else
32
+ n = new_members_count(cls)
33
+ if n > 0
34
+ title = "#{n} new member#{(n>1) ? 's' : ''}"
35
+ "&nbsp;<span class='new-members' title='#{title}'>#{stars(n)}</span>"
36
+ else
37
+ ""
38
+ end
39
+ end
40
+ end
41
+
42
+ # Produces string of n stars.
43
+ # First 3 stars are rendered as "<unicode-star>", the following as "+".
44
+ # At max 15 stars are rendered.
45
+ def stars(n)
46
+ if n > 15
47
+ stars(3) + ("+" * (15-3))
48
+ elsif n > 3
49
+ stars(3) + ("+" * (n-3))
50
+ else
51
+ "&#9733;" * n
52
+ end
53
+ end
54
+
55
+ # Returns number of new members the class has in the current version
56
+ def new_members_count(cls)
57
+ cls.find_members(:local => true).find_all {|m| m[:new] && !m[:private] }.length
58
+ end
59
+
60
+ end
61
+
62
+ end
63
+ end
@@ -0,0 +1,113 @@
1
+ require 'jsduck/logger'
2
+ require 'jsduck/categories/file'
3
+ require 'jsduck/categories/auto'
4
+ require 'jsduck/categories/class_name'
5
+
6
+ module JsDuck
7
+ module Categories
8
+
9
+ # Reads in categories and outputs them as HTML div
10
+ class Factory
11
+ def self.create(filename, doc_formatter, relations)
12
+ if filename
13
+ categories = Categories::File.new(filename, relations)
14
+ else
15
+ categories = Categories::Auto.new(relations)
16
+ end
17
+ Categories::Factory.new(categories.generate, doc_formatter, relations)
18
+ end
19
+
20
+ def initialize(categories, doc_formatter, relations={})
21
+ @categories = categories
22
+ @class_name = Categories::ClassName.new(doc_formatter, relations)
23
+ end
24
+
25
+ # Returns HTML listing of classes divided into categories
26
+ def to_html(style="")
27
+ html = @categories.map do |category|
28
+ [
29
+ "<div class='section'>",
30
+ "<h1>#{category['name']}</h1>",
31
+ render_columns(category['groups']),
32
+ "<div style='clear:both'></div>",
33
+ "</div>",
34
+ ]
35
+ end.flatten.join("\n")
36
+
37
+ return <<-EOHTML
38
+ <div id='categories-content' style='#{style}'>
39
+ #{html}
40
+ </div>
41
+ EOHTML
42
+ end
43
+
44
+ def render_columns(groups)
45
+ align = ["left-column", "middle-column", "right-column"]
46
+ i = -1
47
+ return split(groups, 3).map do |col|
48
+ i += 1
49
+ [
50
+ "<div class='#{align[i]}'>",
51
+ render_groups(col),
52
+ "</div>",
53
+ ]
54
+ end
55
+ end
56
+
57
+ def render_groups(groups)
58
+ return groups.map do |g|
59
+ [
60
+ "<h3>#{g['name']}</h3>",
61
+ "<ul class='links'>",
62
+ g["classes"].map {|cls| "<li>" + @class_name.render(cls) + "</li>" },
63
+ "</ul>",
64
+ ]
65
+ end
66
+ end
67
+
68
+ # Splits the array of items into n chunks so that the sum of
69
+ # largest chunk is as small as possible.
70
+ #
71
+ # This is a brute-force implementation - we just try all the
72
+ # combinations and choose the best one.
73
+ def split(items, n)
74
+ if n == 1
75
+ [items]
76
+ elsif items.length <= n
77
+ Array.new(n) {|i| items[i] ? [items[i]] : [] }
78
+ else
79
+ min_max = nil
80
+ min_arr = nil
81
+ i = 0
82
+ while i <= items.length-n
83
+ i += 1
84
+ # Try placing 1, 2, 3, ... items to first chunk.
85
+ # Calculate the remaining chunks recursively.
86
+ cols = [items[0,i]] + split(items[i, items.length], n-1)
87
+ max = max_sum(cols)
88
+ # Is this the optimal solution so far? Remember it.
89
+ if !min_max || max < min_max
90
+ min_max = max
91
+ min_arr = cols
92
+ end
93
+ end
94
+ min_arr
95
+ end
96
+ end
97
+
98
+ def max_sum(cols)
99
+ cols.map {|col| sum(col) }.max
100
+ end
101
+
102
+ # Finds the total size of items in array
103
+ #
104
+ # The size of one item is it's number of classes + the space for header
105
+ def sum(arr)
106
+ header_size = 3
107
+ arr.reduce(0) {|sum, item| sum + item["classes"].length + header_size }
108
+ end
109
+
110
+ end
111
+
112
+ end
113
+ end