Class: Shellfie::Parser

Inherits:
Object
  • Object
show all
Extended by:
ParserValidation
Defined in:
lib/shellfie/parser.rb

Constant Summary collapse

MAX_INCLUDE_BYTES =
1_048_576
MAX_INCLUDE_DEPTH =
50
MAX_INCLUDE_FILES =
100
MAX_TOTAL_INCLUDE_BYTES =
10 * MAX_INCLUDE_BYTES

Constants included from ParserValidation

Shellfie::ParserValidation::ANIMATION_KEYS, Shellfie::ParserValidation::COLOR_KEYS, Shellfie::ParserValidation::CURSOR_KEYS, Shellfie::ParserValidation::FONT_KEYS, Shellfie::ParserValidation::FRAME_KEYS, Shellfie::ParserValidation::LIMIT_KEYS, Shellfie::ParserValidation::LINE_KEYS, Shellfie::ParserValidation::MAX_FRAME_DELAY_MS, Shellfie::ParserValidation::SHADOW_KEYS, Shellfie::ParserValidation::TOP_LEVEL_KEYS, Shellfie::ParserValidation::WINDOW_DECORATION_KEYS, Shellfie::ParserValidation::WINDOW_KEYS

Class Method Summary collapse

Class Method Details

.parse(path) ⇒ Object



19
20
21
22
23
24
25
26
27
28
# File 'lib/shellfie/parser.rb', line 19

def parse(path)
  return parse_string($stdin.read(MAX_INCLUDE_BYTES + 1), base_dir: Dir.pwd) if path == "-"
  source_path = File.realpath(path)
  content = read_config(source_path)
  state = { files: 1, bytes: content.bytesize, cache: {}, sources: {} }
  parse_string(content, base_dir: File.dirname(source_path), include_stack: [source_path], source_name: source_path,
                        include_state: state)
rescue Errno::ENOENT
  raise ParseError, "Configuration file not found: #{path}"
end

.parse_string(content, base_dir: nil, include_stack: [], source_name: nil, include_state: nil) ⇒ Object



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/shellfie/parser.rb', line 30

def parse_string(content, base_dir: nil, include_stack: [], source_name: nil, include_state: nil)
  raise ParseError, "Configuration is too large (max #{MAX_INCLUDE_BYTES} bytes)" if content.bytesize > MAX_INCLUDE_BYTES

  raw = YAML.safe_load(content, symbolize_names: true, aliases: true)
  YamlSafety.validate_tree!(raw)
  if base_dir
    include_state ||= { files: 1, bytes: content.bytesize, cache: {}, sources: {} }
    raw = apply_includes(raw, base_dir, stack: include_stack, root: base_dir, state: include_state)
  end
  validate_config(raw)
  sources = (include_stack + Array(include_state&.dig(:cache)&.keys)).uniq
  build_config(raw, source_paths: sources)
rescue Psych::Exception => e
  raise ParseError, "Invalid YAML syntax: #{e.message}"
rescue ValidationError => e
  raise e unless source_name

  documents = [[source_name, content]] + include_state.fetch(:sources, {}).to_a.reverse
  raise YamlSafety.annotate_validation_error(e, documents)
end