jsduck 4.4.1 → 4.5.0
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.
- data/.travis.yml +1 -1
- data/README.md +1 -0
- data/Rakefile +1 -1
- data/jsduck.gemspec +3 -3
- data/lib/jsduck/ast.rb +59 -26
- data/lib/jsduck/doc_parser.rb +62 -9
- data/lib/jsduck/doc_type.rb +1 -2
- data/lib/jsduck/ext_patterns.rb +58 -0
- data/lib/jsduck/external_classes.rb +30 -0
- data/lib/jsduck/js_parser.rb +3 -3
- data/lib/jsduck/logger.rb +1 -0
- data/lib/jsduck/options.rb +9 -1
- data/lib/jsduck/override.rb +12 -4
- data/lib/jsduck/relations.rb +4 -3
- data/lib/jsduck/source/file_parser.rb +1 -1
- data/lib/jsduck/type_parser.rb +3 -3
- metadata +406 -400
    
        data/.travis.yml
    CHANGED
    
    
    
        data/README.md
    CHANGED
    
    | @@ -141,6 +141,7 @@ Who's using JSDuck? | |
| 141 141 | 
             
            - Appcelerator [Titanium SDK](http://docs.appcelerator.com/titanium/2.0/index.html)
         | 
| 142 142 | 
             
            - AT&T [API Platform SDK for HTML5](https://code-api-att.com/SenchaSdk20Drop23Docs/)
         | 
| 143 143 | 
             
            - Bryntum [Siesta unit testing framework](http://www.bryntum.com/products/siesta/docs/)
         | 
| 144 | 
            +
            - [CKEditor](http://docs.ckeditor.com)
         | 
| 144 145 | 
             
            - [GeoExt 2](https://github.com/geoext/geoext2)
         | 
| 145 146 | 
             
            - Rally Software [Rally App SDK](https://rally1.rallydev.com/apps/2.0p/doc/)
         | 
| 146 147 | 
             
            - [Sencha](http://docs.sencha.com) - obviously :)
         | 
    
        data/Rakefile
    CHANGED
    
    | @@ -104,7 +104,7 @@ def compress | |
| 104 104 | 
             
              dir = "template-min"
         | 
| 105 105 |  | 
| 106 106 | 
             
              # Create JSB3 file for Docs app
         | 
| 107 | 
            -
              system("sencha", "create", "jsb", "-a", "http://localhost/docs/", "-p", "#{dir}/app.jsb3")
         | 
| 107 | 
            +
              system("sencha", "create", "jsb", "-a", "http://localhost/~renesaarsoo/docs/", "-p", "#{dir}/app.jsb3")
         | 
| 108 108 | 
             
              # Concatenate files listed in JSB3 file
         | 
| 109 109 | 
             
              system("sencha", "build", "-p", "#{dir}/app.jsb3", "-d", dir)
         | 
| 110 110 |  | 
    
        data/jsduck.gemspec
    CHANGED
    
    | @@ -2,8 +2,8 @@ Gem::Specification.new do |s| | |
| 2 2 | 
             
              s.required_rubygems_version = ">= 1.3.5"
         | 
| 3 3 |  | 
| 4 4 | 
             
              s.name = 'jsduck'
         | 
| 5 | 
            -
              s.version = '4. | 
| 6 | 
            -
              s.date = '2012- | 
| 5 | 
            +
              s.version = '4.5.0'
         | 
| 6 | 
            +
              s.date = '2012-12-06'
         | 
| 7 7 | 
             
              s.summary = "Simple JavaScript Duckumentation generator"
         | 
| 8 8 | 
             
              s.description = "Documentation generator for Sencha JS frameworks"
         | 
| 9 9 | 
             
              s.homepage = "https://github.com/senchalabs/jsduck"
         | 
| @@ -22,7 +22,7 @@ Gem::Specification.new do |s| | |
| 22 22 | 
             
              s.add_dependency 'rdiscount'
         | 
| 23 23 | 
             
              s.add_dependency 'json'
         | 
| 24 24 | 
             
              s.add_dependency 'parallel'
         | 
| 25 | 
            -
              s.add_dependency 'therubyracer'
         | 
| 25 | 
            +
              s.add_dependency 'therubyracer', '= 0.10.1'
         | 
| 26 26 |  | 
| 27 27 | 
             
              s.add_development_dependency 'rspec'
         | 
| 28 28 | 
             
              s.add_development_dependency 'rake'
         | 
    
        data/lib/jsduck/ast.rb
    CHANGED
    
    | @@ -1,6 +1,7 @@ | |
| 1 1 | 
             
            require "jsduck/serializer"
         | 
| 2 2 | 
             
            require "jsduck/evaluator"
         | 
| 3 3 | 
             
            require "jsduck/function_ast"
         | 
| 4 | 
            +
            require "jsduck/ext_patterns"
         | 
| 4 5 |  | 
| 5 6 | 
             
            module JsDuck
         | 
| 6 7 |  | 
| @@ -10,21 +11,10 @@ module JsDuck | |
| 10 11 | 
             
                def initialize(docs = [], options = {})
         | 
| 11 12 | 
             
                  @serializer = JsDuck::Serializer.new
         | 
| 12 13 | 
             
                  @evaluator = JsDuck::Evaluator.new
         | 
| 13 | 
            -
                  @ | 
| 14 | 
            +
                  @ext_patterns = JsDuck::ExtPatterns.new(options[:ext_namespaces] || ["Ext"])
         | 
| 14 15 | 
             
                  @docs = docs
         | 
| 15 16 | 
             
                end
         | 
| 16 17 |  | 
| 17 | 
            -
                # Given Array of alternate Ext namespaces builds list of patterns
         | 
| 18 | 
            -
                # for detecting Ext.define:
         | 
| 19 | 
            -
                #
         | 
| 20 | 
            -
                # ["Ext","Foo"] --> ["Ext.define", "Ext.ClassManager.create", "Foo.define", "Foo.ClassManager.create"]
         | 
| 21 | 
            -
                #
         | 
| 22 | 
            -
                def build_ext_define_patterns(namespaces)
         | 
| 23 | 
            -
                  namespaces.map do |ns|
         | 
| 24 | 
            -
                    [ns + ".define", ns + ".ClassManager.create"]
         | 
| 25 | 
            -
                  end.flatten
         | 
| 26 | 
            -
                end
         | 
| 27 | 
            -
             | 
| 28 18 | 
             
                # Performs the detection of code in all docsets.
         | 
| 29 19 | 
             
                #
         | 
| 30 20 | 
             
                # @returns the processed array of docsets. (But it does it
         | 
| @@ -68,7 +58,11 @@ module JsDuck | |
| 68 58 | 
             
                  if exp && ext_define?(exp)
         | 
| 69 59 | 
             
                    make_class(to_value(exp["arguments"][0]), exp)
         | 
| 70 60 |  | 
| 71 | 
            -
                  #  | 
| 61 | 
            +
                  # Ext.override(Class, {})
         | 
| 62 | 
            +
                  elsif exp && ext_override?(exp)
         | 
| 63 | 
            +
                    make_class("", exp)
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                  # foo = Ext.extend(Parent, {})
         | 
| 72 66 | 
             
                  elsif exp && assignment?(exp) && ext_extend?(exp["right"])
         | 
| 73 67 | 
             
                    make_class(to_s(exp["left"]), exp["right"])
         | 
| 74 68 |  | 
| @@ -76,7 +70,7 @@ module JsDuck | |
| 76 70 | 
             
                  elsif exp && assignment?(exp) && class_name?(to_s(exp["left"]))
         | 
| 77 71 | 
             
                    make_class(to_s(exp["left"]), exp["right"])
         | 
| 78 72 |  | 
| 79 | 
            -
                  # var foo = Ext.extend( | 
| 73 | 
            +
                  # var foo = Ext.extend(Parent, {})
         | 
| 80 74 | 
             
                  elsif var && var["init"] && ext_extend?(var["init"])
         | 
| 81 75 | 
             
                    make_class(to_s(var["id"]), var["init"])
         | 
| 82 76 |  | 
| @@ -88,6 +82,10 @@ module JsDuck | |
| 88 82 | 
             
                  elsif function?(ast) && class_name?(to_s(ast["id"]))
         | 
| 89 83 | 
             
                    make_class(to_s(ast["id"]))
         | 
| 90 84 |  | 
| 85 | 
            +
                  # { ... }
         | 
| 86 | 
            +
                  elsif object?(ast)
         | 
| 87 | 
            +
                    make_class("", ast)
         | 
| 88 | 
            +
             | 
| 91 89 | 
             
                  # function foo() {}
         | 
| 92 90 | 
             
                  elsif function?(ast)
         | 
| 93 91 | 
             
                    make_method(to_s(ast["id"]), ast)
         | 
| @@ -108,6 +106,10 @@ module JsDuck | |
| 108 106 | 
             
                  elsif property?(ast) && function?(ast["value"])
         | 
| 109 107 | 
             
                    make_method(key_value(ast["key"]), ast["value"])
         | 
| 110 108 |  | 
| 109 | 
            +
                  # this.fireEvent("foo", ...)
         | 
| 110 | 
            +
                  elsif exp && fire_event?(exp)
         | 
| 111 | 
            +
                    make_event(to_value(exp["arguments"][0]))
         | 
| 112 | 
            +
             | 
| 111 113 | 
             
                  # foo = ...
         | 
| 112 114 | 
             
                  elsif exp && assignment?(exp)
         | 
| 113 115 | 
             
                    make_property(to_s(exp["left"]), exp["right"])
         | 
| @@ -152,11 +154,15 @@ module JsDuck | |
| 152 154 | 
             
                end
         | 
| 153 155 |  | 
| 154 156 | 
             
                def ext_define?(ast)
         | 
| 155 | 
            -
                  call?(ast) &&  | 
| 157 | 
            +
                  call?(ast) && ext_pattern?("Ext.define", ast["callee"])
         | 
| 156 158 | 
             
                end
         | 
| 157 159 |  | 
| 158 160 | 
             
                def ext_extend?(ast)
         | 
| 159 | 
            -
                  call?(ast) &&  | 
| 161 | 
            +
                  call?(ast) && ext_pattern?("Ext.extend", ast["callee"])
         | 
| 162 | 
            +
                end
         | 
| 163 | 
            +
             | 
| 164 | 
            +
                def ext_override?(ast)
         | 
| 165 | 
            +
                  call?(ast) && ext_pattern?("Ext.override", ast["callee"])
         | 
| 160 166 | 
             
                end
         | 
| 161 167 |  | 
| 162 168 | 
             
                def function?(ast)
         | 
| @@ -164,7 +170,15 @@ module JsDuck | |
| 164 170 | 
             
                end
         | 
| 165 171 |  | 
| 166 172 | 
             
                def empty_fn?(ast)
         | 
| 167 | 
            -
                  ast["type"] == "MemberExpression" &&  | 
| 173 | 
            +
                  ast["type"] == "MemberExpression" && ext_pattern?("Ext.emptyFn", ast)
         | 
| 174 | 
            +
                end
         | 
| 175 | 
            +
             | 
| 176 | 
            +
                def ext_pattern?(pattern, ast)
         | 
| 177 | 
            +
                  @ext_patterns.matches?(pattern, to_s(ast))
         | 
| 178 | 
            +
                end
         | 
| 179 | 
            +
             | 
| 180 | 
            +
                def fire_event?(ast)
         | 
| 181 | 
            +
                  call?(ast) && to_s(ast["callee"]) == "this.fireEvent"
         | 
| 168 182 | 
             
                end
         | 
| 169 183 |  | 
| 170 184 | 
             
                def var?(ast)
         | 
| @@ -183,6 +197,10 @@ module JsDuck | |
| 183 197 | 
             
                  ast["type"] == "Literal" && ast["value"].is_a?(String)
         | 
| 184 198 | 
             
                end
         | 
| 185 199 |  | 
| 200 | 
            +
                def object?(ast)
         | 
| 201 | 
            +
                  ast["type"] == "ObjectExpression"
         | 
| 202 | 
            +
                end
         | 
| 203 | 
            +
             | 
| 186 204 | 
             
                # Class name begins with upcase char
         | 
| 187 205 | 
             
                def class_name?(name)
         | 
| 188 206 | 
             
                  return name.split(/\./).last =~ /\A[A-Z]/
         | 
| @@ -196,15 +214,13 @@ module JsDuck | |
| 196 214 |  | 
| 197 215 | 
             
                  # apply information from Ext.extend, Ext.define, or {}
         | 
| 198 216 | 
             
                  if ast
         | 
| 199 | 
            -
                    if  | 
| 200 | 
            -
                      args = ast["arguments"]
         | 
| 201 | 
            -
                      cls[:extends] = to_s(args[0])
         | 
| 202 | 
            -
                      if args.length == 2 && args[1]["type"] == "ObjectExpression"
         | 
| 203 | 
            -
                        detect_class_members_from_object(cls, args[1])
         | 
| 204 | 
            -
                      end
         | 
| 205 | 
            -
                    elsif ext_define?(ast)
         | 
| 217 | 
            +
                    if ext_define?(ast)
         | 
| 206 218 | 
             
                      detect_ext_define(cls, ast)
         | 
| 207 | 
            -
                    elsif ast | 
| 219 | 
            +
                    elsif ext_extend?(ast)
         | 
| 220 | 
            +
                      detect_ext_something(:extends, cls, ast)
         | 
| 221 | 
            +
                    elsif ext_override?(ast)
         | 
| 222 | 
            +
                      detect_ext_something(:override, cls, ast)
         | 
| 223 | 
            +
                    elsif object?(ast)
         | 
| 208 224 | 
             
                      detect_class_members_from_object(cls, ast)
         | 
| 209 225 | 
             
                    elsif ast["type"] == "ArrayExpression"
         | 
| 210 226 | 
             
                      detect_class_members_from_array(cls, ast)
         | 
| @@ -214,6 +230,16 @@ module JsDuck | |
| 214 230 | 
             
                  return cls
         | 
| 215 231 | 
             
                end
         | 
| 216 232 |  | 
| 233 | 
            +
                # Detection of Ext.extend() or Ext.override().
         | 
| 234 | 
            +
                # The type parameter must be correspondingly either :extend or :override.
         | 
| 235 | 
            +
                def detect_ext_something(type, cls, ast)
         | 
| 236 | 
            +
                  args = ast["arguments"]
         | 
| 237 | 
            +
                  cls[type] = to_s(args[0])
         | 
| 238 | 
            +
                  if args.length == 2 && object?(args[1])
         | 
| 239 | 
            +
                    detect_class_members_from_object(cls, args[1])
         | 
| 240 | 
            +
                  end
         | 
| 241 | 
            +
                end
         | 
| 242 | 
            +
             | 
| 217 243 | 
             
                # Inspects Ext.define() and copies detected properties over to the
         | 
| 218 244 | 
             
                # given cls Hash
         | 
| 219 245 | 
             
                def detect_ext_define(cls, ast)
         | 
| @@ -419,6 +445,13 @@ module JsDuck | |
| 419 445 | 
             
                  end
         | 
| 420 446 | 
             
                end
         | 
| 421 447 |  | 
| 448 | 
            +
                def make_event(name)
         | 
| 449 | 
            +
                  return {
         | 
| 450 | 
            +
                    :tagname => :event,
         | 
| 451 | 
            +
                    :name => name,
         | 
| 452 | 
            +
                  }
         | 
| 453 | 
            +
                end
         | 
| 454 | 
            +
             | 
| 422 455 | 
             
                def make_property(name=nil, ast=nil, tagname=:property)
         | 
| 423 456 | 
             
                  return {
         | 
| 424 457 | 
             
                    :tagname => tagname,
         | 
| @@ -461,7 +494,7 @@ module JsDuck | |
| 461 494 | 
             
                # are turned into strings, but values are left as is for further
         | 
| 462 495 | 
             
                # processing.
         | 
| 463 496 | 
             
                def each_pair_in_object_expression(ast)
         | 
| 464 | 
            -
                  return unless ast && ast | 
| 497 | 
            +
                  return unless ast && object?(ast)
         | 
| 465 498 |  | 
| 466 499 | 
             
                  ast["properties"].each do |p|
         | 
| 467 500 | 
             
                    yield(key_value(p["key"]), p["value"], p)
         | 
    
        data/lib/jsduck/doc_parser.rb
    CHANGED
    
    | @@ -1,5 +1,6 @@ | |
| 1 1 | 
             
            require 'strscan'
         | 
| 2 2 | 
             
            require 'jsduck/meta_tag_registry'
         | 
| 3 | 
            +
            require 'jsduck/logger'
         | 
| 3 4 |  | 
| 4 5 | 
             
            module JsDuck
         | 
| 5 6 |  | 
| @@ -28,7 +29,9 @@ module JsDuck | |
| 28 29 | 
             
                  @meta_tags = MetaTagRegistry.instance
         | 
| 29 30 | 
             
                end
         | 
| 30 31 |  | 
| 31 | 
            -
                def parse(input)
         | 
| 32 | 
            +
                def parse(input, filename="", linenr=0)
         | 
| 33 | 
            +
                  @filename = filename
         | 
| 34 | 
            +
                  @linenr = linenr
         | 
| 32 35 | 
             
                  @tags = []
         | 
| 33 36 | 
             
                  @input = StringScanner.new(purify(input))
         | 
| 34 37 | 
             
                  parse_loop
         | 
| @@ -77,6 +80,11 @@ module JsDuck | |
| 77 80 | 
             
                  @tags << @current_tag = {:tagname => tag, :doc => ""}
         | 
| 78 81 | 
             
                end
         | 
| 79 82 |  | 
| 83 | 
            +
                def remove_last_tag
         | 
| 84 | 
            +
                  @tags.pop
         | 
| 85 | 
            +
                  @current_tag = @tags.last
         | 
| 86 | 
            +
                end
         | 
| 87 | 
            +
             | 
| 80 88 | 
             
                def parse_loop
         | 
| 81 89 | 
             
                  add_tag(:default)
         | 
| 82 90 | 
             
                  while !@input.eos? do
         | 
| @@ -141,19 +149,56 @@ module JsDuck | |
| 141 149 | 
             
                    elsif look(/@evented\b/)
         | 
| 142 150 | 
             
                      boolean_at_tag(/@evented/, :evented)
         | 
| 143 151 | 
             
                    elsif look(/@/)
         | 
| 144 | 
            -
                       | 
| 145 | 
            -
                      tag = @meta_tags[look(/\w+/)]
         | 
| 146 | 
            -
                      if tag
         | 
| 147 | 
            -
                        meta_at_tag(tag)
         | 
| 148 | 
            -
                      else
         | 
| 149 | 
            -
                        @current_tag[:doc] += "@"
         | 
| 150 | 
            -
                      end
         | 
| 152 | 
            +
                      other_at_tag
         | 
| 151 153 | 
             
                    elsif look(/[^@]/)
         | 
| 152 | 
            -
                       | 
| 154 | 
            +
                      skip_to_next_at_tag
         | 
| 153 155 | 
             
                    end
         | 
| 154 156 | 
             
                  end
         | 
| 155 157 | 
             
                end
         | 
| 156 158 |  | 
| 159 | 
            +
                # Skips until the beginning of next @tag.
         | 
| 160 | 
            +
                #
         | 
| 161 | 
            +
                # There must be space before the next @tag - this ensures that we
         | 
| 162 | 
            +
                # don't detect tags inside "foo@example.com" or "{@link}".
         | 
| 163 | 
            +
                #
         | 
| 164 | 
            +
                # Also check that the @tag is not part of an indented code block -
         | 
| 165 | 
            +
                # in which case we also ignore the tag.
         | 
| 166 | 
            +
                def skip_to_next_at_tag
         | 
| 167 | 
            +
                  @current_tag[:doc] += match(/[^@]+/)
         | 
| 168 | 
            +
             | 
| 169 | 
            +
                  while look(/@/) && (!prev_char_is_whitespace? || indented_as_code?)
         | 
| 170 | 
            +
                    @current_tag[:doc] += match(/@+[^@]+/)
         | 
| 171 | 
            +
                  end
         | 
| 172 | 
            +
                end
         | 
| 173 | 
            +
             | 
| 174 | 
            +
                def prev_char_is_whitespace?
         | 
| 175 | 
            +
                  @current_tag[:doc][-1,1] =~ /\s/
         | 
| 176 | 
            +
                end
         | 
| 177 | 
            +
             | 
| 178 | 
            +
                def indented_as_code?
         | 
| 179 | 
            +
                  @current_tag[:doc] =~ /^ {4,}[^\n]*\Z/
         | 
| 180 | 
            +
                end
         | 
| 181 | 
            +
             | 
| 182 | 
            +
                # Processes anything else beginning with @-sign.
         | 
| 183 | 
            +
                #
         | 
| 184 | 
            +
                # - When @ is not followed by any word chards, do nothing.
         | 
| 185 | 
            +
                # - When it's one of the meta-tags, process it as such.
         | 
| 186 | 
            +
                # - When it's something else, print a warning.
         | 
| 187 | 
            +
                #
         | 
| 188 | 
            +
                def other_at_tag
         | 
| 189 | 
            +
                  match(/@/)
         | 
| 190 | 
            +
             | 
| 191 | 
            +
                  name = look(/\w+/)
         | 
| 192 | 
            +
                  tag = @meta_tags[name]
         | 
| 193 | 
            +
             | 
| 194 | 
            +
                  if tag
         | 
| 195 | 
            +
                    meta_at_tag(tag)
         | 
| 196 | 
            +
                  elsif name
         | 
| 197 | 
            +
                    Logger.warn(:tag, "Unsupported tag: @#{name}", @filename, @linenr)
         | 
| 198 | 
            +
                    @current_tag[:doc] += "@"
         | 
| 199 | 
            +
                  end
         | 
| 200 | 
            +
                end
         | 
| 201 | 
            +
             | 
| 157 202 | 
             
                # Matches the given meta-tag
         | 
| 158 203 | 
             
                def meta_at_tag(tag)
         | 
| 159 204 | 
             
                  prev_tag = @current_tag
         | 
| @@ -302,6 +347,14 @@ module JsDuck | |
| 302 347 | 
             
                  add_tag(:override)
         | 
| 303 348 | 
             
                  maybe_ident_chain(:class)
         | 
| 304 349 | 
             
                  skip_white
         | 
| 350 | 
            +
             | 
| 351 | 
            +
                  # When @override not followed by class name, ignore the tag.
         | 
| 352 | 
            +
                  # That's because the current ext codebase has some methods
         | 
| 353 | 
            +
                  # tagged with @override to denote they override something.
         | 
| 354 | 
            +
                  # But that's not what @override is meant for in JSDuck.
         | 
| 355 | 
            +
                  unless @current_tag[:class]
         | 
| 356 | 
            +
                    remove_last_tag
         | 
| 357 | 
            +
                  end
         | 
| 305 358 | 
             
                end
         | 
| 306 359 |  | 
| 307 360 | 
             
                # matches @type {type}  or  @type type
         | 
    
        data/lib/jsduck/doc_type.rb
    CHANGED
    
    
| @@ -0,0 +1,58 @@ | |
| 1 | 
            +
            module JsDuck
         | 
| 2 | 
            +
             | 
| 3 | 
            +
              # Identifies Ext JS builtins like Ext.define and Ext.extend, taking
         | 
| 4 | 
            +
              # also into account the possibility of aliasing the Ext namespace.
         | 
| 5 | 
            +
              #
         | 
| 6 | 
            +
              # For example when the following command line option is used:
         | 
| 7 | 
            +
              #
         | 
| 8 | 
            +
              #     --ext-namespaces=Ext,MyApp
         | 
| 9 | 
            +
              #
         | 
| 10 | 
            +
              # we need to identify both Ext.define and MyApp.define, but
         | 
| 11 | 
            +
              # Ext.define is additionally aliased withing ExtJS as
         | 
| 12 | 
            +
              # Ext.ClassManager.create, so we also need to recognize
         | 
| 13 | 
            +
              # Ext.ClassManager.create and MyApp.ClassManager.create.
         | 
| 14 | 
            +
              #
         | 
| 15 | 
            +
              # The matches? method will take care of identifying all these four
         | 
| 16 | 
            +
              # cases:
         | 
| 17 | 
            +
              #
         | 
| 18 | 
            +
              #     ps = ExtPatterns.new(["Ext", "MyApp"])
         | 
| 19 | 
            +
              #     matches?("Ext.define", "MyApp.define") --> true
         | 
| 20 | 
            +
              #
         | 
| 21 | 
            +
              class ExtPatterns
         | 
| 22 | 
            +
                def initialize(namespaces)
         | 
| 23 | 
            +
                  @patterns = {
         | 
| 24 | 
            +
                    "Ext.define" => build_patterns(namespaces, [".define", ".ClassManager.create"]),
         | 
| 25 | 
            +
                    "Ext.extend" => build_patterns(namespaces, [".extend"]),
         | 
| 26 | 
            +
                    "Ext.override" => build_patterns(namespaces, [".override"]),
         | 
| 27 | 
            +
                    "Ext.emptyFn" => build_patterns(namespaces, [".emptyFn"]),
         | 
| 28 | 
            +
                  }
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                # True when string matches the given pattern type.
         | 
| 32 | 
            +
                #
         | 
| 33 | 
            +
                # Pattern type is one of: "Ext.define", "Ext.extend",
         | 
| 34 | 
            +
                # "Ext.override", "Ext.emptyFn"
         | 
| 35 | 
            +
                def matches?(pattern, string)
         | 
| 36 | 
            +
                  @patterns[pattern].include?(string)
         | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                private
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                # Given Array of alternate Ext namespaces builds list of patterns
         | 
| 42 | 
            +
                # for detecting Ext.define or some other construct:
         | 
| 43 | 
            +
                #
         | 
| 44 | 
            +
                # build_patterns(["Ext", "Foo"], [".define"]) --> ["Ext.define", "Foo.define"]
         | 
| 45 | 
            +
                #
         | 
| 46 | 
            +
                def build_patterns(namespaces, suffixes)
         | 
| 47 | 
            +
                  patterns = []
         | 
| 48 | 
            +
                  namespaces.each do |ns|
         | 
| 49 | 
            +
                    suffixes.each do |suffix|
         | 
| 50 | 
            +
                      patterns << ns + suffix
         | 
| 51 | 
            +
                    end
         | 
| 52 | 
            +
                  end
         | 
| 53 | 
            +
                  patterns
         | 
| 54 | 
            +
                end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
              end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
            end
         | 
| @@ -0,0 +1,30 @@ | |
| 1 | 
            +
            module JsDuck
         | 
| 2 | 
            +
             | 
| 3 | 
            +
              # Handles patterns of external classes.
         | 
| 4 | 
            +
              #
         | 
| 5 | 
            +
              # A pattern can be a simple classname or a one with a wildcard "*".
         | 
| 6 | 
            +
              class ExternalClasses
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                def initialize(classnames = [])
         | 
| 9 | 
            +
                  @class_names = {}
         | 
| 10 | 
            +
                  @patterns = []
         | 
| 11 | 
            +
                  classnames.each do |name|
         | 
| 12 | 
            +
                    if name =~ /\*/
         | 
| 13 | 
            +
                      @patterns << make_pattern(name)
         | 
| 14 | 
            +
                    else
         | 
| 15 | 
            +
                      @class_names[name] = true
         | 
| 16 | 
            +
                    end
         | 
| 17 | 
            +
                  end
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                # True if the classname matches an external class pattern.
         | 
| 21 | 
            +
                def is?(classname)
         | 
| 22 | 
            +
                  @class_names[classname] || @patterns.any? {|p| classname =~ p }
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                def make_pattern(pattern)
         | 
| 26 | 
            +
                  Regexp.new("^" + pattern.split(/\*/, -1).map {|s| Regexp.escape(s) }.join(".*") + "$")
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
              end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
            end
         | 
    
        data/lib/jsduck/js_parser.rb
    CHANGED
    
    | @@ -138,17 +138,17 @@ module JsDuck | |
| 138 138 |  | 
| 139 139 | 
             
                # True if range A is less than range B
         | 
| 140 140 | 
             
                def less(a, b)
         | 
| 141 | 
            -
                  return a[1]  | 
| 141 | 
            +
                  return a[1] <= b[0]
         | 
| 142 142 | 
             
                end
         | 
| 143 143 |  | 
| 144 144 | 
             
                # True if range A is greater than range B
         | 
| 145 145 | 
             
                def greater(a, b)
         | 
| 146 | 
            -
                  return a[0]  | 
| 146 | 
            +
                  return a[0] >= b[1]
         | 
| 147 147 | 
             
                end
         | 
| 148 148 |  | 
| 149 149 | 
             
                # True if range A is within range B
         | 
| 150 150 | 
             
                def within(a, b)
         | 
| 151 | 
            -
                  return b[0]  | 
| 151 | 
            +
                  return b[0] <= a[0] && a[1] <= b[1]
         | 
| 152 152 | 
             
                end
         | 
| 153 153 |  | 
| 154 154 |  |