gdharness 1.3.41 → 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 (107) hide show
  1. package/build/cli.js +131 -47
  2. package/build/godot/addons/auto_reload/auto_reload.gd +18 -19
  3. package/build/godot/addons/gdharness_editor/animation_reads.gd +84 -35
  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 +114 -39
  7. package/build/godot/addons/gdharness_editor/file_walk.gd +12 -5
  8. package/build/godot/addons/gdharness_editor/headless_check.gd +94 -41
  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 +136 -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 +41 -28
  20. package/build/godot/addons/gdharness_editor/tools/animation_tools.gd +84 -50
  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 +181 -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 +75 -43
  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 +66 -0
  33. package/build/godot/addons/gdharness_editor/tools/scene_sharing.gd.uid +1 -0
  34. package/build/godot/addons/gdharness_editor/tools/scene_tools.gd +171 -62
  35. package/build/godot/addons/gdharness_editor/tools/script_paths.gd +20 -8
  36. package/build/godot/addons/gdharness_editor/tools/settings_tools.gd +11 -8
  37. package/build/godot/addons/gdharness_editor/tools/signal_tools.gd +47 -34
  38. package/build/godot/addons/gdharness_editor/tools/tileset_tools.gd +77 -50
  39. package/build/godot/addons/gdharness_editor/value_shapes.gd +5 -6
  40. package/build/godot/addons/gdharness_runtime/call_errors.gd +1 -2
  41. package/build/godot/addons/gdharness_runtime/declared_values.gd +68 -32
  42. package/build/godot/addons/gdharness_runtime/error_report.gd +1 -2
  43. package/build/godot/addons/gdharness_runtime/reading.gd +37 -12
  44. package/build/godot/addons/gdharness_runtime/runtime_accessibility.gd +84 -63
  45. package/build/godot/addons/gdharness_runtime/runtime_autoload.gd +153 -148
  46. package/build/godot/addons/gdharness_runtime/runtime_capture.gd +64 -42
  47. package/build/godot/addons/gdharness_runtime/runtime_changes.gd +184 -122
  48. package/build/godot/addons/gdharness_runtime/runtime_frames.gd +2 -2
  49. package/build/godot/addons/gdharness_runtime/runtime_hover.gd +24 -20
  50. package/build/godot/addons/gdharness_runtime/runtime_input.gd +134 -92
  51. package/build/godot/addons/gdharness_runtime/runtime_items.gd +29 -13
  52. package/build/godot/addons/gdharness_runtime/runtime_menus.gd +0 -1
  53. package/build/godot/addons/gdharness_runtime/runtime_mouse.gd +38 -20
  54. package/build/godot/addons/gdharness_runtime/runtime_pad.gd +17 -13
  55. package/build/godot/addons/gdharness_runtime/runtime_paths.gd +84 -46
  56. package/build/godot/addons/gdharness_runtime/runtime_queries.gd +117 -79
  57. package/build/godot/addons/gdharness_runtime/runtime_says.gd +14 -17
  58. package/build/godot/addons/gdharness_runtime/runtime_screen.gd +23 -16
  59. package/build/godot/addons/gdharness_runtime/runtime_targets.gd +117 -66
  60. package/build/godot/addons/gdharness_runtime/runtime_touch.gd +211 -0
  61. package/build/godot/addons/gdharness_runtime/runtime_touch.gd.uid +1 -0
  62. package/build/godot/addons/gdharness_runtime/runtime_typing.gd +44 -27
  63. package/build/godot/addons/gdharness_runtime/runtime_values.gd +108 -73
  64. package/build/godot/addons/gdharness_runtime/runtime_waits.gd +111 -84
  65. package/build/godot/addons/gdharness_runtime/runtime_words.gd +10 -7
  66. package/build/godot/addons/gdharness_runtime/serialisation.gd +75 -51
  67. package/build/godot/addons/gdharness_runtime/value_shapes.gd +5 -6
  68. package/build/godot/addons/gdharness_tests/bench.gd +4 -5
  69. package/build/godot/addons/gdharness_tests/event.gd +10 -5
  70. package/build/godot/addons/gdharness_tests/share.gd +38 -18
  71. package/build/godot/addons/gdharness_tests/suites.gd +3 -3
  72. package/build/godot/addons/gdharness_tests/wait.gd +3 -2
  73. package/build/godot/loader/loader.gd +9 -9
  74. package/build/godot/operations/animation_reads.gd +84 -35
  75. package/build/godot/operations/audio_buses.gd +48 -19
  76. package/build/godot/operations/class_cache.gd +16 -11
  77. package/build/godot/operations/classdb_queries.gd +89 -44
  78. package/build/godot/operations/declared_values.gd +68 -32
  79. package/build/godot/operations/dependencies.gd +139 -93
  80. package/build/godot/operations/editor_tools.gd +9 -10
  81. package/build/godot/operations/export_presets.gd +100 -54
  82. package/build/godot/operations/file_reads.gd +114 -39
  83. package/build/godot/operations/file_walk.gd +12 -5
  84. package/build/godot/operations/gdscript_analysis.gd +105 -66
  85. package/build/godot/operations/gdscript_authoring.gd +138 -39
  86. package/build/godot/operations/godot_operations.gd +17 -11
  87. package/build/godot/operations/import_pipeline.gd +110 -59
  88. package/build/godot/operations/input_actions.gd +63 -39
  89. package/build/godot/operations/patterns.gd +3 -1
  90. package/build/godot/operations/plugins.gd +36 -16
  91. package/build/godot/operations/project_config.gd +144 -27
  92. package/build/godot/operations/project_diagnostics.gd +24 -11
  93. package/build/godot/operations/project_file.gd +16 -16
  94. package/build/godot/operations/project_validation.gd +71 -44
  95. package/build/godot/operations/property_paths.gd +22 -12
  96. package/build/godot/operations/property_values.gd +143 -78
  97. package/build/godot/operations/reading.gd +37 -12
  98. package/build/godot/operations/rename_checks.gd +2 -2
  99. package/build/godot/operations/resource_files.gd +11 -9
  100. package/build/godot/operations/same_values.gd +4 -4
  101. package/build/godot/operations/scene_connections.gd +27 -13
  102. package/build/godot/operations/script_check.gd +52 -49
  103. package/build/godot/operations/serialisation.gd +75 -51
  104. package/build/godot/operations/setting_reads.gd +7 -6
  105. package/build/godot/operations/value_shapes.gd +5 -6
  106. package/build/godot/tests/listed.gd +321 -268
  107. package/package.json +1 -1
@@ -1,5 +1,4 @@
1
1
  extends RefCounted
2
-
3
2
  ## What reaches the running game the way a keyboard reaches it: text typed into the field that has
4
3
  ## the focus, and an item chosen out of a menu the way a keyboard chooses one.
5
4
 
@@ -8,7 +7,6 @@ const GdhRead = preload("reading.gd")
8
7
  const GdhTargets = preload("runtime_targets.gd")
9
8
  const GdhValues = preload("runtime_values.gd")
10
9
  const GdhWords = preload("runtime_words.gd")
11
-
12
10
  ## The two characters a field reads as keys rather than as text.
13
11
  const NEWLINE: int = 10
14
12
  const TAB: int = 9
@@ -43,13 +41,15 @@ func inject_text(params: Dictionary) -> Dictionary:
43
41
  var text: String = str(params.get("text", ""))
44
42
  var over: bool = GdhRead.as_bool(params.get("replace", false))
45
43
  if text.is_empty() and not over:
46
- return {"type": "error", "message": "text needs something to type, or replace to empty a field"}
44
+ return {
45
+ "type": "error", "message": "text needs something to type, or replace to empty a field",
46
+ }
47
47
 
48
48
  var viewport: Viewport = _host.get_tree().root
49
49
  var focused: Control = focus_owner(viewport)
50
50
  var shut: String = _shut_to_typing(focused)
51
51
  if not shut.is_empty():
52
- return {"type": "error", "message": shut}
52
+ return { "type": "error", "message": shut }
53
53
 
54
54
  # Where it goes, which is the one thing a caller cannot see from here, read before the keys: a
55
55
  # name field that swaps its panel out on Enter has left the tree by the time the keys are done,
@@ -87,9 +87,10 @@ func inject_text(params: Dictionary) -> Dictionary:
87
87
  if into != null and before.is_empty():
88
88
  answer["note"] = (
89
89
  (
90
- "%s has the focus and is no LineEdit or TextEdit, so each character reached it as a key"
91
- + " press and went on to the game's input unless it kept it, and a focused button takes a"
92
- + " space or Enter as a press of it. Click a field first to type into one."
90
+ "%s has the focus and is no LineEdit or TextEdit, so each character reached it as "
91
+ + "a key press and went on to the game's input unless it kept it, and a focused "
92
+ + "button takes a space or Enter as a press of it. Click a field first to type "
93
+ + "into one."
93
94
  )
94
95
  % into
95
96
  )
@@ -102,10 +103,10 @@ func inject_text(params: Dictionary) -> Dictionary:
102
103
  static func field_before(focused: Control) -> Dictionary:
103
104
  var field: LineEdit = focused as LineEdit
104
105
  if field != null:
105
- return {"text": field.text, "editing": field.is_editing()}
106
+ return { "text": field.text, "editing": field.is_editing() }
106
107
  var box: TextEdit = focused as TextEdit
107
108
  if box != null:
108
- return {"text": box.text, "editing": true}
109
+ return { "text": box.text, "editing": true }
109
110
  return {}
110
111
 
111
112
 
@@ -216,7 +217,9 @@ static func _shut_to_typing(focused: Control) -> String:
216
217
  var field: LineEdit = focused as LineEdit
217
218
  var box: TextEdit = focused as TextEdit
218
219
  if (field != null and not field.editable) or (box != null and not box.editable):
219
- return "%s has the focus and is read-only, so nothing typed lands in it." % focused.get_path()
220
+ return (
221
+ "%s has the focus and is read-only, so nothing typed lands in it." % focused.get_path()
222
+ )
220
223
  if field == null or field.is_editing():
221
224
  return ""
222
225
  return (
@@ -281,7 +284,7 @@ static func _typed(glyph: int) -> InputEventKey:
281
284
  func choose(params: Dictionary) -> Dictionary:
282
285
  var node_path: String = str(params.get("path", ""))
283
286
  if node_path.is_empty():
284
- return {"type": "error", "message": "Node path required"}
287
+ return { "type": "error", "message": "Node path required" }
285
288
  var standing: Dictionary = GdhValues.node_at(_host.get_tree().root, node_path)
286
289
  if standing.has("message"):
287
290
  return standing
@@ -295,7 +298,7 @@ func choose(params: Dictionary) -> Dictionary:
295
298
  (
296
299
  "%s is a %s, which is neither a PopupMenu nor something holding one"
297
300
  % [node_path, node.get_class()]
298
- )
301
+ ),
299
302
  }
300
303
 
301
304
  if not params.has("index") and str(params.get("text", "")).is_empty():
@@ -305,27 +308,33 @@ func choose(params: Dictionary) -> Dictionary:
305
308
  (
306
309
  "%s needs the item named, by text or index. It holds: %s"
307
310
  % [node_path, ", ".join(GdhMenus.items_of(menu))]
308
- )
311
+ ),
309
312
  }
310
313
 
311
- # A button a player cannot use is refused, as a click refuses one: the engine opens the menu of a
312
- # disabled or hidden OptionButton when asked to, measured on 4.7.2, and the pick then changed a
313
- # selection no player could have changed.
314
+ # A button a player cannot use is refused, as a click refuses one: the engine opens the menu of
315
+ # a disabled or hidden OptionButton when asked to, measured on 4.7.2, and the pick then changed
316
+ # a selection no player could have changed.
314
317
  var holder: BaseButton = node as BaseButton
315
318
  if holder != null and holder.disabled:
316
- return {"type": "error", "message": "%s is disabled, so its menu cannot be opened" % node_path}
319
+ return {
320
+ "type": "error", "message": "%s is disabled, so its menu cannot be opened" % node_path,
321
+ }
317
322
  if holder != null and not holder.is_visible_in_tree():
318
323
  return {
319
324
  "type": "error",
320
325
  "message":
321
- "%s is not visible%s, so its menu cannot be opened" % [node_path, GdhTargets.why_hidden(holder)]
326
+ (
327
+ "%s is not visible%s, so its menu cannot be opened"
328
+ % [node_path, GdhTargets.why_hidden(holder)]
329
+ ),
322
330
  }
323
331
 
324
332
  # Shown first, because a menu nobody has opened has no focus to move and the press would go to
325
333
  # whatever is behind it, and before the item is looked for, because opening is when a game fills
326
334
  # a menu: one rebuilt on about_to_popup was read as it stood before, measured on 4.7.2, and the
327
- # index found in the old items chose another item of the new ones. An OptionButton opens its own;
328
- # a bare PopupMenu is popped where it already sits, which leaves a menu already open where it is.
335
+ # index found in the old items chose another item of the new ones. An OptionButton opens its
336
+ # own; a bare PopupMenu is popped where it already sits, which leaves a menu already open where
337
+ # it is.
329
338
  var opened: bool = GdhMenus.open_the_menu(node, menu)
330
339
  await _host.get_tree().process_frame
331
340
 
@@ -339,15 +348,23 @@ func choose(params: Dictionary) -> Dictionary:
339
348
  "type": "error",
340
349
  "message":
341
350
  (
342
- "%s has %d items that say %s, so nothing was chosen: %s. Name one by its whole text or by index"
343
- % [node_path, found.size(), JSON.stringify(str(params.get("text", ""))), ", ".join(tied)]
344
- )
351
+ (
352
+ "%s has %d items that say %s, so nothing was chosen: %s. Name one by its whole "
353
+ + "text or by index"
354
+ )
355
+ % [
356
+ node_path,
357
+ found.size(),
358
+ JSON.stringify(str(params.get("text", ""))),
359
+ ", ".join(tied),
360
+ ]
361
+ ),
345
362
  }
346
363
  var index: int = found[0] if found.size() == 1 else -1
347
364
  var refused: String = _not_a_choice(node_path, menu, index)
348
365
  if not refused.is_empty():
349
366
  await _shut(menu, opened)
350
- return {"type": "error", "message": refused}
367
+ return { "type": "error", "message": refused }
351
368
 
352
369
  # Read before the press, because the press can take the menu away: a game that rebuilds its
353
370
  # settings screen on item_selected frees the button and its menu inside the pick, and reading
@@ -385,11 +402,11 @@ func choose(params: Dictionary) -> Dictionary:
385
402
  "message":
386
403
  (
387
404
  (
388
- "%s item %d, %s, had the focus and ui_accept was pressed, and the menu did not take it,"
389
- + " so nothing was chosen"
405
+ "%s item %d, %s, had the focus and ui_accept was pressed, and the menu did not "
406
+ + "take it, so nothing was chosen"
390
407
  )
391
408
  % [node_path, index, answer["text"]]
392
- )
409
+ ),
393
410
  }
394
411
 
395
412
  answer["control_afterwards"] = GdhValues.afterwards(node)
@@ -1,5 +1,4 @@
1
1
  extends RefCounted
2
-
3
2
  ## What crosses the wire between the game and the server, in both directions: Godot values
4
3
  ## as JSON-safe dictionaries, and JSON back into the values a property or parameter wants.
5
4
  ##
@@ -12,7 +11,6 @@ const GdhDeclared = preload("declared_values.gd")
12
11
  const GdhRead = preload("reading.gd")
13
12
  const GdhSerialisation = preload("serialisation.gd")
14
13
  const GdhShapes = preload("value_shapes.gd")
15
-
16
14
  ## The engine singletons a call, a write or a read may name instead of a node: what the engine
17
15
  ## measures, and the engine settings that are the game's own. Not every singleton: OS runs programs
18
16
  ## and opens files, DisplayServer switches the keyboard's layout and Input moves the real pointer,
@@ -61,7 +59,7 @@ func deserialize(value: Variant) -> Variant:
61
59
  ## that take them are the property and the method.
62
60
  static func node_at(root: Node, path: String) -> Dictionary:
63
61
  if path.is_empty():
64
- return {"type": "error", "message": "Node path required"}
62
+ return { "type": "error", "message": "Node path required" }
65
63
 
66
64
  if path.contains(":"):
67
65
  var shape: String = (
@@ -75,8 +73,8 @@ static func node_at(root: Node, path: String) -> Dictionary:
75
73
 
76
74
  var node: Node = root.get_node_or_null(path)
77
75
  if node == null:
78
- return {"type": "error", "message": _not_found(root, path)}
79
- return {"node": node}
76
+ return { "type": "error", "message": _not_found(root, path) }
77
+ return { "node": node }
80
78
 
81
79
 
82
80
  ## "Node not found" for [param path], with the deepest node of it the game has and the children that
@@ -90,7 +88,10 @@ static func _not_found(root: Node, path: String) -> String:
90
88
  var meant: Node = scene.get_node_or_null(path)
91
89
  if meant != null:
92
90
  return (
93
- "%s. Paths here go from the root, /root, not from the current scene, so this one is %s."
91
+ (
92
+ "%s. Paths here go from the root, /root, not from the current scene, so this "
93
+ + "one is %s."
94
+ )
94
95
  % [said, str(meant.get_path())]
95
96
  )
96
97
  var parts: PackedStringArray = path.split("/", false)
@@ -111,7 +112,9 @@ static func _not_found(root: Node, path: String) -> String:
111
112
  var names: PackedStringArray = []
112
113
  for child: Node in at.get_children():
113
114
  var _named: bool = names.append(str(child.name))
114
- return GdhRead.missing_below(said, "", PackedStringArray([str(at.get_path())]), parts[step], names)
115
+ return GdhRead.missing_below(
116
+ said, "", PackedStringArray([str(at.get_path())]), parts[step], names
117
+ )
115
118
 
116
119
 
117
120
  ## How many process frames a whole press holds before its release, from `holdFrames`: one unless
@@ -150,7 +153,7 @@ static func hold(tree: SceneTree, frames: int) -> Dictionary:
150
153
  for _frame: int in frames:
151
154
  await tree.process_frame
152
155
  return {
153
- "seconds": snappedf((Time.get_ticks_usec() - began_usec) / 1000000.0, 0.001),
156
+ "seconds": snappedf((Time.get_ticks_usec() - began_usec) / 1_000_000.0, 0.001),
154
157
  "physics_frames": Engine.get_physics_frames() - began_tick,
155
158
  }
156
159
 
@@ -169,9 +172,9 @@ static func glyph_of(keycode: Key, shifted: bool) -> int:
169
172
  return keycode
170
173
 
171
174
 
172
- ## The refusal for [param name], which no key is called, with the key names nearest it. Read from the
173
- ## engine's own names, printable keys and the special ones above [constant KEY_SPECIAL], since the
174
- ## game takes any name OS.find_keycode_from_string does.
175
+ ## The refusal for [param name], which no key is called, with the key names nearest it. Read from
176
+ ## the engine's own names, printable keys and the special ones above [constant KEY_SPECIAL], since
177
+ ## the game takes any name OS.find_keycode_from_string does.
175
178
  static func unknown_key(name: String) -> String:
176
179
  var close: PackedStringArray = GdhRead.nearest(name, _key_names())
177
180
  var said: String = "No key is called %s." % name
@@ -205,8 +208,9 @@ static func _key_names() -> PackedStringArray:
205
208
 
206
209
 
207
210
  ## The refusal for [param action], which the input map lacks, with the nearest of the project's own
208
- ## actions, or else all of them. The engine's ui_ ones are in every project, and offered for any name
209
- ## they only buried the project's ("dance" is near ui_cancel), so they are offered for a ui_ name only.
211
+ ## actions, or else all of them. The engine's ui_ ones are in every project, and offered for any
212
+ ## name they only buried the project's ("dance" is near ui_cancel), so they are offered for a ui_
213
+ ## name only.
210
214
  static func no_action(action: String) -> String:
211
215
  var engine: PackedStringArray = []
212
216
  var own: PackedStringArray = []
@@ -217,12 +221,23 @@ static func no_action(action: String) -> String:
217
221
  var _owned: bool = own.append(str(named))
218
222
  own.sort()
219
223
  var said: String = "Action not found: %s" % action
220
- var close: PackedStringArray = GdhRead.nearest(action, engine if action.begins_with("ui_") else own)
224
+ var close: PackedStringArray = GdhRead.nearest(
225
+ action, engine if action.begins_with("ui_") else own
226
+ )
221
227
  if not close.is_empty():
222
- return "%s; the nearest %s %s." % [said, "is" if close.size() == 1 else "are", ", ".join(close)]
228
+ return (
229
+ "%s; the nearest %s %s."
230
+ % [said, "is" if close.size() == 1 else "are", ", ".join(close)]
231
+ )
223
232
  if own.is_empty():
224
- return "%s; the project defines no actions of its own, and the engine's are the ui_ ones." % said
225
- return "%s; the project's own actions are %s, beside the engine's ui_ ones." % [said, ", ".join(own)]
233
+ return (
234
+ "%s; the project defines no actions of its own, and the engine's are the ui_ ones."
235
+ % said
236
+ )
237
+ return (
238
+ "%s; the project's own actions are %s, beside the engine's ui_ ones."
239
+ % [said, ", ".join(own)]
240
+ )
226
241
 
227
242
 
228
243
  ## The actions of the input map that [param event] stands for, as Input reads it for
@@ -248,10 +263,11 @@ static func focus_path(host: Node) -> String:
248
263
  return "" if holding == null else str(holding.get_path())
249
264
 
250
265
 
251
- ## [param said] with [param focused], the Control that had the focus, under focused. A key, an action
252
- ## or a pad's event reaches that Control before the game's _unhandled_input: Space on a focused Button
253
- ## pressed it and the game's own handler counted the key as well, and a stick pushed down moved a
254
- ## focused list's selection and never reached the game, with nothing in the answer saying why.
266
+ ## [param said] with [param focused], the Control that had the focus, under focused. A key, an
267
+ ## action or a pad's event reaches that Control before the game's _unhandled_input: Space on a
268
+ ## focused Button pressed it and the game's own handler counted the key as well, and a stick pushed
269
+ ## down moved a focused list's selection and never reached the game, with nothing in the answer
270
+ ## saying why.
255
271
  ##
256
272
  ## Where the focus is once the event has been handled goes under focused_after when it moved, null
257
273
  ## when nothing holds it then: ui_down on a focused button hands the focus to its neighbour, and an
@@ -314,7 +330,7 @@ static func press_shortcuts(root: Node, action: String) -> Dictionary:
314
330
  var pressed: Variant = null
315
331
  if not taken.is_empty():
316
332
  pressed = taken[0]
317
- return {"shortcuts": paths, "shortcut_pressed": pressed}
333
+ return { "shortcuts": paths, "shortcut_pressed": pressed }
318
334
 
319
335
 
320
336
  ## The methods [param object] answers to, as the engine lists them: for a script itself, the static
@@ -336,16 +352,16 @@ static func methods_of(object: Object) -> Array[Dictionary]:
336
352
  ## named in a value are found from, which for a singleton is [param root].
337
353
  static func target_at(root: Node, path: String) -> Dictionary:
338
354
  if SINGLETONS.has(path):
339
- return {"object": Engine.get_singleton(path), "node": root}
355
+ return { "object": Engine.get_singleton(path), "node": root }
340
356
  if not path.contains("/") and Engine.has_singleton(path):
341
357
  return {
342
358
  "type": "error",
343
359
  "message":
344
360
  (
345
361
  (
346
- "%s is an engine singleton, and the ones that can be reached are %s. The rest act"
347
- + " on the machine rather than the game: OS runs programs, DisplayServer switches the"
348
- + " keyboard's layout and Input moves the real pointer."
362
+ "%s is an engine singleton, and the ones that can be reached are %s. The rest "
363
+ + "act on the machine rather than the game: OS runs programs, DisplayServer "
364
+ + "switches the keyboard's layout and Input moves the real pointer."
349
365
  )
350
366
  % [path, ", ".join(SINGLETONS)]
351
367
  ),
@@ -353,7 +369,7 @@ static func target_at(root: Node, path: String) -> Dictionary:
353
369
  var standing: Dictionary = node_at(root, path)
354
370
  if standing.has("message"):
355
371
  return standing
356
- return {"object": standing["node"], "node": standing["node"]}
372
+ return { "object": standing["node"], "node": standing["node"] }
357
373
 
358
374
 
359
375
  ## The script [param path] names for a call of one of its static functions, as [method target_at]
@@ -379,7 +395,7 @@ static func class_at(root: Node, path: String) -> Dictionary:
379
395
  "type": "error",
380
396
  "message": "No script is at %s to call a static function of." % script_path,
381
397
  }
382
- return {"object": loaded, "node": root}
398
+ return { "object": loaded, "node": root }
383
399
 
384
400
 
385
401
  ## Whether two values can be compared without the comparison itself failing.
@@ -424,7 +440,8 @@ static func inexact(given: Variant, type: int) -> String:
424
440
  return GdhSerialisation.inexact(given, type)
425
441
 
426
442
 
427
- ## What a refusal of [param value] where a [param type] goes ends with: see [method GdhShapes.remedy].
443
+ ## What a refusal of [param value] where a [param type] goes ends with: see
444
+ ## [method GdhShapes.remedy].
428
445
  static func remedy(value: Variant, type: int) -> String:
429
446
  return GdhShapes.remedy(value, type)
430
447
 
@@ -444,8 +461,8 @@ func parameter_type(object: Object, method: String, index: int) -> int:
444
461
 
445
462
 
446
463
  ## The values of the enum argument [param index] of [param method] declares, by name, as
447
- ## `{"enum": "Mood", "values": {...}}`, or {} when it declares none. The engine gives such an argument
448
- ## the type int and the enum's name, as res://main.gd.Mood or Node.ProcessMode.
464
+ ## `{"enum": "Mood", "values": {...}}`, or {} when it declares none. The engine gives such an
465
+ ## argument the type int and the enum's name, as res://main.gd.Mood or Node.ProcessMode.
449
466
  func parameter_enum(object: Object, method: String, index: int) -> Dictionary:
450
467
  for entry: Dictionary in methods_of(object):
451
468
  if entry.get("name", "") != method:
@@ -463,12 +480,12 @@ func parameter_enum(object: Object, method: String, index: int) -> Dictionary:
463
480
  values = _enum_along(object if object is Script else object.get_script(), enum_name)
464
481
  if values.is_empty():
465
482
  return {}
466
- return {"enum": enum_name, "values": values}
483
+ return { "enum": enum_name, "values": values }
467
484
  return {}
468
485
 
469
486
 
470
- ## The enum [param named] declared by [param script] or a script it extends, or {}. A script built in
471
- ## a scene or made at run time names its enums by an id nothing loads, gdscript://-92233….gd.Mood
487
+ ## The enum [param named] declared by [param script] or a script it extends, or {}. A script built
488
+ ## in a scene or made at run time names its enums by an id nothing loads, gdscript://-92233….gd.Mood
472
489
  ## measured on 4.7.2, and a method of the object called declares its enums along this chain.
473
490
  static func _enum_along(script: Variant, named: String) -> Dictionary:
474
491
  if not script is Script:
@@ -506,12 +523,12 @@ func parameter_class(object: Object, method: String, index: int) -> String:
506
523
  return ""
507
524
 
508
525
 
509
- ## What the slot [param named] on [param holder] declares it holds, as `{"type": int, "class":
510
- ## String, "script": Script or null, "declared": Dictionary}`: a property's declaration, or the
511
- ## element type of a typed list or the value type of a typed map. TYPE_NIL when nothing is declared,
512
- ## which is also what a property declared as Variant or left untyped reads as: either way it takes
513
- ## anything. declared is the property's entry in the property list, which carries its enum or
514
- ## range, and empty for anything that is not a property.
526
+ ## What the slot [param named] on [param holder] declares it holds, as
527
+ ## `{"type": int, "class": String, "script": Script or null, "declared": Dictionary}`: a property's
528
+ ## declaration, or the element type of a typed list or the value type of a typed map. TYPE_NIL when
529
+ ## nothing is declared, which is also what a property declared as Variant or left untyped reads as:
530
+ ## either way it takes anything. declared is the property's entry in the property list, which
531
+ ## carries its enum or range, and empty for anything that is not a property.
515
532
  ##
516
533
  ## Asked rather than read off the value in the slot, because an object slot can be empty: a
517
534
  ## property typed `Gear` holding null reads as TYPE_NIL, and anything written into it passed the
@@ -525,7 +542,7 @@ static func slot_declared(holder: Variant, named: String) -> Dictionary:
525
542
  # form's an integer, a rectangle's size a vector of the same form.
526
543
  if named in GdhSerialisation.components_of(holder):
527
544
  var component: Variant = holder[named]
528
- return {"type": typeof(component), "class": "", "script": null, "declared": {}}
545
+ return { "type": typeof(component), "class": "", "script": null, "declared": {} }
529
546
  if holder is Array:
530
547
  var items: Array = holder
531
548
  if items.is_typed():
@@ -540,7 +557,8 @@ static func slot_declared(holder: Variant, named: String) -> Dictionary:
540
557
  if map.is_typed_value():
541
558
  return {
542
559
  "type": map.get_typed_value_builtin(),
543
- "class": _typed_class(map.get_typed_value_script(), map.get_typed_value_class_name()),
560
+ "class":
561
+ _typed_class(map.get_typed_value_script(), map.get_typed_value_class_name()),
544
562
  "script": _script_or_null(map.get_typed_value_script()),
545
563
  "declared": {},
546
564
  }
@@ -554,7 +572,7 @@ static func slot_declared(holder: Variant, named: String) -> Dictionary:
554
572
  "script": null,
555
573
  "declared": entry,
556
574
  }
557
- return {"type": TYPE_NIL, "class": "", "script": null, "declared": {}}
575
+ return { "type": TYPE_NIL, "class": "", "script": null, "declared": {} }
558
576
 
559
577
 
560
578
  static func _script_or_null(typed: Variant) -> Script:
@@ -574,10 +592,10 @@ static func _typed_class(script: Variant, engine_class: StringName) -> String:
574
592
  ## Whether [param object] is a [param declared]: an engine class, or a script class by its global
575
593
  ## name anywhere along the script's inheritance.
576
594
  ##
577
- ## Against [param declared_script] itself when there is one. A script with no global name is named by
578
- ## the engine class it extends, so an object of that class with another script, or none, passes the
579
- ## name, and a typed list built with it drops the element: measured on 4.7.2, an Array[Walker] given
580
- ## a plain Node3D comes out empty, the engine's errors going to the game's output alone.
595
+ ## Against [param declared_script] itself when there is one. A script with no global name is named
596
+ ## by the engine class it extends, so an object of that class with another script, or none, passes
597
+ ## the name, and a typed list built with it drops the element: measured on 4.7.2, an Array[Walker]
598
+ ## given a plain Node3D comes out empty, the engine's errors going to the game's output alone.
581
599
  static func is_a(object: Object, declared: String, declared_script: Script = null) -> bool:
582
600
  if declared_script != null:
583
601
  var own: Variant = object.get_script()
@@ -667,7 +685,13 @@ func parameter_container(object: Object, method: String, index: int) -> Variant:
667
685
  var value_builtin: int = entry_type["builtin"]
668
686
  var value_class: StringName = entry_type["class"]
669
687
  return Dictionary(
670
- {}, key_builtin, key_class, key["script"], value_builtin, value_class, entry_type["script"]
688
+ {},
689
+ key_builtin,
690
+ key_class,
691
+ key["script"],
692
+ value_builtin,
693
+ value_class,
694
+ entry_type["script"]
671
695
  )
672
696
  return null
673
697
  return null
@@ -679,15 +703,17 @@ func parameter_container(object: Object, method: String, index: int) -> Variant:
679
703
  static func _element_type(named: String) -> Dictionary:
680
704
  for type: int in TYPE_MAX:
681
705
  if type != TYPE_OBJECT and type_string(type) == named:
682
- return {"builtin": type, "class": &"", "script": null}
706
+ return { "builtin": type, "class": &"", "script": null }
683
707
  if ClassDB.class_exists(named):
684
- return {"builtin": TYPE_OBJECT, "class": StringName(named), "script": null}
708
+ return { "builtin": TYPE_OBJECT, "class": StringName(named), "script": null }
685
709
  for global: Dictionary in ProjectSettings.get_global_class_list():
686
710
  if str(global.get("class", "")) == named:
687
711
  var script: Script = load(str(global.get("path", "")))
688
712
  if script == null:
689
713
  return {}
690
- return {"builtin": TYPE_OBJECT, "class": script.get_instance_base_type(), "script": script}
714
+ return {
715
+ "builtin": TYPE_OBJECT, "class": script.get_instance_base_type(), "script": script,
716
+ }
691
717
  return {}
692
718
 
693
719
 
@@ -708,7 +734,7 @@ func typed_like(given: Variant, like: Variant, resolve: Callable) -> Dictionary:
708
734
  if like is Array and given is Array:
709
735
  var template: Array = like
710
736
  if not template.is_typed():
711
- return {"value": given}
737
+ return { "value": given }
712
738
  var items: Array = given
713
739
  var built: Array = []
714
740
  for index: int in items.size():
@@ -720,18 +746,21 @@ func typed_like(given: Variant, like: Variant, resolve: Callable) -> Dictionary:
720
746
  resolve
721
747
  )
722
748
  if element.has("message"):
723
- return {"message": "element %d %s" % [index, element["message"]]}
749
+ return { "message": "element %d %s" % [index, element["message"]] }
724
750
  built.append(element["value"])
725
751
  var typed: Array = Array(
726
- built, template.get_typed_builtin(), template.get_typed_class_name(), template.get_typed_script()
752
+ built,
753
+ template.get_typed_builtin(),
754
+ template.get_typed_class_name(),
755
+ template.get_typed_script()
727
756
  )
728
757
  if typed.size() != built.size():
729
- return {"message": "the engine would not take its elements as what the list holds."}
730
- return {"value": typed}
758
+ return { "message": "the engine would not take its elements as what the list holds." }
759
+ return { "value": typed }
731
760
  if like is Dictionary and given is Dictionary:
732
761
  var map_like: Dictionary = like
733
762
  if not map_like.is_typed():
734
- return {"value": given}
763
+ return { "value": given }
735
764
  var entries: Dictionary = given
736
765
  var rebuilt: Dictionary = {}
737
766
  for key: Variant in entries:
@@ -743,16 +772,18 @@ func typed_like(given: Variant, like: Variant, resolve: Callable) -> Dictionary:
743
772
  resolve
744
773
  )
745
774
  if key_fitted.has("message"):
746
- return {"message": "key %s %s" % [str(key), key_fitted["message"]]}
775
+ return { "message": "key %s %s" % [str(key), key_fitted["message"]] }
747
776
  var value_fitted: Dictionary = _element(
748
777
  entries[key],
749
778
  map_like.get_typed_value_builtin(),
750
- _typed_class(map_like.get_typed_value_script(), map_like.get_typed_value_class_name()),
779
+ _typed_class(
780
+ map_like.get_typed_value_script(), map_like.get_typed_value_class_name()
781
+ ),
751
782
  _script_or_null(map_like.get_typed_value_script()),
752
783
  resolve
753
784
  )
754
785
  if value_fitted.has("message"):
755
- return {"message": "the value under %s %s" % [str(key), value_fitted["message"]]}
786
+ return { "message": "the value under %s %s" % [str(key), value_fitted["message"]] }
756
787
  rebuilt[key_fitted["value"]] = value_fitted["value"]
757
788
  var typed_map: Dictionary = Dictionary(
758
789
  rebuilt,
@@ -764,9 +795,9 @@ func typed_like(given: Variant, like: Variant, resolve: Callable) -> Dictionary:
764
795
  map_like.get_typed_value_script()
765
796
  )
766
797
  if typed_map.size() != rebuilt.size():
767
- return {"message": "the engine would not take its entries as what the map holds."}
768
- return {"value": typed_map}
769
- return {"value": given}
798
+ return { "message": "the engine would not take its entries as what the map holds." }
799
+ return { "value": typed_map }
800
+ return { "value": given }
770
801
 
771
802
 
772
803
  ## One element fitted to a container's element type, as `{"value"}` or `{"message"}` saying what it
@@ -775,14 +806,16 @@ func typed_like(given: Variant, like: Variant, resolve: Callable) -> Dictionary:
775
806
  ##
776
807
  ## An object element given as a record goes to [param resolve] as a path would, which says how an
777
808
  ## object is named, rather than being refused as a map that cannot become the class.
778
- func _element(item: Variant, builtin: int, declared: String, script: Script, resolve: Callable) -> Dictionary:
809
+ func _element(
810
+ item: Variant, builtin: int, declared: String, script: Script, resolve: Callable
811
+ ) -> Dictionary:
779
812
  if builtin == TYPE_NIL:
780
- return {"value": item}
813
+ return { "value": item }
781
814
  if builtin == TYPE_OBJECT and (item is String or item is Dictionary):
782
815
  var named: Dictionary = resolve.call(item, declared, script)
783
816
  if named.has("message"):
784
- return {"message": str(named["message"]) + "."}
785
- return {"value": named["object"]}
817
+ return { "message": str(named["message"]) + "." }
818
+ return { "value": named["object"] }
786
819
  # Fitted alone, 4.5 into an Array[int] went in as 4, as a single value is refused for.
787
820
  if cuts(item, builtin):
788
821
  return {
@@ -790,18 +823,20 @@ func _element(item: Variant, builtin: int, declared: String, script: Script, res
790
823
  (
791
824
  "is %s, which %s cannot hold without changing it."
792
825
  % [JSON.stringify(serialize(item), "", false), cut_by(builtin)]
793
- )
826
+ ),
794
827
  }
795
828
  var rounded: String = inexact(item, builtin)
796
829
  if not rounded.is_empty():
797
- return {"message": "is too large to be sure of: %s." % rounded}
830
+ return { "message": "is too large to be sure of: %s." % rounded }
798
831
  var fitted_item: Variant = fitted(item, builtin)
799
832
  if not acceptable(fitted_item, builtin):
800
- # The value as it was sent rather than its engine type: JSON numbers arrive as floats, so a 7
801
- # the caller wrote was named "float".
833
+ # The value as it was sent rather than its engine type: JSON numbers arrive as floats, so a
834
+ # 7 the caller wrote was named "float".
802
835
  var wanted: String = type_string(builtin)
803
836
  if builtin == TYPE_OBJECT:
804
837
  wanted = declared if script == null else script_named(script)
805
838
  var sent: String = JSON.stringify(serialize(item), "", false)
806
- return {"message": "is %s, which cannot become %s.%s" % [sent, wanted, remedy(item, builtin)]}
807
- return {"value": fitted_item}
839
+ return {
840
+ "message": "is %s, which cannot become %s.%s" % [sent, wanted, remedy(item, builtin)],
841
+ }
842
+ return { "value": fitted_item }