Class: Comet::Generator

Inherits:
Object
  • Object
show all
Defined in:
lib/comet-html/generator.rb

Instance Method Summary collapse

Constructor Details

#initialize(output, input, file) ⇒ Generator

Returns a new instance of Generator.



41
42
43
44
45
# File 'lib/comet-html/generator.rb', line 41

def initialize output, input, file
  @output   = output
  @input    = input
  @filepath = file
end

Instance Method Details

#append_classes_predeclarationObject



63
64
65
66
67
68
69
70
# File 'lib/comet-html/generator.rb', line 63

def append_classes_predeclaration
  result = ""
  Context.classes.each do |object|
    next if object.should_skip?
    result += "  class #{object.typename};\n"
  end
  result
end

#compiled_header_pathObject



55
56
57
# File 'lib/comet-html/generator.rb', line 55

def compiled_header_path
  @output + relative_filepath.delete_suffix(File.extname relative_filepath) + ".hpp"
end

#compiled_source_pathObject



59
60
61
# File 'lib/comet-html/generator.rb', line 59

def compiled_source_path
  @output + relative_filepath.delete_suffix(File.extname relative_filepath) + ".cpp"
end

#generateObject



129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
# File 'lib/comet-html/generator.rb', line 129

def generate
  src = File.read @filepath
  src.gsub! /<template/i,  "<html"
  src.gsub! /<\/template/i, "</html>"

  document = Nokogiri::HTML.parse(src) do |config| config.strict end
  
  html = document.xpath("html").first
  head = document.xpath("//head")
  body = document.xpath("//body")
  raise LoadError.new "could not load html template `#{@filepath}`" if html.nil?
  raise LoadError.new "missing body element in `#{@filepath}`" if body.first.nil?

  Context.reset
  Context.filename = @filepath
  if !@config.nil? && !@config["elements"].nil?
    Context.load_global_element_types @config["elements"]
  end
  
  load_includes head
  
  fatal_error = nil
  document.errors.each do |error|
    if is_error_fatal? error
      puts "[comet-html] #{@filepath}:#{error.line}:#{error.column}: #{error.message}"
      fatal_error ||= error
      error_count += 1
    end
  end
  raise HtmlParseError.new fatal_error unless fatal_error.nil?

  main_element = Comet::Class.new body
  main_element.typename = if html["classname"].nil?
    File.basename(@filepath, ".html").to_s.camelize
  else
    html["classname"]
  end
  main_element.superclass = html["extends"] unless html["extends"].nil?
  main_element.probe

  main_element.inline_code = ""
  head.css("script").each do |script|
    main_element.inline_code += script.text.strip + "\n"
  end

  head.css("attribute").each do |attribute|
    main_element.refs << (CppReference.new attribute, attribute["type"], attribute["name"], attribute["value"])
  end

  define_name = "__COMET_CUSTOM_ELEMENT_#{main_element.typename.upcase}__"
  header_code = ""
  source_code = ""
  Context.classes.reverse.each do |object|
    next if object.should_skip?
    header_code += HeaderGenerator.new(object).generate + "\n"
    source_code += SourceGenerator.new(object).generate + "\n"
  end

  includes_str = prepare_includes head
  
  header = <<HEADER
#ifndef  #{define_name}
# define #{define_name}

# include <comet/bindable.hpp>
# include <comet/repeater.hpp>
# include <comet/slot_element.hpp>
# include <comet/comment_element.hpp>
# include <comet/custom_element.hpp>
# include <comet/signal.hpp>
#{includes_str}

namespace HtmlTemplate
{
#{append_classes_predeclaration}
#{header_code}
}

#endif
HEADER

  source = <<SOURCE
#include <comet/lexical_cast.hpp>
#include "#{compiled_header_path}"

#{source_code}
SOURCE

  { header: header, source: source }
end

#html5_tagsObject



105
106
107
# File 'lib/comet-html/generator.rb', line 105

def html5_tags
  ["article", "aside", "details", "figcaption", "figure", "footer", "header", "main", "mark", "nav", "section", "summary", "time"]
end

#internal_tagsObject



113
114
115
# File 'lib/comet-html/generator.rb', line 113

def internal_tags
  ["include", "attribute", "slot"]
end

#is_error_fatal?(error) ⇒ Boolean

Returns:

  • (Boolean)


117
118
119
120
121
122
123
124
125
126
127
# File 'lib/comet-html/generator.rb', line 117

def is_error_fatal? error
  matches = error.message.match(/^[0-9]+:[0-9]+: ERROR: Tag (.+) invalid$/)
  unless matches.nil?
    tagName = matches[1]
    return false if (internal_tags + html5_tags + whitelisted_tags).include? tagName
    return (if Context.element_types[tagName].nil? then true else false end)
  end
  return false if error.message.end_with?("ERROR: htmlParseEntityRef: no name") ||
                  error.message.end_with?("ERROR: Expected a doctype token$")
  true
end

#load_includes(head) ⇒ Object



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/comet-html/generator.rb', line 72

def load_includes head
  head.css("include").each do |include_attribute|
    unless include_attribute["require"].nil?
      type = include_attribute["require"].to_s
      tag  = if include_attribute["tag-name"].nil?
        parts = type.split("<")
        parts[0].gsub! "::", "_"
        parts.join("<").dasherize
      else
        include_attribute["tag-name"].to_s
      end
      Context.element_types[tag] = type
    end
  end
end

#prepare_includes(head) ⇒ Object



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/comet-html/generator.rb', line 88

def prepare_includes head
  result = ""
  included_paths = []
  head.css("include").each do |include_attribute|
    included_paths << include_attribute["src"].to_s
  end
  included_paths.uniq.each do |include_path|
    result += "# include \"#{include_path}\"\n"
  end
  @config["elements"].each do |element_data|
    if Context.referenced_types.include? element_data["require"]
      result += "# include \"#{element_data["include"]}\"\n"
    end
  end if !@config.nil? && !@config["elements"].nil?
  result
end

#relative_filepathObject



51
52
53
# File 'lib/comet-html/generator.rb', line 51

def relative_filepath
  @filepath[@input.length..-1]
end

#set_config(config) ⇒ Object



47
48
49
# File 'lib/comet-html/generator.rb', line 47

def set_config config
  @config = config
end

#whitelisted_tagsObject



109
110
111
# File 'lib/comet-html/generator.rb', line 109

def whitelisted_tags
  ["svg"] + (if @config.nil? then [] else @config["whitelisted-tags"] || [] end)
end