refactor(client): unify duplicate YAML parsers into YamlParser (#560)
Extract shared YamlParser utility (client/scripts/util/yaml_parser.gd) with parse() for nested typed dicts and parse_flat() for dotted-key string format. UIStrings._parse_yaml() and ChecklistEvaluator's inline parser both delegate to YamlParser, removing ~140 lines of duplication. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -233,12 +233,7 @@ func _find_entity(entity_id: int) -> bool:
|
||||
return false
|
||||
|
||||
|
||||
# -- YAML parsing (checklist-specific) -----------------------------------------
|
||||
# Handles the constrained checklist YAML format: top-level key:value pairs,
|
||||
# a conditions array of flat dictionaries. No nested arrays or anchors.
|
||||
#
|
||||
# Limitation: unquoted values containing " #" are truncated at the comment marker.
|
||||
# Use quoted strings ("value # with hash") if values must contain literal hashes.
|
||||
# -- YAML parsing --------------------------------------------------------------
|
||||
|
||||
func _load_checklist_file(path: String) -> Dictionary:
|
||||
if not FileAccess.file_exists(path):
|
||||
@@ -252,103 +247,6 @@ func _load_checklist_file(path: String) -> Dictionary:
|
||||
return parse_checklist_yaml(text)
|
||||
|
||||
|
||||
## Delegates to YamlParser.parse() (#560).
|
||||
static func parse_checklist_yaml(text: String) -> Dictionary:
|
||||
var result := {}
|
||||
var conditions: Array = []
|
||||
var current_item: Dictionary = {}
|
||||
var in_conditions := false
|
||||
|
||||
for line in text.split("\n"):
|
||||
var stripped := line.strip_edges(false, true)
|
||||
if stripped.is_empty() or stripped.strip_edges().begins_with("#"):
|
||||
continue
|
||||
|
||||
var indent := line.length() - line.lstrip(" ").length()
|
||||
var content := stripped.strip_edges()
|
||||
|
||||
# Detect conditions: array header
|
||||
if content == "conditions:":
|
||||
in_conditions = true
|
||||
continue
|
||||
|
||||
if not in_conditions:
|
||||
# Top-level key: value
|
||||
var colon := content.find(":")
|
||||
if colon >= 0:
|
||||
var key := content.substr(0, colon).strip_edges()
|
||||
var val_str := content.substr(colon + 1).strip_edges()
|
||||
result[key] = _parse_value(val_str)
|
||||
else:
|
||||
if content.begins_with("- "):
|
||||
# New array item — flush previous
|
||||
if not current_item.is_empty():
|
||||
conditions.append(current_item)
|
||||
current_item = {}
|
||||
var rest := content.substr(2).strip_edges()
|
||||
var colon := rest.find(":")
|
||||
if colon >= 0:
|
||||
var key := rest.substr(0, colon).strip_edges()
|
||||
var val_str := rest.substr(colon + 1).strip_edges()
|
||||
current_item[key] = _parse_value(val_str)
|
||||
elif indent >= 2 and not current_item.is_empty():
|
||||
# Continuation of current array item
|
||||
var colon := content.find(":")
|
||||
if colon >= 0:
|
||||
var key := content.substr(0, colon).strip_edges()
|
||||
var val_str := content.substr(colon + 1).strip_edges()
|
||||
current_item[key] = _parse_value(val_str)
|
||||
elif indent == 0:
|
||||
# Back to top level — shouldn't happen in valid checklist YAML
|
||||
in_conditions = false
|
||||
if not current_item.is_empty():
|
||||
conditions.append(current_item)
|
||||
current_item = {}
|
||||
var colon := content.find(":")
|
||||
if colon >= 0:
|
||||
var key := content.substr(0, colon).strip_edges()
|
||||
var val_str := content.substr(colon + 1).strip_edges()
|
||||
result[key] = _parse_value(val_str)
|
||||
|
||||
# Flush last item
|
||||
if not current_item.is_empty():
|
||||
conditions.append(current_item)
|
||||
|
||||
if not conditions.is_empty():
|
||||
result["conditions"] = conditions
|
||||
|
||||
return result
|
||||
|
||||
|
||||
static func _parse_value(val: String) -> Variant:
|
||||
if val.is_empty():
|
||||
return ""
|
||||
|
||||
# Strip inline comments (not inside quotes)
|
||||
if not val.begins_with("\""):
|
||||
var comment_pos := val.find(" #")
|
||||
if comment_pos >= 0:
|
||||
val = val.substr(0, comment_pos).strip_edges()
|
||||
|
||||
# Quoted string
|
||||
if val.begins_with("\""):
|
||||
var end_quote := val.find("\"", 1)
|
||||
if end_quote > 0:
|
||||
return val.substr(1, end_quote - 1)
|
||||
return val.substr(1)
|
||||
|
||||
# Boolean
|
||||
if val == "true":
|
||||
return true
|
||||
if val == "false":
|
||||
return false
|
||||
|
||||
# Float (contains decimal point)
|
||||
if val.contains(".") and val.is_valid_float():
|
||||
return val.to_float()
|
||||
|
||||
# Integer
|
||||
if val.is_valid_int():
|
||||
return val.to_int()
|
||||
|
||||
# Plain string
|
||||
return val
|
||||
return YamlParser.parse(text)
|
||||
|
||||
Reference in New Issue
Block a user