gdharness 1.3.42 → 1.3.43

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/build/cli.js +62 -9
  2. package/build/godot/addons/auto_reload/auto_reload.gd +18 -19
  3. package/build/godot/addons/gdharness_editor/animation_reads.gd +55 -33
  4. package/build/godot/addons/gdharness_editor/bridge_client.gd +53 -58
  5. package/build/godot/addons/gdharness_editor/declared_values.gd +68 -32
  6. package/build/godot/addons/gdharness_editor/file_reads.gd +83 -42
  7. package/build/godot/addons/gdharness_editor/file_walk.gd +12 -5
  8. package/build/godot/addons/gdharness_editor/headless_check.gd +68 -44
  9. package/build/godot/addons/gdharness_editor/plugin.gd +2 -3
  10. package/build/godot/addons/gdharness_editor/property_paths.gd +22 -12
  11. package/build/godot/addons/gdharness_editor/property_values.gd +143 -78
  12. package/build/godot/addons/gdharness_editor/reading.gd +37 -12
  13. package/build/godot/addons/gdharness_editor/same_values.gd +4 -4
  14. package/build/godot/addons/gdharness_editor/scene_file.gd +109 -79
  15. package/build/godot/addons/gdharness_editor/scene_uids.gd +12 -6
  16. package/build/godot/addons/gdharness_editor/serialisation.gd +75 -51
  17. package/build/godot/addons/gdharness_editor/setting_reads.gd +7 -6
  18. package/build/godot/addons/gdharness_editor/tool_executor.gd +3 -6
  19. package/build/godot/addons/gdharness_editor/tools/animation_states.gd +37 -27
  20. package/build/godot/addons/gdharness_editor/tools/animation_tools.gd +79 -49
  21. package/build/godot/addons/gdharness_editor/tools/animation_tracks.gd +70 -40
  22. package/build/godot/addons/gdharness_editor/tools/class_tools.gd +34 -30
  23. package/build/godot/addons/gdharness_editor/tools/filesystem_tools.gd +24 -22
  24. package/build/godot/addons/gdharness_editor/tools/navigation_bake.gd +49 -29
  25. package/build/godot/addons/gdharness_editor/tools/play_tools.gd +26 -21
  26. package/build/godot/addons/gdharness_editor/tools/profile_tools.gd +40 -40
  27. package/build/godot/addons/gdharness_editor/tools/resource_tools.gd +166 -107
  28. package/build/godot/addons/gdharness_editor/tools/scene_groups.gd +16 -9
  29. package/build/godot/addons/gdharness_editor/tools/scene_kin.gd +68 -41
  30. package/build/godot/addons/gdharness_editor/tools/scene_paths.gd +35 -20
  31. package/build/godot/addons/gdharness_editor/tools/scene_placing.gd +28 -13
  32. package/build/godot/addons/gdharness_editor/tools/scene_sharing.gd +12 -5
  33. package/build/godot/addons/gdharness_editor/tools/scene_tools.gd +113 -67
  34. package/build/godot/addons/gdharness_editor/tools/script_paths.gd +20 -8
  35. package/build/godot/addons/gdharness_editor/tools/settings_tools.gd +11 -8
  36. package/build/godot/addons/gdharness_editor/tools/signal_tools.gd +47 -34
  37. package/build/godot/addons/gdharness_editor/tools/tileset_tools.gd +77 -50
  38. package/build/godot/addons/gdharness_editor/value_shapes.gd +5 -6
  39. package/build/godot/addons/gdharness_runtime/call_errors.gd +1 -2
  40. package/build/godot/addons/gdharness_runtime/declared_values.gd +68 -32
  41. package/build/godot/addons/gdharness_runtime/error_report.gd +1 -2
  42. package/build/godot/addons/gdharness_runtime/reading.gd +37 -12
  43. package/build/godot/addons/gdharness_runtime/runtime_accessibility.gd +84 -63
  44. package/build/godot/addons/gdharness_runtime/runtime_autoload.gd +149 -147
  45. package/build/godot/addons/gdharness_runtime/runtime_capture.gd +64 -42
  46. package/build/godot/addons/gdharness_runtime/runtime_changes.gd +184 -122
  47. package/build/godot/addons/gdharness_runtime/runtime_frames.gd +2 -2
  48. package/build/godot/addons/gdharness_runtime/runtime_hover.gd +24 -20
  49. package/build/godot/addons/gdharness_runtime/runtime_input.gd +134 -92
  50. package/build/godot/addons/gdharness_runtime/runtime_items.gd +29 -13
  51. package/build/godot/addons/gdharness_runtime/runtime_menus.gd +0 -1
  52. package/build/godot/addons/gdharness_runtime/runtime_mouse.gd +34 -17
  53. package/build/godot/addons/gdharness_runtime/runtime_pad.gd +17 -13
  54. package/build/godot/addons/gdharness_runtime/runtime_paths.gd +84 -46
  55. package/build/godot/addons/gdharness_runtime/runtime_queries.gd +117 -79
  56. package/build/godot/addons/gdharness_runtime/runtime_says.gd +14 -17
  57. package/build/godot/addons/gdharness_runtime/runtime_screen.gd +23 -16
  58. package/build/godot/addons/gdharness_runtime/runtime_targets.gd +117 -66
  59. package/build/godot/addons/gdharness_runtime/runtime_touch.gd +15 -15
  60. package/build/godot/addons/gdharness_runtime/runtime_typing.gd +44 -27
  61. package/build/godot/addons/gdharness_runtime/runtime_values.gd +108 -73
  62. package/build/godot/addons/gdharness_runtime/runtime_waits.gd +111 -84
  63. package/build/godot/addons/gdharness_runtime/runtime_words.gd +10 -7
  64. package/build/godot/addons/gdharness_runtime/serialisation.gd +75 -51
  65. package/build/godot/addons/gdharness_runtime/value_shapes.gd +5 -6
  66. package/build/godot/addons/gdharness_tests/bench.gd +4 -5
  67. package/build/godot/addons/gdharness_tests/event.gd +10 -5
  68. package/build/godot/addons/gdharness_tests/share.gd +38 -18
  69. package/build/godot/addons/gdharness_tests/suites.gd +3 -3
  70. package/build/godot/addons/gdharness_tests/wait.gd +3 -2
  71. package/build/godot/loader/loader.gd +9 -9
  72. package/build/godot/operations/animation_reads.gd +55 -33
  73. package/build/godot/operations/audio_buses.gd +48 -19
  74. package/build/godot/operations/class_cache.gd +16 -11
  75. package/build/godot/operations/classdb_queries.gd +89 -44
  76. package/build/godot/operations/declared_values.gd +68 -32
  77. package/build/godot/operations/dependencies.gd +139 -93
  78. package/build/godot/operations/editor_tools.gd +9 -10
  79. package/build/godot/operations/export_presets.gd +100 -54
  80. package/build/godot/operations/file_reads.gd +83 -42
  81. package/build/godot/operations/file_walk.gd +12 -5
  82. package/build/godot/operations/gdscript_analysis.gd +86 -65
  83. package/build/godot/operations/gdscript_authoring.gd +83 -36
  84. package/build/godot/operations/godot_operations.gd +17 -11
  85. package/build/godot/operations/import_pipeline.gd +110 -59
  86. package/build/godot/operations/input_actions.gd +62 -39
  87. package/build/godot/operations/patterns.gd +3 -1
  88. package/build/godot/operations/plugins.gd +36 -16
  89. package/build/godot/operations/project_config.gd +53 -29
  90. package/build/godot/operations/project_diagnostics.gd +24 -11
  91. package/build/godot/operations/project_file.gd +16 -16
  92. package/build/godot/operations/project_validation.gd +71 -44
  93. package/build/godot/operations/property_paths.gd +22 -12
  94. package/build/godot/operations/property_values.gd +143 -78
  95. package/build/godot/operations/reading.gd +37 -12
  96. package/build/godot/operations/rename_checks.gd +2 -2
  97. package/build/godot/operations/resource_files.gd +11 -9
  98. package/build/godot/operations/same_values.gd +4 -4
  99. package/build/godot/operations/scene_connections.gd +27 -13
  100. package/build/godot/operations/script_check.gd +52 -49
  101. package/build/godot/operations/serialisation.gd +75 -51
  102. package/build/godot/operations/setting_reads.gd +7 -6
  103. package/build/godot/operations/value_shapes.gd +5 -6
  104. package/build/godot/tests/listed.gd +321 -268
  105. package/package.json +1 -1
@@ -22,7 +22,7 @@ func list_plugins(_params: Dictionary) -> Dictionary:
22
22
  "addons_directory_exists": false,
23
23
  "enabled_count": 0,
24
24
  "disabled_count": 0,
25
- "message": "No addons directory found in the project"
25
+ "message": "No addons directory found in the project",
26
26
  }
27
27
 
28
28
  var enabled_paths: Array[String] = _enabled_paths()
@@ -34,7 +34,7 @@ func list_plugins(_params: Dictionary) -> Dictionary:
34
34
  var plugin_cfg_path: String = folder.path_join("plugin.cfg")
35
35
  var name: String = folder.trim_prefix(addons_path)
36
36
  var enabled: bool = plugin_cfg_path in enabled_paths
37
- var plugin_info: Dictionary = {"name": name, "path": folder, "enabled": enabled}
37
+ var plugin_info: Dictionary = { "name": name, "path": folder, "enabled": enabled }
38
38
 
39
39
  var plugin_config: ConfigFile = ConfigFile.new()
40
40
  if plugin_config.load(plugin_cfg_path) == OK:
@@ -52,7 +52,7 @@ func list_plugins(_params: Dictionary) -> Dictionary:
52
52
  "plugins": plugins,
53
53
  "addons_directory_exists": true,
54
54
  "enabled_count": enabled_count,
55
- "disabled_count": plugins.size() - enabled_count
55
+ "disabled_count": plugins.size() - enabled_count,
56
56
  }
57
57
  # Enabled in the project with no plugin.cfg where the entry points: the editor reports each one
58
58
  # as an error at every start and loads nothing for it.
@@ -99,7 +99,9 @@ func enable_plugin(params: Dictionary) -> Dictionary:
99
99
 
100
100
  if plugin_cfg_path in enabled_paths:
101
101
  return {
102
- "plugin_name": plugin_name, "action": "already_enabled", "message": "Plugin is already enabled"
102
+ "plugin_name": plugin_name,
103
+ "action": "already_enabled",
104
+ "message": "Plugin is already enabled",
103
105
  }
104
106
 
105
107
  enabled_paths.append(plugin_cfg_path)
@@ -108,7 +110,9 @@ func enable_plugin(params: Dictionary) -> Dictionary:
108
110
  return _log.failure("Failed to save project.godot: " + error_string(err))
109
111
 
110
112
  var answer: Dictionary = {
111
- "plugin_name": plugin_name, "action": "enabled", "enabled_plugins": _names_of(enabled_paths)
113
+ "plugin_name": plugin_name,
114
+ "action": "enabled",
115
+ "enabled_plugins": _names_of(enabled_paths),
112
116
  }
113
117
  var unloadable: String = _why_not_loaded(plugin_cfg_path)
114
118
  if not unloadable.is_empty():
@@ -116,9 +120,9 @@ func enable_plugin(params: Dictionary) -> Dictionary:
116
120
  return answer
117
121
 
118
122
 
119
- # What the editor finds wrong with the plugin at [param plugin_cfg_path] when it loads it, the checks
120
- # EditorNode::set_addon_plugin_enabled makes, or "" when it would load. Written all the same, since
121
- # the script can be put right before the editor next starts.
123
+ # What the editor finds wrong with the plugin at [param plugin_cfg_path] when it loads it, the
124
+ # checks EditorNode::set_addon_plugin_enabled makes, or "" when it would load. Written all the same,
125
+ # since the script can be put right before the editor next starts.
122
126
  static func _why_not_loaded(plugin_cfg_path: String) -> String:
123
127
  var config: ConfigFile = ConfigFile.new()
124
128
  if config.load(plugin_cfg_path) != OK:
@@ -134,11 +138,16 @@ static func _why_not_loaded(plugin_cfg_path: String) -> String:
134
138
  # Loaded only to learn whether the editor could; what the engine says of a script that does not
135
139
  # parse is about a file the answer does not describe.
136
140
  printerr(GdhLog.ASIDE)
137
- var script: Script = ResourceLoader.load(script_path, "Script", ResourceLoader.CACHE_MODE_IGNORE)
141
+ var script: Script = ResourceLoader.load(
142
+ script_path, "Script", ResourceLoader.CACHE_MODE_IGNORE
143
+ )
138
144
  printerr(GdhLog.RESUMED)
139
145
  if script == null or script.get_instance_base_type() == &"":
140
146
  return (
141
- "%s does not compile, so the editor disables the plugin again at its next start." % script_path
147
+ (
148
+ "%s does not compile, so the editor disables the plugin again at its next start."
149
+ % script_path
150
+ )
142
151
  + " script_diagnostics names the error."
143
152
  )
144
153
  if not ClassDB.is_parent_class(script.get_instance_base_type(), "EditorPlugin"):
@@ -161,7 +170,7 @@ func disable_plugin(params: Dictionary) -> Dictionary:
161
170
  return {
162
171
  "plugin_name": plugin_name,
163
172
  "action": "already_disabled",
164
- "message": "Plugin is not currently enabled"
173
+ "message": "Plugin is not currently enabled",
165
174
  }
166
175
 
167
176
  enabled_paths.erase(plugin_cfg_path)
@@ -169,7 +178,11 @@ func disable_plugin(params: Dictionary) -> Dictionary:
169
178
  if err != OK:
170
179
  return _log.failure("Failed to save project.godot: " + error_string(err))
171
180
 
172
- return {"plugin_name": plugin_name, "action": "disabled", "enabled_plugins": _names_of(enabled_paths)}
181
+ return {
182
+ "plugin_name": plugin_name,
183
+ "action": "disabled",
184
+ "enabled_plugins": _names_of(enabled_paths),
185
+ }
173
186
 
174
187
 
175
188
  # Every entry in [editor_plugins], as the plugin.cfg path the editor stores. Paths rather than
@@ -180,13 +193,17 @@ func disable_plugin(params: Dictionary) -> Dictionary:
180
193
  # hand-edited file can carry.
181
194
  func _enabled_paths() -> Array[String]:
182
195
  var paths: Array[String] = []
183
- var enabled_value: Variant = ProjectSettings.get_setting("editor_plugins/enabled", PackedStringArray())
196
+ var enabled_value: Variant = ProjectSettings.get_setting(
197
+ "editor_plugins/enabled", PackedStringArray()
198
+ )
184
199
  if enabled_value is PackedStringArray:
185
200
  var packed: PackedStringArray = enabled_value
186
201
  paths.assign(packed)
187
202
  elif enabled_value is String:
188
203
  var listed: String = enabled_value
189
- for m: RegExMatch in GdhPatterns.compiled("res://[^\"',)]+?plugin\\.cfg").search_all(listed):
204
+ for m: RegExMatch in GdhPatterns.compiled("res://[^\"',)]+?plugin\\.cfg").search_all(
205
+ listed
206
+ ):
190
207
  paths.append(m.get_string())
191
208
  return paths
192
209
 
@@ -197,7 +214,9 @@ static func _names_of(paths: Array[String]) -> Array[String]:
197
214
  var names: Array[String] = []
198
215
  for path: String in paths:
199
216
  var inside: bool = path.begins_with("res://addons/") and path.ends_with("/plugin.cfg")
200
- names.append(path.trim_prefix("res://addons/").trim_suffix("/plugin.cfg") if inside else path)
217
+ names.append(
218
+ path.trim_prefix("res://addons/").trim_suffix("/plugin.cfg") if inside else path
219
+ )
201
220
  return names
202
221
 
203
222
 
@@ -215,6 +234,7 @@ func _save_enabled_paths(paths: Array[String]) -> Error:
215
234
  # Kept in an Array[String] and converted here, because appending to a packed array answers with
216
235
  # whether it worked and a project holding return_value_discarded at error level will not compile
217
236
  # a script that drops that answer. The conversion is what matters: an Array[String] handed to
218
- # set_setting is written as Array[String]([...]), which the editor does not read as a plugin list.
237
+ # set_setting is written as Array[String]([...]), which the editor does not read as a plugin
238
+ # list.
219
239
  ProjectSettings.set_setting("editor_plugins/enabled", PackedStringArray(paths))
220
240
  return GdhProjectFile.save(["editor_plugins/enabled"])
@@ -100,9 +100,9 @@ func set_project_setting(params: Dictionary) -> Dictionary:
100
100
  var in_file: bool = GdhProjectFile.sets(setting_path)
101
101
 
102
102
  var wanted: int = _wanted_type(setting_path, old_value if had_value else null)
103
- # A value of fields or a colour's html code is fitted as a property write fits it, so a value one
104
- # of them takes the other takes too. A number is left to the check below, which refuses one the
105
- # setting would cut where fitting it would cut it.
103
+ # A value of fields or a colour's html code is fitted as a property write fits it, so a value
104
+ # one of them takes the other takes too. A number is left to the check below, which refuses one
105
+ # the setting would cut where fitting it would cut it.
106
106
  var final_value: Variant = _values.deserialize_value(value)
107
107
  if final_value is Dictionary or (wanted == TYPE_COLOR and final_value is String):
108
108
  final_value = _values.fitted(value, wanted)
@@ -110,8 +110,8 @@ func set_project_setting(params: Dictionary) -> Dictionary:
110
110
  if not _converts_faithfully(final_value, wanted):
111
111
  return _log.failure(_cannot_hold(setting_path, wanted, final_value))
112
112
  final_value = type_convert(final_value, wanted)
113
- # JSON carries every number as a float and a new setting has no declared type to fit one to, so a
114
- # whole number was saved as 800.0 beside an answer saying 800.
113
+ # JSON carries every number as a float and a new setting has no declared type to fit one to, so
114
+ # a whole number was saved as 800.0 beside an answer saying 800.
115
115
  if not had_value and wanted == TYPE_NIL and final_value is float:
116
116
  var number: float = final_value
117
117
  if number == floorf(number) and absf(number) < 9.0e15:
@@ -132,7 +132,8 @@ func set_project_setting(params: Dictionary) -> Dictionary:
132
132
  "saved": true,
133
133
  }
134
134
  # The same value in the same type is no change, and the file is left alone: a save rewrites it
135
- # whole. The type is compared as well, so an int setting the file holds as 50.0 is still put right.
135
+ # whole. The type is compared as well, so an int setting the file holds as 50.0 is still put
136
+ # right.
136
137
  if had_value and typeof(old_value) == typeof(final_value) and old_value == final_value:
137
138
  answer["saved"] = false
138
139
  answer["unchanged"] = true
@@ -173,7 +174,9 @@ func set_project_setting(params: Dictionary) -> Dictionary:
173
174
  )
174
175
  var made: Array[String] = _translations_made_by(missing)
175
176
  if not made.is_empty():
176
- said += ("; project_import reimport makes the translation files from " + ", ".join(made))
177
+ said += (
178
+ "; project_import reimport makes the translation files from " + ", ".join(made)
179
+ )
177
180
  answer["note"] = (str(answer["note"]) + " " if answer.has("note") else "") + said + "."
178
181
  ProjectSettings.set_setting(setting_path, final_value)
179
182
  var err: Error = GdhProjectFile.save([setting_path])
@@ -193,7 +196,10 @@ func set_project_setting(params: Dictionary) -> Dictionary:
193
196
  )
194
197
  )
195
198
  answer["overridesNote"] = (
196
- "Not every build reads what was written: %s. Set or unset an override to change what its builds read."
199
+ (
200
+ "Not every build reads what was written: %s. Set or unset an override to change "
201
+ + "what its builds read."
202
+ )
197
203
  % "; ".join(parts)
198
204
  )
199
205
  return answer
@@ -238,8 +244,9 @@ static func _translations_made_by(missing: Array[String]) -> Array[String]:
238
244
  return sources
239
245
 
240
246
 
241
- # Takes a setting's line out of project.godot, so the engine's default holds again, or nothing at all
242
- # for one the engine does not declare: the way back from a set, which writes a misspelt name as given.
247
+ # Takes a setting's line out of project.godot, so the engine's default holds again, or nothing at
248
+ # all for one the engine does not declare: the way back from a set, which writes a misspelt name as
249
+ # given.
243
250
  func unset_project_setting(params: Dictionary) -> Dictionary:
244
251
  var setting_path: String = str(params.get("setting", ""))
245
252
  if setting_path.is_empty():
@@ -256,7 +263,9 @@ func unset_project_setting(params: Dictionary) -> Dictionary:
256
263
  if not held or not GdhProjectFile.sets(setting_path):
257
264
  answer["removed"] = false
258
265
  answer["saved"] = false
259
- answer["note"] = "project.godot does not set %s, so there was nothing to take out." % setting_path
266
+ answer["note"] = (
267
+ "project.godot does not set %s, so there was nothing to take out." % setting_path
268
+ )
260
269
  var near: PackedStringArray = PackedStringArray() if held else _settings_near(setting_path)
261
270
  if not near.is_empty():
262
271
  answer["note"] += (
@@ -265,8 +274,8 @@ func unset_project_setting(params: Dictionary) -> Dictionary:
265
274
  )
266
275
  return _with_what_holds(answer, setting_path)
267
276
  answer["old_value"] = _values.serialize_value(value)
268
- # The default rather than null for a setting the engine declares: null takes the declaration away
269
- # as well, and a value at its default is left out of the file all the same.
277
+ # The default rather than null for a setting the engine declares: null takes the declaration
278
+ # away as well, and a value at its default is left out of the file all the same.
270
279
  ProjectSettings.set_setting(setting_path, default_value)
271
280
  var err: Error = GdhProjectFile.save([setting_path])
272
281
  if err != OK:
@@ -340,7 +349,10 @@ static func _cannot_hold(setting_path: String, wanted: int, value: Variant) -> S
340
349
  var declared: String = "%s is declared as %s" % [setting_path, type_string(wanted)]
341
350
  var cost: String = " Setting it would save a different value than the one asked for."
342
351
  if wanted == TYPE_INT and typeof(value) == TYPE_FLOAT:
343
- return "%s, which holds whole numbers, and %s would be cut to fit.%s" % [declared, str(value), cost]
352
+ return (
353
+ "%s, which holds whole numbers, and %s would be cut to fit.%s"
354
+ % [declared, str(value), cost]
355
+ )
344
356
  if wanted in numbers and typeof(value) in numbers:
345
357
  return "%s, and %s is not the same number as one.%s" % [declared, str(value), cost]
346
358
  var given: String = type_string(typeof(value))
@@ -348,8 +360,8 @@ static func _cannot_hold(setting_path: String, wanted: int, value: Variant) -> S
348
360
  return "%s, and %s (%s) cannot become one.%s" % [declared, JSON.stringify(value), given, remedy]
349
361
 
350
362
 
351
- ## Why [param tagged], a value whose tag could not be built, was not written to [param setting_path],
352
- ## and how a value of that tag is written.
363
+ ## Why [param tagged], a value whose tag could not be built, was not written to
364
+ ## [param setting_path], and how a value of that tag is written.
353
365
  static func _unbuilt(setting_path: String, tagged: Dictionary) -> String:
354
366
  var tag: String = str(tagged["_type"])
355
367
  var refused: String = (
@@ -362,7 +374,9 @@ static func _unbuilt(setting_path: String, tagged: Dictionary) -> String:
362
374
  var keys: Array = shapes[0]
363
375
  var parts: Array[String] = ['"_type": "%s"' % tag]
364
376
  for key: Variant in keys:
365
- parts.append('"%s": %s' % [key, "[...]" if tag.begins_with("Packed") and key == "value" else "..."])
377
+ parts.append(
378
+ '"%s": %s' % [key, "[...]" if tag.begins_with("Packed") and key == "value" else "..."]
379
+ )
366
380
  return refused + " One is written as {%s}." % ", ".join(parts)
367
381
 
368
382
 
@@ -376,11 +390,14 @@ func add_autoload(params: Dictionary) -> Dictionary:
376
390
  # every start. `enabled: false` used to write the entry without its asterisk and answer that it
377
391
  # was disabled, and the autoload ran all the same.
378
392
  if not GdhRead.as_bool(params.get("enabled", true), true):
379
- return _log.failure(
380
- (
381
- "An autoload cannot be added disabled: Godot loads every autoload in the list at every"
382
- + " start. global: false keeps its name out of the global scope and still loads it;"
383
- + " remove_autoload is what stops it loading"
393
+ return (
394
+ _log
395
+ . failure(
396
+ (
397
+ "An autoload cannot be added disabled: Godot loads every autoload in the list "
398
+ + "at every start. global: false keeps its name out of the global scope and "
399
+ + "still loads it; remove_autoload is what stops it loading"
400
+ )
384
401
  )
385
402
  )
386
403
 
@@ -414,7 +431,7 @@ func add_autoload(params: Dictionary) -> Dictionary:
414
431
  "enabled": true,
415
432
  "global": global,
416
433
  "action": "unchanged",
417
- "saved": false
434
+ "saved": false,
418
435
  }
419
436
  ProjectSettings.set_setting(setting, entry)
420
437
  var err: Error = GdhProjectFile.save([setting])
@@ -452,7 +469,10 @@ static func _autoload_name_refusal(name: String) -> String:
452
469
  if reason.is_empty():
453
470
  return ""
454
471
  return (
455
- "%s cannot name an autoload: %s. Nothing was written; the editor's Autoload tab refuses it too."
472
+ (
473
+ "%s cannot name an autoload: %s. Nothing was written; the editor's Autoload tab "
474
+ + "refuses it too."
475
+ )
456
476
  % [JSON.stringify(name), reason]
457
477
  )
458
478
 
@@ -473,7 +493,7 @@ func remove_autoload(params: Dictionary) -> Dictionary:
473
493
  if err != OK:
474
494
  return _log.failure("Failed to save project.godot: " + error_string(err))
475
495
 
476
- return {"name": name, "removed": true, "old_path": old_value.trim_prefix("*")}
496
+ return { "name": name, "removed": true, "old_path": old_value.trim_prefix("*") }
477
497
 
478
498
 
479
499
  # List all autoload singletons
@@ -500,7 +520,7 @@ func list_autoloads(_params: Dictionary) -> Dictionary:
500
520
  }
501
521
  autoloads.append(autoload_info)
502
522
 
503
- return {"autoloads": autoloads, "count": autoloads.size()}
523
+ return { "autoloads": autoloads, "count": autoloads.size() }
504
524
 
505
525
 
506
526
  # Set the main scene
@@ -514,7 +534,9 @@ func set_main_scene(params: Dictionary) -> Dictionary:
514
534
 
515
535
  if not FileAccess.file_exists(scene_path):
516
536
  return _log.failure(
517
- GdhFileWalk.new().with_nearest_files("Scene file does not exist: " + scene_path, scene_path)
537
+ GdhFileWalk.new().with_nearest_files(
538
+ "Scene file does not exist: " + scene_path, scene_path
539
+ )
518
540
  )
519
541
 
520
542
  # The engine starts the game by instancing the main scene, so a script or any other resource set
@@ -526,7 +548,9 @@ func set_main_scene(params: Dictionary) -> Dictionary:
526
548
  "%s is %s, not a scene, and the main scene has to be one"
527
549
  % [scene_path, "a " + kind if not kind.is_empty() else "no resource the engine loads"]
528
550
  )
529
- return _log.failure(GdhFileWalk.new().with_nearest_files(said, scene_path.get_basename() + ".tscn"))
551
+ return _log.failure(
552
+ GdhFileWalk.new().with_nearest_files(said, scene_path.get_basename() + ".tscn")
553
+ )
530
554
 
531
555
  var old_main_scene: String = str(ProjectSettings.get_setting("application/run/main_scene", ""))
532
556
 
@@ -536,4 +560,4 @@ func set_main_scene(params: Dictionary) -> Dictionary:
536
560
  if err != OK:
537
561
  return _log.failure("Failed to save project settings: " + str(err))
538
562
 
539
- return {"old_main_scene": old_main_scene, "new_main_scene": scene_path, "saved": true}
563
+ return { "old_main_scene": old_main_scene, "new_main_scene": scene_path, "saved": true }
@@ -40,14 +40,17 @@ func get_project_health(params: Dictionary) -> Dictionary:
40
40
  # failed this check and lost points, while Godot's own guidance is to keep a scene's files
41
41
  # together by feature, so the check failed projects for following the engine's advice.
42
42
 
43
- checks["structure"] = {"name": "Project Structure", "passed": details.is_empty(), "details": details}
43
+ checks["structure"] = {
44
+ "name": "Project Structure", "passed": details.is_empty(), "details": details,
45
+ }
44
46
 
45
47
  # 2. Resource Check
46
48
  if "resources" in check_categories:
47
49
  var details: Array[String] = []
48
50
 
49
- # Every format the engine imports, the list the import status reads: five of them were checked
50
- # here, so a project of glTF models, fonts and WebP textures had nothing to reimport.
51
+ # Every format the engine imports, the list the import status reads: five of them were
52
+ # checked here, so a project of glTF models, fonts and WebP textures had nothing to
53
+ # reimport.
51
54
  var resources: Array[String] = _files.find_files_with_extensions(
52
55
  "res://", GdhImportPipeline.IMPORTABLE_EXTENSIONS
53
56
  )
@@ -68,7 +71,7 @@ func get_project_health(params: Dictionary) -> Dictionary:
68
71
  "details": details,
69
72
  # What the check read: files the engine imports. A .tres is a resource and was counted
70
73
  # under this name as none, beside a project holding one.
71
- "importable_files": resources.size()
74
+ "importable_files": resources.size(),
72
75
  }
73
76
 
74
77
  # 3. Scripts Check
@@ -106,7 +109,7 @@ func get_project_health(params: Dictionary) -> Dictionary:
106
109
  "name": "Scripts",
107
110
  "passed": details.is_empty(),
108
111
  "details": details,
109
- "total_scripts": script_files.size()
112
+ "total_scripts": script_files.size(),
110
113
  }
111
114
  if compiled.has("checked"):
112
115
  scripts["compiled"] = GdhRead.as_int(compiled["checked"])
@@ -123,14 +126,18 @@ func get_project_health(params: Dictionary) -> Dictionary:
123
126
  for entry: Dictionary in GdhInputActions.new(_log).undefined_in_scripts():
124
127
  details.append(GdhInputActions.undefined_line(entry))
125
128
  deductions += 5
126
- checks["references"] = {"name": "References", "passed": details.is_empty(), "details": details}
129
+ checks["references"] = {
130
+ "name": "References", "passed": details.is_empty(), "details": details,
131
+ }
127
132
 
128
133
  # 4. Scenes Check
129
134
  if "scenes" in check_categories:
130
135
  var details: Array[String] = []
131
136
 
132
137
  # Binary scenes too, which a project may save instead and which counted as none.
133
- var scene_files: Array[String] = _files.find_files_with_extensions("res://", ["tscn", "scn"])
138
+ var scene_files: Array[String] = _files.find_files_with_extensions(
139
+ "res://", ["tscn", "scn"]
140
+ )
134
141
  if scene_files.size() == 0:
135
142
  details.append("No scene files found in project")
136
143
  deductions += 5
@@ -142,7 +149,7 @@ func get_project_health(params: Dictionary) -> Dictionary:
142
149
  "name": "Scenes",
143
150
  "passed": details.is_empty(),
144
151
  "details": details,
145
- "total_scenes": scene_files.size()
152
+ "total_scenes": scene_files.size(),
146
153
  }
147
154
 
148
155
  # 5. Configuration Check
@@ -162,7 +169,9 @@ func get_project_health(params: Dictionary) -> Dictionary:
162
169
  details.append("No project name set")
163
170
  deductions += 2
164
171
 
165
- checks["config"] = {"name": "Configuration", "passed": details.is_empty(), "details": details}
172
+ checks["config"] = {
173
+ "name": "Configuration", "passed": details.is_empty(), "details": details,
174
+ }
166
175
 
167
176
  var score: int = maxi(0, 100 - deductions)
168
177
 
@@ -193,7 +202,11 @@ func get_project_health(params: Dictionary) -> Dictionary:
193
202
  var check: Dictionary = checks[category]
194
203
  var found: Array[String] = check["details"]
195
204
  for detail: String in found:
196
- issues.append({"check": category, "detail": detail})
205
+ issues.append({ "check": category, "detail": detail })
197
206
  return {
198
- "score": score, "grade": grade, "checks": checks, "issues": issues, "recommendations": recommendations
207
+ "score": score,
208
+ "grade": grade,
209
+ "checks": checks,
210
+ "issues": issues,
211
+ "recommendations": recommendations,
199
212
  }
@@ -1,16 +1,15 @@
1
1
  extends RefCounted
2
-
3
2
  ## project.godot written through the engine's own save, in the order the file already held.
4
3
  ##
5
4
  ## The engine writes each section's keys in the order it registered them, and an engine running a
6
5
  ## script registers them in another order than the editor does, so a one-setting change moved lines
7
- ## nobody touched across several sections and a commit of it read as a rewrite. The save is still the
8
- ## engine's, for what only it gets right: the header and the text of each value the call changed.
9
- ## The order is taken from the file as it was, and so is every line of a key the call did not change,
10
- ## because the engine writes its settings as it holds them rather than as the file had them. It
11
- ## leaves out each key at its default, so a project holding `unsafe_call_argument=0` on purpose lost
12
- ## the line to a change of another key. It writes a dictionary with its keys sorted, so gdUnit4's
13
- ## session hooks, which run in the order listed, changed order. And it writes what a
6
+ ## nobody touched across several sections and a commit of it read as a rewrite. The save is still
7
+ ## the engine's, for what only it gets right: the header and the text of each value the call
8
+ ## changed. The order is taken from the file as it was, and so is every line of a key the call did
9
+ ## not change, because the engine writes its settings as it holds them rather than as the file had
10
+ ## them. It leaves out each key at its default, so a project holding `unsafe_call_argument=0` on
11
+ ## purpose lost the line to a change of another key. It writes a dictionary with its keys sorted, so
12
+ ## gdUnit4's session hooks, which run in the order listed, changed order. And it writes what a
14
13
  ## `project_settings_override` file laid over the project, so a player's window mode in the user
15
14
  ## directory became the game's default.
16
15
 
@@ -42,8 +41,8 @@ static func save(changed: PackedStringArray) -> Error:
42
41
  ## [param before] with the lines of the settings in [param changed] as [param written] has them: one
43
42
  ## the engine wrote goes in its place, or where the engine put it relative to its neighbours when it
44
43
  ## is new, and one the engine left out leaves the file. Every other line is [param before]'s, in its
45
- ## place, and a key the engine wrote that the file did not hold and the call did not change stays out.
46
- ## The header is [param written]'s.
44
+ ## place, and a key the engine wrote that the file did not hold and the call did not change stays
45
+ ## out. The header is [param written]'s.
47
46
  static func in_order_of(before: String, written: String, changed: PackedStringArray) -> String:
48
47
  var old: Dictionary = _parsed(before)
49
48
  var fresh: Dictionary = _parsed(written)
@@ -113,8 +112,8 @@ static func in_order_of(before: String, written: String, changed: PackedStringAr
113
112
  fresh_keys[name].append(str(entry["key"]))
114
113
 
115
114
  # The blank lines closing a section belong to its place in the file rather than to the section,
116
- # so the last one keeps the ending the engine gave the file wherever it moved from. A section put
117
- # back sits between two others, which the engine parts with a blank line.
115
+ # so the last one keeps the ending the engine gave the file wherever it moved from. A section
116
+ # put back sits between two others, which the engine parts with a blank line.
118
117
  var names: Array[String] = _merged(old_names, fresh_names)
119
118
  var tails: Array[String] = []
120
119
  for section: Dictionary in fresh_sections:
@@ -181,7 +180,8 @@ static func _merged(held: Array[String], wanted: Array[String]) -> Array[String]
181
180
 
182
181
 
183
182
  ## [param text] as a preamble (the header and anything before the first section) and its sections,
184
- ## each with its header line and the blank lines after it, its entries, and the blank lines closing it.
183
+ ## each with its header line and the blank lines after it, its entries, and the blank lines closing
184
+ ## it.
185
185
  static func _parsed(text: String) -> Dictionary:
186
186
  var preamble: String = ""
187
187
  var sections: Array[Dictionary] = []
@@ -193,7 +193,7 @@ static func _parsed(text: String) -> Dictionary:
193
193
  if not current.is_empty():
194
194
  _close(current, body)
195
195
  sections.append(current)
196
- current = {"name": stripped.substr(1, stripped.length() - 2), "head": line}
196
+ current = { "name": stripped.substr(1, stripped.length() - 2), "head": line }
197
197
  body = []
198
198
  elif current.is_empty():
199
199
  preamble += line
@@ -204,7 +204,7 @@ static func _parsed(text: String) -> Dictionary:
204
204
  if not current.is_empty():
205
205
  _close(current, body)
206
206
  sections.append(current)
207
- return {"preamble": preamble, "sections": sections}
207
+ return { "preamble": preamble, "sections": sections }
208
208
 
209
209
 
210
210
  ## Fills in [param section]'s entries and closing blank lines from the lines after its head. A blank
@@ -218,7 +218,7 @@ static func _close(section: Dictionary, body: Array[String]) -> void:
218
218
  for line: String in body:
219
219
  var stripped: String = line.strip_edges()
220
220
  if entries.is_empty() or not (stripped.is_empty() or stripped.begins_with(";")):
221
- entries.append({"key": _key_of(line), "text": line})
221
+ entries.append({ "key": _key_of(line), "text": line })
222
222
  else:
223
223
  var last: Dictionary = entries[entries.size() - 1]
224
224
  last["text"] = str(last["text"]) + line