# frozen_string_literal: truerequire'uri'moduleRuboCopmoduleCopmoduleMetrics# This cop checks the length of lines in the source code.# The maximum length is configurable.classLineLength<CopincludeConfigurableMaxincludeIgnoredPatternMSG='Line is too long. [%<length>d/%<max>d]'.freezedefinvestigate(processed_source)heredocs=extract_heredocs(processed_source.ast)ifallow_heredoc?processed_source.lines.each_with_indexdo|line,index|check_line(line,index,heredocs)endendprivatedefcheck_line(line,index,heredocs)returnifline.length<=maxreturnifignored_line?(line,index,heredocs)ifignore_cop_directives?&&directive_on_source_line?(index)returncheck_directive_line(line,index)endreturncheck_uri_line(line,index)ifallow_uri?register_offense(source_range(processed_source.buffer,index+1,0...line.length),line)enddefignored_line?(line,index,heredocs)matches_ignored_pattern?(line)||heredocs&&line_in_whitelisted_heredoc?(heredocs,index.succ)enddefregister_offense(loc,line)message=format(MSG,length: line.length,max: max)add_offense(nil,location: loc,message: message)doself.max=line.lengthendenddefexcess_range(uri_range,line,index)excessive_position=ifuri_range&&uri_range.begin<maxuri_range.endelsemaxendsource_range(processed_source.buffer,index+1,excessive_position...(line.length))enddefmaxcop_config['Max']enddefallow_heredoc?allowed_heredocenddefallowed_heredoccop_config['AllowHeredoc']enddefextract_heredocs(ast)return[]unlessastast.each_node.with_object([])do|node,heredocs|nextunlessnode.location.is_a?(Parser::Source::Map::Heredoc)body=node.location.heredoc_bodydelimiter=node.location.heredoc_end.source.stripheredocs<<[body.first_line...body.last_line,delimiter]endenddefline_in_whitelisted_heredoc?(heredocs,line_number)heredocs.any?do|range,delimiter|range.cover?(line_number)&&(allowed_heredoc==true||allowed_heredoc.include?(delimiter))endenddefallow_uri?cop_config['AllowURI']enddefignore_cop_directives?cop_config['IgnoreCopDirectives']enddefallowed_uri_position?(line,uri_range)uri_range.begin<max&&uri_range.end==line.lengthenddeffind_excessive_uri_range(line)last_uri_match=match_uris(line).lastreturnnilunlesslast_uri_matchbegin_position,end_position=last_uri_match.offset(0)returnnilifbegin_position<max&&end_position<maxbegin_position...end_positionenddefmatch_uris(string)matches=[]string.scan(uri_regexp)domatches<<$LAST_MATCH_INFOifvalid_uri?($LAST_MATCH_INFO[0])endmatchesenddefvalid_uri?(uri_ish_string)URI.parse(uri_ish_string)truerescueURI::InvalidURIError,NoMethodErrorfalseenddefuri_regexp@regexp||=URI::DEFAULT_PARSER.make_regexp(cop_config['URISchemes'])enddefcheck_directive_line(line,index)returnifline_length_without_directive(line)<=maxrange=max..(line_length_without_directive(line)-1)register_offense(source_range(processed_source.buffer,index+1,range),line)enddefdirective_on_source_line?(index)source_line_number=index+processed_source.buffer.first_linecomment=processed_source.comments.detect{|e|e.location.line==source_line_number}returnfalseunlesscommentcomment.text.match(CommentConfig::COMMENT_DIRECTIVE_REGEXP)enddefline_length_without_directive(line)before_comment,=line.split(CommentConfig::COMMENT_DIRECTIVE_REGEXP)before_comment.rstrip.lengthenddefcheck_uri_line(line,index)uri_range=find_excessive_uri_range(line)returnifuri_range&&allowed_uri_position?(line,uri_range)register_offense(excess_range(uri_range,line,index),line)endendendendend