class Blufin::ScannerJs
Constants
- DATA_TYPES
Public Class Methods
scan(path)
click to toggle source
Scan Javascript code. @return void
# File lib/scan/scanner_js.rb, line 9 def self.scan(path) # Check path exists. Blufin::Terminal::error("Path does not exist: #{Blufin::Terminal::format_invalid(path)}") unless Blufin::Files::path_exists(path) @path = path @data = {} @errors = [] # Get all file(s) in path. Blufin::Files::get_files_in_dir(path, 'js').each { |file| scan_file(file) } return @data, @errors end
Private Class Methods
extract_type(string, allow_void = false)
click to toggle source
Attempts to extract 'string' from something like '{string}'. Will throw Error if anything isn't right. @return string
# File lib/scan/scanner_js.rb, line 176 def self.extract_type(string, allow_void = false) types = DATA_TYPES types << 'void' if allow_void type = string.gsub(/^\{/, '').gsub(/\}$/, '') types_compare = type =~ /\|/ ? type.split('|') : [type] types_compare.each do |type_inner| raise RuntimeError, "Unrecognized data type: #{type_inner}" unless types.include?(type_inner.downcase) raise RuntimeError, "Data types must be lowercase, found: #{type_inner}" if type_inner.downcase != 'array' && type_inner != type_inner.downcase end type end
parse_comment(line)
click to toggle source
Parses comments. @return void
# File lib/scan/scanner_js.rb, line 96 def self.parse_comment(line) if line =~ /^\s*\/\*+\s*.*$/ # /** OR * return elsif line =~ /^\s*\/+\s*\w.*$/ # // some comment return elsif line =~ /^\s*\*\/\s*$/ # */ return elsif line =~ /^\s*\*+\s*[A-Za-z0-9].*$/ # * some comment @docs[:description] = [] if @docs[:description].nil? @docs[:description] << line.gsub(/^\s*\*\s*/, '').strip elsif line =~ /^\s*\*+\s*@param\s*\{(\w|\*)+\}*.+$/ # * @param {string} parent - The parent key. ls = line.gsub(/^\s*\*+\s*@param\s+/, '').split(' ') type = extract_type(ls[0]) param_name = ls[1] param_name = param_name.strip.gsub(/^\[/, '').gsub(/]$/, '') hyphen = ls[2] description = ls.drop(3).join(' ') raise RuntimeError, "Duplicate parameter: #{param_name}" if @docs[:params].is_a?(Hash) && @docs[:params].has_key?(param_name) raise RuntimeError, "Expected hyphen after parameter name. IE: {#{type}} #{param_name} - ..." if ls.length > 2 && hyphen != '-' @docs[:params] = {} if @docs[:params].nil? @docs[:params][param_name] = {} @docs[:params][param_name][:type] = type @docs[:params][param_name][:description] = description elsif line =~ /^\s*\*+\s*@returns\s+\{(\w|\*)+\}.*$/ # * @returns {boolean} raise RuntimeError, 'Multiple return statement(s).' if @docs.has_key?(:return) ls = line.gsub(/^\s*\*+\s*@returns\s+/, '').split(' ') @docs[:return] = nil @docs[:return] = extract_type(ls[0], true) if ls.any? elsif line.strip == '*' return else raise RuntimeError, 'Something is wrong with this line, it failed to parse.' end end
parse_method_definition(line)
click to toggle source
Parses the 1st line of a method and extracts information about the parameters. @return void
# File lib/scan/scanner_js.rb, line 139 def self.parse_method_definition(line) method_name = line.strip.gsub(/\(.*$/, '') method_private = method_name =~ /^_/ ? true : false raise RuntimeError, "Duplicate method: #{method_name}" if @data[@file_short][:methods].keys.include?(method_name) matches = line.match(/\(.*\)/) raise RuntimeError, 'Unable to extract method parameters.' unless matches.length == 1 params = matches[0].strip.gsub(/^\(/, '').gsub(/\)$/, '') params = params.split(',') params.each do |param| param.strip! if param =~ /\w+\s*=\s*\w+/ ps = param.split('=') raise RuntimeError, "Expected exactly one equal (=) sign, got: #{ps.length - 1}" unless ps.length == 2 param_extracted = ps[0].strip raise RuntimeError, "Duplicate parameter: #{param_extracted}" if @params.has_key?(param_extracted) @params[param_extracted] = {:default => ps[1].strip} elsif param =~ /\w+/ raise RuntimeError, "Duplicate parameter: #{param}" if @params.has_key?(param) @params[param] = {} else raise RuntimeError, "Unrecognized parameter: #{param}" end end @docs = {:params => {}} unless @docs.is_a?(Hash) @docs[:params] = {} unless @docs[:params].is_a?(Hash) @data[@file_short][:methods][method_name] = { :line => @line, :line_number => @line_number, :docs => @docs, :params => @params, :private => method_private } end
scan_file(file)
click to toggle source
Scans a file. @return void
# File lib/scan/scanner_js.rb, line 29 def self.scan_file(file) @file = file @file_short = Blufin::Strings::remove_surrounding_slashes(file.gsub(@path, '')) @data[@file_short] = {} @data[@file_short][:methods] = {} @data[@file_short][:file] = file @line = nil @line_number = 0 @params = nil @docs = nil @docs_active = false @method_active = false Blufin::Files::read_file(file).each do |line| begin @line = line.gsub("\n", '') @line_number += 1 if @line =~ /^\s*\/+\s*\w.*$/ # // some comment parse_comment(@line) elsif @line =~ /^\s*\/\*+\s*.*$/ # /** OR * @docs = {} @docs_active = true elsif @line =~ /^\s{4}\w+\s*(:\s*function)?\(.*\)\s*\{\s*(\}|\},)?\s*$/ # clear() {} # clear() {}, # clear(key) { # clear(key, value) { # clear(key, value = null) { # set: function() { # set: function(key) { # set: function(key, value) { # set: function(key, value = null) { @method_active = true @params = {} # Extract method data. parse_method_definition(@line) @docs = nil end # If we're inside a comment. parse_comment(@line) if @docs_active # Break out of comment ( ... */) @docs_active = false if @line =~ /^.*\*+\/\s*$/ # Break out of method ( ... } OR }, ) @method_active = false if @line =~ /^\s{4}(\}|\},)\s*$/ || @line =~ /^\s{4}\w+\s*(:\s*function)?\(.*\)\s*\{\s*(\}|\},)\s*$/ rescue RuntimeError => e @errors << Blufin::ScannerError.new(file, @line, @line_number, e.message) next end end # Make sure we have at least one method. @errors << Blufin::ScannerError.new(file, nil, nil, "No methods/functions found in file: #{file}") unless @data[@file_short][:methods].length > 0 end