Skip to content

Commit

Permalink
refactor: ♻️ add mod_id in all validation error messages
Browse files Browse the repository at this point in the history
Also changes all single quotes to double quotes as discussed in GodotModding#166 and fixes a critical bug that caused the validation to break on `if is_semver_valid(version_number):` - added the `not` to fix that.

closes GodotModding#173
  • Loading branch information
KANAjetzt committed Mar 29, 2023
1 parent 28ce51b commit 4c53ccd
Showing 1 changed file with 39 additions and 31 deletions.
70 changes: 39 additions & 31 deletions addons/mod_loader/classes/mod_manifest.gd
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,9 @@ func _init(manifest: Dictionary) -> void:
):
return

if is_semver_valid(version_number):
var mod_id = get_mod_id()

if not is_semver_valid(mod_id, version_number, "version_number"):
return

description = manifest.description
Expand All @@ -90,12 +92,11 @@ func _init(manifest: Dictionary) -> void:
incompatibilities = ModLoaderUtils.get_array_from_dict(godot_details, "incompatibilities")
load_before = ModLoaderUtils.get_array_from_dict(godot_details, "load_before")
compatible_game_version = ModLoaderUtils.get_array_from_dict(godot_details, "compatible_game_version")
compatible_mod_loader_version = _handle_compatible_mod_loader_version(godot_details)
compatible_mod_loader_version = _handle_compatible_mod_loader_version(mod_id, godot_details)
description_rich = ModLoaderUtils.get_string_from_dict(godot_details, "description_rich")
tags = ModLoaderUtils.get_array_from_dict(godot_details, "tags")
config_defaults = godot_details.config_defaults

var mod_id = get_mod_id()
if (
not is_mod_id_array_valid(mod_id, dependencies, "dependency") or
not is_mod_id_array_valid(mod_id, incompatibilities, "incompatibility") or
Expand Down Expand Up @@ -194,14 +195,14 @@ func to_json() -> String:


# Handles deprecation of the single string value in the compatible_mod_loader_version.
func _handle_compatible_mod_loader_version(godot_details: Dictionary) -> Array:
func _handle_compatible_mod_loader_version(mod_id: String, godot_details: Dictionary) -> Array:
var link_manifest_docs := "https://github.com/GodotModding/godot-mod-loader/wiki/Mod-Files#manifestjson"
var array_value := ModLoaderUtils.get_array_from_dict(godot_details, "compatible_mod_loader_version")

# If there are array values
if array_value.size() > 0:
# Check for valid versions
if not is_semver_version_array_valid(array_value):
if not is_semver_version_array_valid(mod_id, array_value, "compatible_mod_loader_version"):
return []

return array_value
Expand All @@ -210,19 +211,22 @@ func _handle_compatible_mod_loader_version(godot_details: Dictionary) -> Array:
var string_value := ModLoaderUtils.get_string_from_dict(godot_details, "compatible_mod_loader_version")
# If an empty string was passed
if string_value == "":
ModLoaderUtils.log_error(
"\"compatible_mod_loader_version\" is a required field." +
" For more details visit " + link_manifest_docs,
LOG_NAME
)
# Using str() here because format strings caused an error
ModLoaderUtils.log_fatal(
str (
"%s - \"compatible_mod_loader_version\" is a required field." +
" For more details visit %s"
) % [mod_id, link_manifest_docs],
LOG_NAME)
return []

# If a string was passed
ModLoaderDeprecated.deprecated_message(
"The single String value for \"compatible_mod_loader_version\" is deprecated." +
" Please provide an Array. For more details visit " + link_manifest_docs,
"6.0.0"
)
str(
"%s - The single String value for \"compatible_mod_loader_version\" is deprecated. " +
"Please provide an Array. For more details visit %s"
) % [mod_id, link_manifest_docs],
"6.0.0")
return [string_value]


Expand All @@ -235,23 +239,23 @@ static func is_name_or_namespace_valid(check_name: String, is_silent := false) -

if re.search(check_name) == null:
if not is_silent:
ModLoaderUtils.log_fatal('Invalid name or namespace: "%s". You may only use letters, numbers and underscores.' % check_name, LOG_NAME)
ModLoaderUtils.log_fatal("Invalid name or namespace: \"%s\". You may only use letters, numbers and underscores." % check_name, LOG_NAME)
return false

var _compile_error_2 = re.compile("^[a-zA-Z0-9_]{3,}$") # at least 3 long
if re.search(check_name) == null:
if not is_silent:
ModLoaderUtils.log_fatal('Invalid name or namespace: "%s". Must be longer than 3 characters.' % check_name, LOG_NAME)
ModLoaderUtils.log_fatal("Invalid name or namespace: \"%s\". Must be longer than 3 characters." % check_name, LOG_NAME)
return false

return true


static func is_semver_version_array_valid(version_array: PoolStringArray, is_silent := false) -> bool:
static func is_semver_version_array_valid(mod_id: String, version_array: PoolStringArray, version_array_descripton: String, is_silent := false) -> bool:
var is_valid := true

for version in version_array:
if not is_semver_valid(version, is_silent):
if not is_semver_valid(mod_id, version, version_array_descripton, is_silent):
is_valid = false

return is_valid
Expand All @@ -260,27 +264,31 @@ static func is_semver_version_array_valid(version_array: PoolStringArray, is_sil
# A valid semantic version should follow this format: {mayor}.{minor}.{patch}
# reference https://semver.org/ for details
# {0-9}.{0-9}.{0-9} (no leading 0, shorter than 16 characters total)
static func is_semver_valid(check_version_number: String, is_silent := false) -> bool:
static func is_semver_valid(mod_id: String, check_version_number: String, field_name: String, is_silent := false) -> bool:
var re := RegEx.new()
var _compile_error = re.compile("^(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)$")

if re.search(check_version_number) == null:
if not is_silent:
# Using str() here because format strings cause an error
# Using str() here because format strings caused an error
ModLoaderUtils.log_fatal(
str(
'Invalid semantic version: "%s".',
'You may only use numbers without leading zero and periods',
'following this format {mayor}.{minor}.{patch}'
) % check_version_number,
"Invalid semantic version: \"%s\" in field \"%s\" of mod \"%s\". " +
"You may only use numbers without leading zero and periods" +
"following this format {mayor}.{minor}.{patch}"
) % [check_version_number, field_name, mod_id],
LOG_NAME
)
return false

if check_version_number.length() > 16:
if not is_silent:
ModLoaderUtils.log_fatal('Invalid semantic version: "%s". ' +
'Version number must be shorter than 16 characters.', LOG_NAME
ModLoaderUtils.log_fatal(
str(
"Invalid semantic version: \"%s\" in field \"%s\" of mod \"%s\". " +
"Version number must be shorter than 16 characters."
) % [check_version_number, field_name, mod_id],
LOG_NAME
)
return false

Expand Down Expand Up @@ -342,19 +350,19 @@ static func is_mod_id_array_valid(own_mod_id: String, mod_id_array: PoolStringAr


static func is_mod_id_valid(original_mod_id: String, check_mod_id: String, type := "", is_silent := false) -> bool:
var intro_text = "A %s for the mod '%s' is invalid: " % [type, original_mod_id] if not type == "" else ""
var intro_text = "A %s for the mod \"%s\" is invalid: " % [type, original_mod_id] if not type == "" else ""

# contains hyphen?
if not check_mod_id.count("-") == 1:
if not is_silent:
ModLoaderUtils.log_fatal(str(intro_text, 'Expected a single hyphen in the mod ID, but the %s was: "%s"' % [type, check_mod_id]), LOG_NAME)
ModLoaderUtils.log_fatal(str(intro_text, "Expected a single hyphen in the mod ID, but the %s was: \"%s\"" % [type, check_mod_id]), LOG_NAME)
return false

# at least 7 long (1 for hyphen, 3 each for namespace/name)
var mod_id_length = check_mod_id.length()
if mod_id_length < 7:
if not is_silent:
ModLoaderUtils.log_fatal(str(intro_text, 'Mod ID for "%s" is too short. It must be at least 7 characters, but its length is: %s' % [check_mod_id, mod_id_length]), LOG_NAME)
ModLoaderUtils.log_fatal(str(intro_text, "Mod ID for \"%s\" is too short. It must be at least 7 characters, but its length is: %s" % [check_mod_id, mod_id_length]), LOG_NAME)
return false

var split = check_mod_id.split("-")
Expand All @@ -365,12 +373,12 @@ static func is_mod_id_valid(original_mod_id: String, check_mod_id: String, type

if re.search(check_namespace) == null:
if not is_silent:
ModLoaderUtils.log_fatal(str(intro_text, 'Mod ID has an invalid namespace (author) for "%s". Namespace can only use letters, numbers and underscores, but was: "%s"' % [check_mod_id, check_namespace]), LOG_NAME)
ModLoaderUtils.log_fatal(str(intro_text, "Mod ID has an invalid namespace (author) for \"%s\". Namespace can only use letters, numbers and underscores, but was: \"%s\"" % [check_mod_id, check_namespace]), LOG_NAME)
return false

if re.search(check_name) == null:
if not is_silent:
ModLoaderUtils.log_fatal(str(intro_text, 'Mod ID has an invalid name for "%s". Name can only use letters, numbers and underscores, but was: "%s"' % [check_mod_id, check_name]), LOG_NAME)
ModLoaderUtils.log_fatal(str(intro_text, "Mod ID has an invalid name for \"%s\". Name can only use letters, numbers and underscores, but was: \"%s\"" % [check_mod_id, check_name]), LOG_NAME)
return false

return true

0 comments on commit 4c53ccd

Please # to comment.