# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details. # frozen_string_literal: true module Contrast module Agent module Assess module Policy module Propagator # Propagation that results in all the tags of the source being # applied to the totality of the target and then those sections # which have been removed from the target are removed from the # tags. The target's preexisting tags are also updated by this # removal. class Remove < Contrast::Agent::Assess::Policy::Propagator::Base class << self # For the source, append its tags to the target. # Once the tag is applied, remove the section that was removed by the delete. # Unlike additive propagation, this currently only supports one source def propagate propagation_node, preshift, target source = find_source(propagation_node.sources[0], preshift) target.cs__copy_from(source, 0, propagation_node.untags) source_chars = source.is_a?(String) ? source.chars : source.string.chars handle_removal(source_chars, target) end def handle_removal source_chars, target source_idx = 0 target_chars = target.chars target_idx = 0 remove_ranges = [] current_range = nil # loop over the target, the result of the delete # every range of characters that it differs from the source # represents a section that was deleted. these sections # need to have their tags updated target_len = target_chars.length while target_idx < target_len target_char = target_chars[target_idx] source_char = source_chars[source_idx] if target_char == source_char target_idx += 1 if current_range current_range.stop = source_idx remove_ranges << current_range current_range = nil end else current_range ||= Contrast::Agent::Assess::AdjustedSpan.new(source_idx) end source_idx += 1 end # once we're done looping over the target, anything left # over is extra from the source that was deleted. tags # applying to it need to be removed. if source_idx != source_chars.length remove_ranges << Contrast::Agent::Assess::AdjustedSpan.new( source_idx, source_chars.length) end # handle deleting the removed ranges target.cs__properties.delete_tags_at_ranges(remove_ranges) end end end end end end end end