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.
- data/.travis.yml +0 -1
- data/README.md +32 -6
- data/Rakefile +10 -18
- data/bin/compare +5 -5
- data/bin/jsduck +2 -3
- data/jsduck.gemspec +3 -4
- data/lib/jsduck/aggregator.rb +21 -80
- data/lib/jsduck/app.rb +7 -14
- data/lib/jsduck/app_data.rb +4 -5
- data/lib/jsduck/assets.rb +4 -7
- data/lib/jsduck/base_type.rb +53 -0
- data/lib/jsduck/batch_parser.rb +8 -87
- data/lib/jsduck/batch_processor.rb +77 -0
- data/lib/jsduck/categories/auto.rb +83 -0
- data/lib/jsduck/categories/class_name.rb +63 -0
- data/lib/jsduck/categories/factory.rb +113 -0
- data/lib/jsduck/categories/file.rb +75 -0
- data/lib/jsduck/class.rb +3 -9
- data/lib/jsduck/class_doc_expander.rb +1 -1
- data/lib/jsduck/css/lexer.rb +203 -0
- data/lib/jsduck/css/parser.rb +121 -0
- data/lib/jsduck/doc/comment.rb +40 -0
- data/lib/jsduck/doc/map.rb +23 -0
- data/lib/jsduck/doc/parser.rb +128 -0
- data/lib/jsduck/doc/processor.rb +52 -0
- data/lib/jsduck/doc/scanner.rb +76 -0
- data/lib/jsduck/doc/standard_tag_parser.rb +154 -0
- data/lib/jsduck/doc/subproperties.rb +64 -0
- data/lib/jsduck/docs_code_comparer.rb +31 -0
- data/lib/jsduck/export_writer.rb +2 -2
- data/lib/jsduck/exporter/app.rb +16 -4
- data/lib/jsduck/exporter/full.rb +2 -2
- data/lib/jsduck/format/batch.rb +58 -0
- data/lib/jsduck/format/class.rb +62 -0
- data/lib/jsduck/format/doc.rb +172 -0
- data/lib/jsduck/format/html_stack.rb +109 -0
- data/lib/jsduck/format/shortener.rb +55 -0
- data/lib/jsduck/format/subproperties.rb +64 -0
- data/lib/jsduck/guides.rb +32 -14
- data/lib/jsduck/index_html.rb +3 -1
- data/lib/jsduck/inline/auto_link.rb +2 -2
- data/lib/jsduck/inline/link.rb +4 -3
- data/lib/jsduck/inline/link_renderer.rb +2 -2
- data/lib/jsduck/inline/video.rb +8 -2
- data/lib/jsduck/js/ast.rb +361 -0
- data/lib/jsduck/js/esprima.rb +39 -0
- data/lib/jsduck/{esprima → js/esprima}/esprima.js +0 -0
- data/lib/jsduck/js/evaluator.rb +70 -0
- data/lib/jsduck/js/ext_patterns.rb +70 -0
- data/lib/jsduck/js/function.rb +206 -0
- data/lib/jsduck/js/node.rb +194 -0
- data/lib/jsduck/js/node_array.rb +36 -0
- data/lib/jsduck/js/parser.rb +223 -0
- data/lib/jsduck/js/serializer.rb +263 -0
- data/lib/jsduck/js/utils.rb +21 -0
- data/lib/jsduck/logger.rb +3 -13
- data/lib/jsduck/members_index.rb +3 -4
- data/lib/jsduck/merger.rb +25 -145
- data/lib/jsduck/options.rb +29 -132
- data/lib/jsduck/parser.rb +76 -0
- data/lib/jsduck/process/accessors.rb +133 -0
- data/lib/jsduck/process/circular_deps.rb +58 -0
- data/lib/jsduck/process/enums.rb +91 -0
- data/lib/jsduck/process/ext4_events.rb +43 -0
- data/lib/jsduck/process/global_members.rb +36 -0
- data/lib/jsduck/process/ignored_classes.rb +16 -0
- data/lib/jsduck/process/importer.rb +58 -0
- data/lib/jsduck/process/inherit_doc.rb +197 -0
- data/lib/jsduck/process/lint.rb +135 -0
- data/lib/jsduck/process/overrides.rb +99 -0
- data/lib/jsduck/process/return_values.rb +72 -0
- data/lib/jsduck/process/versions.rb +102 -0
- data/lib/jsduck/relations.rb +5 -0
- data/lib/jsduck/render/class.rb +144 -0
- data/lib/jsduck/render/sidebar.rb +97 -0
- data/lib/jsduck/render/signature.rb +94 -0
- data/lib/jsduck/render/subproperties.rb +99 -0
- data/lib/jsduck/render/tags.rb +38 -0
- data/lib/jsduck/search_data.rb +19 -13
- data/lib/jsduck/source/file.rb +8 -17
- data/lib/jsduck/tag/abstract.rb +4 -7
- data/lib/jsduck/tag/accessor.rb +10 -0
- data/lib/jsduck/tag/alias.rb +61 -0
- data/lib/jsduck/tag/alternate_class_names.rb +17 -0
- data/lib/jsduck/tag/aside.rb +28 -31
- data/lib/jsduck/tag/author.rb +9 -5
- data/lib/jsduck/tag/boolean_tag.rb +24 -0
- data/lib/jsduck/tag/cfg.rb +45 -0
- data/lib/jsduck/tag/chainable.rb +5 -7
- data/lib/jsduck/tag/class.rb +28 -0
- data/lib/jsduck/tag/class_list_tag.rb +40 -0
- data/lib/jsduck/tag/constructor.rb +24 -0
- data/lib/jsduck/tag/css_mixin.rb +17 -0
- data/lib/jsduck/tag/css_var.rb +29 -0
- data/lib/jsduck/tag/default.rb +31 -0
- data/lib/jsduck/tag/deprecated.rb +13 -27
- data/lib/jsduck/tag/deprecated_tag.rb +58 -0
- data/lib/jsduck/tag/doc.rb +32 -0
- data/lib/jsduck/tag/docauthor.rb +4 -5
- data/lib/jsduck/tag/enum.rb +70 -0
- data/lib/jsduck/tag/event.rb +28 -0
- data/lib/jsduck/tag/evented.rb +10 -0
- data/lib/jsduck/tag/extends.rb +45 -0
- data/lib/jsduck/tag/ftype.rb +18 -0
- data/lib/jsduck/tag/hide.rb +4 -11
- data/lib/jsduck/tag/ignore.rb +6 -7
- data/lib/jsduck/tag/inheritable.rb +10 -0
- data/lib/jsduck/tag/inheritdoc.rb +48 -0
- data/lib/jsduck/tag/markdown.rb +8 -6
- data/lib/jsduck/tag/member.rb +24 -0
- data/lib/jsduck/tag/method.rb +35 -0
- data/lib/jsduck/tag/mixins.rb +26 -0
- data/lib/jsduck/tag/name.rb +36 -0
- data/lib/jsduck/tag/new.rb +13 -27
- data/lib/jsduck/tag/override.rb +37 -0
- data/lib/jsduck/tag/overrides.rb +29 -0
- data/lib/jsduck/tag/param.rb +87 -0
- data/lib/jsduck/tag/preventable.rb +19 -10
- data/lib/jsduck/tag/private.rb +28 -13
- data/lib/jsduck/tag/property.rb +39 -0
- data/lib/jsduck/tag/protected.rb +5 -7
- data/lib/jsduck/tag/ptype.rb +18 -0
- data/lib/jsduck/tag/readonly.rb +4 -7
- data/lib/jsduck/tag/removed.rb +21 -29
- data/lib/jsduck/tag/required.rb +11 -9
- data/lib/jsduck/tag/requires.rb +12 -0
- data/lib/jsduck/tag/return.rb +47 -0
- data/lib/jsduck/tag/since.rb +19 -11
- data/lib/jsduck/tag/singleton.rb +15 -0
- data/lib/jsduck/tag/static.rb +5 -7
- data/lib/jsduck/tag/subproperties.rb +23 -0
- data/lib/jsduck/tag/tag.rb +208 -0
- data/lib/jsduck/tag/template.rb +14 -9
- data/lib/jsduck/tag/throws.rb +38 -0
- data/lib/jsduck/tag/type.rb +48 -0
- data/lib/jsduck/tag/uses.rb +12 -0
- data/lib/jsduck/tag/xtype.rb +30 -0
- data/lib/jsduck/tag_loader.rb +39 -0
- data/lib/jsduck/tag_registry.rb +189 -0
- data/lib/jsduck/type_parser.rb +3 -3
- data/lib/jsduck/web_writer.rb +2 -2
- data/lib/jsduck/welcome.rb +1 -1
- metadata +578 -538
- data/lib/jsduck/accessors.rb +0 -136
- data/lib/jsduck/ast.rb +0 -524
- data/lib/jsduck/auto_categories.rb +0 -80
- data/lib/jsduck/batch_formatter.rb +0 -60
- data/lib/jsduck/categories.rb +0 -73
- data/lib/jsduck/categories_class_name.rb +0 -37
- data/lib/jsduck/circular_deps.rb +0 -56
- data/lib/jsduck/class_formatter.rb +0 -102
- data/lib/jsduck/columns.rb +0 -56
- data/lib/jsduck/css_lexer.rb +0 -201
- data/lib/jsduck/css_parser.rb +0 -119
- data/lib/jsduck/doc_ast.rb +0 -319
- data/lib/jsduck/doc_formatter.rb +0 -142
- data/lib/jsduck/doc_parser.rb +0 -611
- data/lib/jsduck/doc_type.rb +0 -59
- data/lib/jsduck/enum.rb +0 -73
- data/lib/jsduck/esprima.rb +0 -51
- data/lib/jsduck/evaluator.rb +0 -69
- data/lib/jsduck/ext_patterns.rb +0 -58
- data/lib/jsduck/file_categories.rb +0 -76
- data/lib/jsduck/function_ast.rb +0 -206
- data/lib/jsduck/guide_anchors.rb +0 -32
- data/lib/jsduck/guide_toc.rb +0 -49
- data/lib/jsduck/html_stack.rb +0 -105
- data/lib/jsduck/importer.rb +0 -121
- data/lib/jsduck/inherit_doc.rb +0 -193
- data/lib/jsduck/js_parser.rb +0 -221
- data/lib/jsduck/lint.rb +0 -133
- data/lib/jsduck/meta_tag.rb +0 -88
- data/lib/jsduck/meta_tag_loader.rb +0 -67
- data/lib/jsduck/meta_tag_registry.rb +0 -111
- data/lib/jsduck/meta_tag_renderer.rb +0 -34
- data/lib/jsduck/news.rb +0 -128
- data/lib/jsduck/override.rb +0 -87
- data/lib/jsduck/renderer.rb +0 -361
- data/lib/jsduck/return_values.rb +0 -72
- data/lib/jsduck/serializer.rb +0 -262
- data/lib/jsduck/shortener.rb +0 -58
- data/lib/jsduck/signature_renderer.rb +0 -91
- 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/
|
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 =
|
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
|
data/lib/jsduck/batch_parser.rb
CHANGED
@@ -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
|
-
#
|
17
|
-
#
|
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
|
-
|
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
|
-
|
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
|
+
" <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
|
+
" <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
|
+
"★" * 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
|