<commit_before>require 'temple'
require 'fast_haml/ast'
require 'fast_haml/filter_compilers'
require 'fast_haml/static_hash_parser'
require 'fast_haml/text_compiler'

module FastHaml
  class Compiler < Temple::Parser
    DEFAULT_AUTO_CLOSE_TAGS = %w[
      area base basefont br col command embed frame hr img input isindex keygen
      link menuitem meta param source track wbr
    ]
    DEFAULT_PRESERVE_TAGS = %w[pre textarea code]

    define_options(
      autoclose: DEFAULT_AUTO_CLOSE_TAGS,
      format: :html,
      preserve: DEFAULT_PRESERVE_TAGS,
    )

    def initialize(*)
      super
      @text_compiler = TextCompiler.new
    end

    def call(ast)
      compile(ast)
    end

    def self.find_and_preserve(input)
      # Taken from the original haml code
      re = /<(#{options[:preserve].map(&Regexp.method(:escape)).join('|')})([^>]*)>(.*?)(<\/\1>)/im
      input.to_s.gsub(re) do |s|
        s =~ re # Can't rely on $1, etc. existing since Rails' SafeBuffer#gsub is incompatible
        "<#{$1}#{$2}>#{preserve($3)}</#{$1}>"
      end
    end

    def self.preserve(input)
      # Taken from the original haml code
      input.to_s.chomp("\n").gsub(/\n/, '&#x000A;').gsub(/\r/, '')
    end

    private

    def compile(ast)
      case ast
      when Ast::Root
        compile_root(ast)
      when Ast::Doctype
        compile_doctype(ast)
      when Ast::HtmlComment
        compile_html_comment(ast)
      when Ast::HamlComment
        [:multi]
      when Ast::Element
        compile_element(ast)
      when Ast::Script
        compile_script(ast)
      when Ast::SilentScript
        compile_silent_script(ast)
      when Ast::Text
        compile_text(ast)
      when Ast::Filter
        compile_filter(ast)
      else
        raise "InternalError: Unknown AST node #{ast.class}: #{ast.inspect}"
      end
    end

    def compile_root(ast)
      [:multi].tap do |temple|
        compile_children(ast, temple)
      end
    end

    def compile_children(ast, temple)
      was_newline = false
      ast.children.each do |c|
        if c.is_a?(Ast::Element) && c.nuke_outer_whitespace && was_newline
          # pop newline
          x = temple.pop
          if x != [:newline]
            raise "InternalError: Unexpected pop (expected [:newline]): #{x}"
          end
          x = temple.pop
          if x != [:static, "\n"]
            raise "InternalError: Unexpected pop (expected [:static, newline]): #{x}"
          end
        end
        temple << compile(c)
        if was_newline = need_newline?(ast, c)
          temple << [:static, "\n"]
          temple << [:newline]
        end
      end
    end

    def need_newline?(parent, child)
      if parent.is_a?(Ast::Element) && nuke_inner_whitespace?(parent) && parent.children.last.equal?(child)
        return false
      end
      case child
      when Ast::Script
        child.children.empty?
      when Ast::SilentScript, Ast::HamlComment
        false
      when Ast::Element
        !child.nuke_outer_whitespace
      else
        true
      end
    end

    def compile_text(ast)
      @text_compiler.compile(ast.text, escape_html: ast.escape_html)
    end

    # html5 and html4 is deprecated in temple.<commit_msg>Keep newlines around nuke-whitespaces<commit_after>require 'temple'
require 'fast_haml/ast'
require 'fast_haml/filter_compilers'
require 'fast_haml/static_hash_parser'
require 'fast_haml/text_compiler'

module FastHaml
  class Compiler < Temple::Parser
    DEFAULT_AUTO_CLOSE_TAGS = %w[
      area base basefont br col command embed frame hr img input isindex keygen
      link menuitem meta param source track wbr
    ]
    DEFAULT_PRESERVE_TAGS = %w[pre textarea code]

    define_options(
      autoclose: DEFAULT_AUTO_CLOSE_TAGS,
      format: :html,
      preserve: DEFAULT_PRESERVE_TAGS,
    )

    def initialize(*)
      super
      @text_compiler = TextCompiler.new
    end

    def call(ast)
      compile(ast)
    end

    def self.find_and_preserve(input)
      # Taken from the original haml code
      re = /<(#{options[:preserve].map(&Regexp.method(:escape)).join('|')})([^>]*)>(.*?)(<\/\1>)/im
      input.to_s.gsub(re) do |s|
        s =~ re # Can't rely on $1, etc. existing since Rails' SafeBuffer#gsub is incompatible
        "<#{$1}#{$2}>#{preserve($3)}</#{$1}>"
      end
    end

    def self.preserve(input)
      # Taken from the original haml code
      input.to_s.chomp("\n").gsub(/\n/, '&#x000A;').gsub(/\r/, '')
    end

    private

    def compile(ast)
      case ast
      when Ast::Root
        compile_root(ast)
      when Ast::Doctype
        compile_doctype(ast)
      when Ast::HtmlComment
        compile_html_comment(ast)
      when Ast::HamlComment
        [:multi]
      when Ast::Element
        compile_element(ast)
      when Ast::Script
        compile_script(ast)
      when Ast::SilentScript
        compile_silent_script(ast)
      when Ast::Text
        compile_text(ast)
      when Ast::Filter
        compile_filter(ast)
      else
        raise "InternalError: Unknown AST node #{ast.class}: #{ast.inspect}"
      end
    end

    def compile_root(ast)
      [:multi].tap do |temple|
        compile_children(ast, temple)
      end
    end

    def compile_children(ast, temple)
      was_newline = false
      ast.children.each do |c|
        if c.is_a?(Ast::Element) && c.nuke_outer_whitespace && was_newline
          # pop newline
          x = temple.pop
          if x != [:newline]
            raise "InternalError: Unexpected pop (expected [:newline]): #{x}"
          end
          x = temple.pop
          if x != [:static, "\n"]
            raise "InternalError: Unexpected pop (expected [:static, newline]): #{x}"
          end
          temple << [:newline]
        end
        temple << compile(c)
        if was_newline = need_newline?(ast, c)
          temple << [:static, "\n"]
        end
        temple << [:newline]
      end
    end

    def need_newline?(parent, child)
      if parent.is_a?(Ast::Element) && nuke_inner_whitespace?(parent) && parent.children.last.equal?(child)
        return false
      end
      case child
      when Ast::Script
        child.children.empty?
      when Ast::SilentScript, Ast::HamlComment
        false
      when Ast::Element
        !child.nuke_outer_whitespace
      else
        true
      end
    end

    def compile_text(ast)
      @text_compiler.compile(ast.text, escape_html: ast.escape_html)
    end

    # html5 and html4 is deprecated in temple.
{'fraction_non_alphanumeric': 0.11383618695048589, 'fraction_numerical': 0.0033934906679006635, 'mean_word_length': 2.2913705583756343, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6580346', 'n_tokens_mistral': 2106, 'n_tokens_neox': 2052, 'n_words': 494}