gdharness 1.3.42 → 1.3.44
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.
- package/build/cli.js +383 -243
- package/build/godot/addons/auto_reload/auto_reload.gd +18 -19
- package/build/godot/addons/gdharness_editor/animation_reads.gd +55 -33
- package/build/godot/addons/gdharness_editor/bridge_client.gd +53 -58
- package/build/godot/addons/gdharness_editor/declared_values.gd +68 -32
- package/build/godot/addons/gdharness_editor/file_reads.gd +83 -42
- package/build/godot/addons/gdharness_editor/file_walk.gd +12 -5
- package/build/godot/addons/gdharness_editor/headless_check.gd +68 -44
- package/build/godot/addons/gdharness_editor/plugin.gd +2 -3
- package/build/godot/addons/gdharness_editor/property_paths.gd +22 -12
- package/build/godot/addons/gdharness_editor/property_values.gd +143 -78
- package/build/godot/addons/gdharness_editor/reading.gd +51 -17
- package/build/godot/addons/gdharness_editor/same_values.gd +4 -4
- package/build/godot/addons/gdharness_editor/scene_file.gd +127 -80
- package/build/godot/addons/gdharness_editor/scene_uids.gd +12 -6
- package/build/godot/addons/gdharness_editor/serialisation.gd +75 -51
- package/build/godot/addons/gdharness_editor/setting_reads.gd +7 -6
- package/build/godot/addons/gdharness_editor/tool_executor.gd +3 -6
- package/build/godot/addons/gdharness_editor/tools/animation_states.gd +37 -27
- package/build/godot/addons/gdharness_editor/tools/animation_tools.gd +79 -49
- package/build/godot/addons/gdharness_editor/tools/animation_tracks.gd +70 -40
- package/build/godot/addons/gdharness_editor/tools/class_tools.gd +65 -42
- package/build/godot/addons/gdharness_editor/tools/filesystem_tools.gd +24 -22
- package/build/godot/addons/gdharness_editor/tools/navigation_bake.gd +49 -29
- package/build/godot/addons/gdharness_editor/tools/play_tools.gd +26 -21
- package/build/godot/addons/gdharness_editor/tools/profile_tools.gd +40 -40
- package/build/godot/addons/gdharness_editor/tools/resource_tools.gd +166 -107
- package/build/godot/addons/gdharness_editor/tools/scene_groups.gd +16 -9
- package/build/godot/addons/gdharness_editor/tools/scene_kin.gd +68 -41
- package/build/godot/addons/gdharness_editor/tools/scene_paths.gd +35 -20
- package/build/godot/addons/gdharness_editor/tools/scene_placing.gd +28 -13
- package/build/godot/addons/gdharness_editor/tools/scene_sharing.gd +12 -5
- package/build/godot/addons/gdharness_editor/tools/scene_tools.gd +113 -67
- package/build/godot/addons/gdharness_editor/tools/script_paths.gd +20 -8
- package/build/godot/addons/gdharness_editor/tools/settings_tools.gd +11 -8
- package/build/godot/addons/gdharness_editor/tools/signal_tools.gd +47 -34
- package/build/godot/addons/gdharness_editor/tools/tileset_tools.gd +77 -50
- package/build/godot/addons/gdharness_editor/value_shapes.gd +5 -6
- package/build/godot/addons/gdharness_runtime/call_errors.gd +1 -2
- package/build/godot/addons/gdharness_runtime/declared_values.gd +68 -32
- package/build/godot/addons/gdharness_runtime/error_report.gd +1 -2
- package/build/godot/addons/gdharness_runtime/reading.gd +51 -17
- package/build/godot/addons/gdharness_runtime/runtime_accessibility.gd +84 -63
- package/build/godot/addons/gdharness_runtime/runtime_autoload.gd +149 -147
- package/build/godot/addons/gdharness_runtime/runtime_capture.gd +64 -42
- package/build/godot/addons/gdharness_runtime/runtime_changes.gd +184 -122
- package/build/godot/addons/gdharness_runtime/runtime_frames.gd +2 -2
- package/build/godot/addons/gdharness_runtime/runtime_hover.gd +24 -20
- package/build/godot/addons/gdharness_runtime/runtime_input.gd +134 -92
- package/build/godot/addons/gdharness_runtime/runtime_items.gd +29 -13
- package/build/godot/addons/gdharness_runtime/runtime_menus.gd +0 -1
- package/build/godot/addons/gdharness_runtime/runtime_mouse.gd +34 -17
- package/build/godot/addons/gdharness_runtime/runtime_pad.gd +17 -13
- package/build/godot/addons/gdharness_runtime/runtime_paths.gd +84 -46
- package/build/godot/addons/gdharness_runtime/runtime_queries.gd +117 -79
- package/build/godot/addons/gdharness_runtime/runtime_says.gd +14 -17
- package/build/godot/addons/gdharness_runtime/runtime_screen.gd +23 -16
- package/build/godot/addons/gdharness_runtime/runtime_targets.gd +117 -66
- package/build/godot/addons/gdharness_runtime/runtime_touch.gd +15 -15
- package/build/godot/addons/gdharness_runtime/runtime_typing.gd +44 -27
- package/build/godot/addons/gdharness_runtime/runtime_values.gd +108 -73
- package/build/godot/addons/gdharness_runtime/runtime_waits.gd +111 -84
- package/build/godot/addons/gdharness_runtime/runtime_words.gd +10 -7
- package/build/godot/addons/gdharness_runtime/serialisation.gd +75 -51
- package/build/godot/addons/gdharness_runtime/value_shapes.gd +5 -6
- package/build/godot/addons/gdharness_tests/bench.gd +4 -5
- package/build/godot/addons/gdharness_tests/event.gd +10 -5
- package/build/godot/addons/gdharness_tests/share.gd +38 -18
- package/build/godot/addons/gdharness_tests/suites.gd +3 -3
- package/build/godot/addons/gdharness_tests/wait.gd +3 -2
- package/build/godot/loader/loader.gd +9 -9
- package/build/godot/operations/animation_reads.gd +55 -33
- package/build/godot/operations/audio_buses.gd +48 -19
- package/build/godot/operations/class_cache.gd +16 -11
- package/build/godot/operations/classdb_queries.gd +89 -44
- package/build/godot/operations/declared_values.gd +68 -32
- package/build/godot/operations/dependencies.gd +190 -109
- package/build/godot/operations/editor_tools.gd +10 -10
- package/build/godot/operations/export_presets.gd +100 -54
- package/build/godot/operations/file_reads.gd +83 -42
- package/build/godot/operations/file_walk.gd +12 -5
- package/build/godot/operations/gdscript_analysis.gd +86 -65
- package/build/godot/operations/gdscript_authoring.gd +83 -36
- package/build/godot/operations/godot_operations.gd +17 -11
- package/build/godot/operations/import_pipeline.gd +110 -59
- package/build/godot/operations/input_actions.gd +62 -39
- package/build/godot/operations/patterns.gd +3 -1
- package/build/godot/operations/plugins.gd +36 -16
- package/build/godot/operations/project_config.gd +61 -32
- package/build/godot/operations/project_diagnostics.gd +24 -11
- package/build/godot/operations/project_file.gd +16 -16
- package/build/godot/operations/project_validation.gd +71 -44
- package/build/godot/operations/property_paths.gd +22 -12
- package/build/godot/operations/property_values.gd +143 -78
- package/build/godot/operations/reading.gd +51 -17
- package/build/godot/operations/rename_checks.gd +2 -2
- package/build/godot/operations/resource_files.gd +11 -9
- package/build/godot/operations/same_values.gd +4 -4
- package/build/godot/operations/scene_connections.gd +27 -13
- package/build/godot/operations/script_check.gd +52 -49
- package/build/godot/operations/serialisation.gd +75 -51
- package/build/godot/operations/setting_reads.gd +7 -6
- package/build/godot/operations/value_shapes.gd +5 -6
- package/build/godot/tests/listed.gd +321 -268
- package/build/keeper.js +43 -43
- package/package.json +1 -1
|
@@ -124,7 +124,8 @@ static func json_or_null(text: String) -> Variant:
|
|
|
124
124
|
## [param said], the refusal for [param node_path] found nowhere in a scene whose root is called
|
|
125
125
|
## [param root_name], with how paths are read when the path starts with that name and the root has
|
|
126
126
|
## no child called that. Paths go from the root, so its own name there names a child of it, and a
|
|
127
|
-
## caller who read the root as Main in a tree wrote Main/Body and was told only that nothing is
|
|
127
|
+
## caller who read the root as Main in a tree wrote Main/Body and was told only that nothing is
|
|
128
|
+
## there.
|
|
128
129
|
static func from_the_root(said: String, node_path: String, root_name: String) -> String:
|
|
129
130
|
var first: String = node_path.get_slice("/", 0)
|
|
130
131
|
if root_name.is_empty() or first != root_name:
|
|
@@ -141,7 +142,11 @@ static func from_the_root(said: String, node_path: String, root_name: String) ->
|
|
|
141
142
|
## is empty; the name below it that is missing; and [param children], the names that node has, as
|
|
142
143
|
## after a node was moved or renamed. Names up to [constant NAMED_CHILDREN] of them.
|
|
143
144
|
static func missing_below(
|
|
144
|
-
said: String,
|
|
145
|
+
said: String,
|
|
146
|
+
root_name: String,
|
|
147
|
+
reached: PackedStringArray,
|
|
148
|
+
missing: String,
|
|
149
|
+
children: PackedStringArray
|
|
145
150
|
) -> String:
|
|
146
151
|
var shown: String = ", ".join(children.slice(0, NAMED_CHILDREN))
|
|
147
152
|
if children.size() > NAMED_CHILDREN:
|
|
@@ -167,9 +172,18 @@ static func not_of_kind(
|
|
|
167
172
|
) -> String:
|
|
168
173
|
var told: String = said + ("" if said.ends_with(".") else ".")
|
|
169
174
|
if not found.is_empty():
|
|
170
|
-
told +=
|
|
175
|
+
told += (
|
|
176
|
+
' The node at "%s" is %s, not %s.'
|
|
177
|
+
% [node_path, with_article(found), with_article(kind)]
|
|
178
|
+
)
|
|
171
179
|
if holders.is_empty():
|
|
172
|
-
return
|
|
180
|
+
return (
|
|
181
|
+
told
|
|
182
|
+
+ (
|
|
183
|
+
" The scene holds no %s; scene_node add with nodeType %s puts one in it."
|
|
184
|
+
% [kind, kind]
|
|
185
|
+
)
|
|
186
|
+
)
|
|
173
187
|
var quoted: PackedStringArray = []
|
|
174
188
|
for holder: String in holders.slice(0, NAMED_CHILDREN):
|
|
175
189
|
var _quoted: bool = quoted.append('"%s"' % holder)
|
|
@@ -209,7 +223,10 @@ static func offered(said: String, word: String, names: Array) -> String:
|
|
|
209
223
|
var close: PackedStringArray = nearest(word, every)
|
|
210
224
|
if close.is_empty():
|
|
211
225
|
return "%s; it has %s" % [said, ", ".join(every)]
|
|
212
|
-
return
|
|
226
|
+
return (
|
|
227
|
+
"%s; the nearest it has %s %s"
|
|
228
|
+
% [said, "is" if close.size() == 1 else "are", ", ".join(close)]
|
|
229
|
+
)
|
|
213
230
|
|
|
214
231
|
|
|
215
232
|
## [param said], the refusal for [param property], which [param target] does not declare, with the
|
|
@@ -233,14 +250,20 @@ static func near_property(said: String, target: Object, property: String) -> Str
|
|
|
233
250
|
scripted.append(str(declared.get("name", "")))
|
|
234
251
|
var close: PackedStringArray = nearest(property, PackedStringArray(names))
|
|
235
252
|
if not close.is_empty():
|
|
236
|
-
return
|
|
237
|
-
|
|
238
|
-
|
|
253
|
+
return (
|
|
254
|
+
"%s; the nearest it has %s %s"
|
|
255
|
+
% [said, "is" if close.size() == 1 else "are", ", ".join(close)]
|
|
256
|
+
)
|
|
257
|
+
# With a script that declares nothing readable, as one that does not compile, the name is
|
|
258
|
+
# likelier the script's than the class's, so the class's list would point the wrong way.
|
|
239
259
|
if scripted.is_empty() and target.get_script() != null:
|
|
240
260
|
return said
|
|
241
261
|
if scripted.is_empty():
|
|
242
262
|
return (
|
|
243
|
-
|
|
263
|
+
(
|
|
264
|
+
"%s; editor_classes info with className %s and includeInherited true lists the "
|
|
265
|
+
+ "ones it has"
|
|
266
|
+
)
|
|
244
267
|
% [said, target.get_class()]
|
|
245
268
|
)
|
|
246
269
|
scripted.sort()
|
|
@@ -264,11 +287,13 @@ static func _list_called(target: Object, count: Dictionary, property: String) ->
|
|
|
264
287
|
fields = _fields_at(fresh, first)
|
|
265
288
|
if not fresh is RefCounted:
|
|
266
289
|
fresh.free()
|
|
267
|
-
var each: String =
|
|
290
|
+
var each: String = (
|
|
291
|
+
"each one's fields" if fields.is_empty() else "each one's %s" % ", ".join(fields)
|
|
292
|
+
)
|
|
268
293
|
return (
|
|
269
294
|
(
|
|
270
|
-
"it keeps its %s as %s, how many there are, and %s under %s for the first, %s for the
|
|
271
|
-
+ "give %s before the fields of the entries it makes"
|
|
295
|
+
"it keeps its %s as %s, how many there are, and %s under %s for the first, %s for the "
|
|
296
|
+
+ "second and so on: give %s before the fields of the entries it makes"
|
|
272
297
|
)
|
|
273
298
|
% [parts[0].to_lower(), counted, each, first, parts[1] + "1/", counted]
|
|
274
299
|
)
|
|
@@ -287,16 +312,25 @@ static func _bare(word: String) -> String:
|
|
|
287
312
|
return word.to_lower().replace("_", "").replace(" ", "")
|
|
288
313
|
|
|
289
314
|
|
|
290
|
-
## The signals [param object] has that a caller can connect, its own class's first:
|
|
291
|
-
##
|
|
292
|
-
##
|
|
315
|
+
## The signals [param object] has that a caller can connect, its own class's first: its script's,
|
|
316
|
+
## as declared, then the engine's from the class down to Object. The engine lists its own from
|
|
317
|
+
## Object down, which puts a Button's pressed after thirty a Control has, and its script's ahead of
|
|
318
|
+
## those, so reversing the whole list put a game's own two signals after twenty-four of the
|
|
319
|
+
## engine's. Names starting with an underscore are the engine's own.
|
|
293
320
|
static func signals_of(object: Object) -> Array:
|
|
321
|
+
var declared: Array = []
|
|
322
|
+
var script: Script = object.get_script()
|
|
323
|
+
if script != null:
|
|
324
|
+
for entry: Dictionary in script.get_script_signal_list():
|
|
325
|
+
var name: String = str(entry["name"])
|
|
326
|
+
if not name.begins_with("_") and not name in declared:
|
|
327
|
+
declared.append(name)
|
|
294
328
|
var names: Array = []
|
|
295
329
|
for entry: Dictionary in object.get_signal_list():
|
|
296
330
|
var name: String = str(entry["name"])
|
|
297
|
-
if not name.begins_with("_"):
|
|
331
|
+
if not name.begins_with("_") and not name in declared:
|
|
298
332
|
names.push_front(name)
|
|
299
|
-
return names
|
|
333
|
+
return declared + names
|
|
300
334
|
|
|
301
335
|
|
|
302
336
|
## [param word] after the article it takes, "an AnimationTree" or "a Node2D".
|
|
@@ -30,12 +30,12 @@ func names_taken(params: Dictionary) -> Dictionary:
|
|
|
30
30
|
as_what.append("a built-in type")
|
|
31
31
|
if singletons.has(name):
|
|
32
32
|
as_what.append("an engine singleton")
|
|
33
|
-
var entry: Dictionary = {"as": as_what, "declaredBy": null}
|
|
33
|
+
var entry: Dictionary = { "as": as_what, "declaredBy": null }
|
|
34
34
|
var declared_by: String = _declared_in_chain(base, name)
|
|
35
35
|
if not declared_by.is_empty():
|
|
36
36
|
entry["declaredBy"] = declared_by
|
|
37
37
|
taken[name] = entry
|
|
38
|
-
return {"taken": taken}
|
|
38
|
+
return { "taken": taken }
|
|
39
39
|
|
|
40
40
|
|
|
41
41
|
# The native class from [param base] upwards that declares [param name] as a method, property,
|
|
@@ -3,7 +3,6 @@ extends RefCounted
|
|
|
3
3
|
const GdhFileWalk = preload("file_walk.gd")
|
|
4
4
|
const GdhLog = preload("logger.gd")
|
|
5
5
|
const GdhPatterns = preload("patterns.gd")
|
|
6
|
-
|
|
7
6
|
## Where the engine keeps a file's UID, by what kind of file it is. Measured on 4.7.2: a script or
|
|
8
7
|
## shader has a `.uid` file beside it, an imported file has it in its `.import`, and a text scene or
|
|
9
8
|
## resource has it in its own header. `ResourceLoader.get_resource_uid` answers the first two in a
|
|
@@ -34,7 +33,7 @@ func get_uid(params: Dictionary) -> Dictionary:
|
|
|
34
33
|
GdhFileWalk.new().with_nearest_files("File does not exist: " + file_path, file_path)
|
|
35
34
|
)
|
|
36
35
|
|
|
37
|
-
var answer: Dictionary = {"file": file_path, "absolute_path": absolute_path}
|
|
36
|
+
var answer: Dictionary = { "file": file_path, "absolute_path": absolute_path }
|
|
38
37
|
var found: Dictionary = uid_of(file_path)
|
|
39
38
|
if found.is_empty():
|
|
40
39
|
answer["exists"] = false
|
|
@@ -51,12 +50,12 @@ static func uid_of(file_path: String) -> Dictionary:
|
|
|
51
50
|
if FileAccess.file_exists(sidecar):
|
|
52
51
|
var text: String = FileAccess.get_file_as_string(sidecar).strip_edges()
|
|
53
52
|
if not text.is_empty():
|
|
54
|
-
return {"uid": text, "from": sidecar}
|
|
53
|
+
return { "uid": text, "from": sidecar }
|
|
55
54
|
var import_file: String = file_path + ".import"
|
|
56
55
|
if FileAccess.file_exists(import_file):
|
|
57
56
|
var config: ConfigFile = ConfigFile.new()
|
|
58
57
|
if config.load(import_file) == OK and config.has_section_key("remap", "uid"):
|
|
59
|
-
return {"uid": str(config.get_value("remap", "uid")), "from": import_file}
|
|
58
|
+
return { "uid": str(config.get_value("remap", "uid")), "from": import_file }
|
|
60
59
|
if file_path.get_extension().to_lower() in TEXT_RESOURCE_KINDS:
|
|
61
60
|
var file: FileAccess = FileAccess.open(file_path, FileAccess.READ)
|
|
62
61
|
if file != null:
|
|
@@ -64,10 +63,10 @@ static func uid_of(file_path: String) -> Dictionary:
|
|
|
64
63
|
file.close()
|
|
65
64
|
var matched: RegExMatch = GdhPatterns.compiled('\\buid="(uid://[^"]+)"').search(header)
|
|
66
65
|
if matched != null:
|
|
67
|
-
return {"uid": matched.get_string(1), "from": "the file's header"}
|
|
66
|
+
return { "uid": matched.get_string(1), "from": "the file's header" }
|
|
68
67
|
var id: int = ResourceLoader.get_resource_uid(file_path)
|
|
69
68
|
if id != ResourceUID.INVALID_ID:
|
|
70
|
-
return {"uid": ResourceUID.id_to_text(id), "from": "the engine"}
|
|
69
|
+
return { "uid": ResourceUID.id_to_text(id), "from": "the engine" }
|
|
71
70
|
return {}
|
|
72
71
|
|
|
73
72
|
|
|
@@ -79,9 +78,12 @@ func _why_none(file_path: String) -> String:
|
|
|
79
78
|
return "No .uid file beside it. refresh_uids writes one for every script and shader."
|
|
80
79
|
if kind in TEXT_RESOURCE_KINDS:
|
|
81
80
|
return (
|
|
82
|
-
"Its header carries no uid. The editor writes one when it saves the file; refresh_uids
|
|
83
|
-
+ " and a headless save does not either."
|
|
81
|
+
"Its header carries no uid. The editor writes one when it saves the file; refresh_uids "
|
|
82
|
+
+ "does not, and a headless save does not either."
|
|
84
83
|
)
|
|
85
84
|
if ResourceLoader.exists(file_path):
|
|
86
85
|
return "The engine keeps no UID for it."
|
|
87
|
-
return
|
|
86
|
+
return (
|
|
87
|
+
"It has not been imported, and the import is what gives it a UID: project_import reimport "
|
|
88
|
+
+ "imports it."
|
|
89
|
+
)
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
@tool
|
|
2
2
|
extends RefCounted
|
|
3
|
-
|
|
4
3
|
## Whether a value read back is the value that was given, as the tools that write properties judge
|
|
5
4
|
## what a write kept and what it changed besides.
|
|
6
5
|
|
|
7
6
|
const GdhRead = preload("reading.gd")
|
|
8
7
|
const GdhSerialisation = preload("serialisation.gd")
|
|
9
|
-
|
|
10
8
|
# The types made of floats, which a read back compares within float precision: a Vector2 property
|
|
11
9
|
# stores 32-bit components, so 0.1 comes back as 0.100000001.
|
|
12
10
|
const FLOAT_SHAPES: Array[int] = [
|
|
@@ -23,7 +21,6 @@ const FLOAT_SHAPES: Array[int] = [
|
|
|
23
21
|
TYPE_AABB,
|
|
24
22
|
TYPE_PROJECTION,
|
|
25
23
|
]
|
|
26
|
-
|
|
27
24
|
const PACKED: Array[int] = [
|
|
28
25
|
TYPE_PACKED_BYTE_ARRAY,
|
|
29
26
|
TYPE_PACKED_INT32_ARRAY,
|
|
@@ -63,7 +60,10 @@ static func same(held: Variant, given: Variant) -> bool:
|
|
|
63
60
|
return held_type == given_type and held == given
|
|
64
61
|
var held_number: float = GdhRead.as_float(held)
|
|
65
62
|
var given_number: float = GdhRead.as_float(given)
|
|
66
|
-
return (
|
|
63
|
+
return (
|
|
64
|
+
(is_nan(held_number) and is_nan(given_number))
|
|
65
|
+
or is_equal_approx(held_number, given_number)
|
|
66
|
+
)
|
|
67
67
|
if GdhSerialisation.TEXTS.has(held_type) and GdhSerialisation.TEXTS.has(given_type):
|
|
68
68
|
return str(held) == str(given)
|
|
69
69
|
if _listed(held_type) and _listed(given_type):
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
extends RefCounted
|
|
2
|
-
|
|
3
2
|
## The signal connections the project's scenes hold that cannot work: a method the node it calls
|
|
4
3
|
## does not have, which fails on every emission, or a signal the node it leaves does not have, which
|
|
5
4
|
## the engine drops as the scene loads. Read from the text of each scene and script, so nothing is
|
|
@@ -13,7 +12,6 @@ extends RefCounted
|
|
|
13
12
|
const GdhDependencies = preload("dependencies.gd")
|
|
14
13
|
const GdhFileWalk = preload("file_walk.gd")
|
|
15
14
|
const GdhLog = preload("logger.gd")
|
|
16
|
-
|
|
17
15
|
const EXT_RESOURCE: String = '^\\[ext_resource [^\\]]*?path="([^"]+)"[^\\]]*? id="([^"]+)"'
|
|
18
16
|
const NODE: String = "^\\[node ([^\\]]*)\\]"
|
|
19
17
|
const CONNECTION: String = "^\\[connection ([^\\]]*)\\]"
|
|
@@ -38,8 +36,8 @@ func _init(p_log: GdhLog) -> void:
|
|
|
38
36
|
_globals = GdhDependencies.new(p_log).classes_declared()
|
|
39
37
|
|
|
40
38
|
|
|
41
|
-
## Every connection that cannot work, as {scene, from, signal, to, method, missing}, where missing
|
|
42
|
-
## "method" or "signal".
|
|
39
|
+
## Every connection that cannot work, as {scene, from, signal, to, method, missing}, where missing
|
|
40
|
+
## is "method" or "signal".
|
|
43
41
|
func broken() -> Array[Dictionary]:
|
|
44
42
|
var found: Array[Dictionary] = []
|
|
45
43
|
for scene: String in _files.find_files_with_extensions("res://", ["tscn"]):
|
|
@@ -76,7 +74,10 @@ static func broken_line(entry: Dictionary) -> String:
|
|
|
76
74
|
% [entry["scene"], entry["from"], entry["signal"], entry["to"], entry["method"]]
|
|
77
75
|
)
|
|
78
76
|
if entry["missing"] == "signal":
|
|
79
|
-
return
|
|
77
|
+
return (
|
|
78
|
+
connected
|
|
79
|
+
+ ", a signal that node does not have, so the engine drops it as the scene loads."
|
|
80
|
+
)
|
|
80
81
|
return connected + ", a method that node does not have, so every emission fails to call it."
|
|
81
82
|
|
|
82
83
|
|
|
@@ -100,11 +101,17 @@ func _nodes_of(content: String, scene: String) -> Dictionary:
|
|
|
100
101
|
var attributes: Dictionary = _attributes(heading.get_string(1))
|
|
101
102
|
var name: String = str(attributes.get("name", ""))
|
|
102
103
|
var parent: Variant = attributes.get("parent")
|
|
103
|
-
current =
|
|
104
|
-
|
|
104
|
+
current = (
|
|
105
|
+
"." if parent == null else (name if parent == "." else "%s/%s" % [parent, name])
|
|
106
|
+
)
|
|
107
|
+
var node: Dictionary = {
|
|
108
|
+
"class": str(attributes.get("type", "")), "script": "", "name": name,
|
|
109
|
+
}
|
|
105
110
|
var instanced: RegExMatch = instance.search(heading.get_string(1))
|
|
106
111
|
if instanced != null:
|
|
107
|
-
var root: Dictionary = _root_of(
|
|
112
|
+
var root: Dictionary = _root_of(
|
|
113
|
+
str(resources.get(instanced.get_string(1), "")), scene
|
|
114
|
+
)
|
|
108
115
|
node = root.duplicate()
|
|
109
116
|
node["name"] = name
|
|
110
117
|
nodes[current] = node
|
|
@@ -118,7 +125,9 @@ func _nodes_of(content: String, scene: String) -> Dictionary:
|
|
|
118
125
|
# A built-in script lives in the scene, where this does not read it, so its node is one
|
|
119
126
|
# nothing here can judge, which a path that is no script file says.
|
|
120
127
|
var external: bool = scripted.get_string(1) == "Ext"
|
|
121
|
-
node["script"] =
|
|
128
|
+
node["script"] = (
|
|
129
|
+
str(resources.get(scripted.get_string(2), "?")) if external else "built-in"
|
|
130
|
+
)
|
|
122
131
|
return nodes
|
|
123
132
|
|
|
124
133
|
|
|
@@ -127,11 +136,16 @@ func _nodes_of(content: String, scene: String) -> Dictionary:
|
|
|
127
136
|
func _root_of(path: String, from: String) -> Dictionary:
|
|
128
137
|
if _roots.has(path):
|
|
129
138
|
return _roots[path]
|
|
130
|
-
_roots[path] = {"class": "", "script": ""}
|
|
131
|
-
if
|
|
139
|
+
_roots[path] = { "class": "", "script": "" }
|
|
140
|
+
if (
|
|
141
|
+
path.is_empty()
|
|
142
|
+
or path == from
|
|
143
|
+
or not path.ends_with(".tscn")
|
|
144
|
+
or not FileAccess.file_exists(path)
|
|
145
|
+
):
|
|
132
146
|
return _roots[path]
|
|
133
147
|
var nodes: Dictionary = _nodes_of(FileAccess.get_file_as_string(path), path)
|
|
134
|
-
_roots[path] = nodes.get(".", {"class": "", "script": ""})
|
|
148
|
+
_roots[path] = nodes.get(".", { "class": "", "script": "" })
|
|
135
149
|
return _roots[path]
|
|
136
150
|
|
|
137
151
|
|
|
@@ -200,7 +214,7 @@ func _script(path: String, seen: Dictionary) -> Dictionary:
|
|
|
200
214
|
methods.merge(inherited_methods)
|
|
201
215
|
signals.merge(inherited_signals)
|
|
202
216
|
engine_class = str(inherited["class"])
|
|
203
|
-
_scripts[path] = {"class": engine_class, "methods": methods, "signals": signals}
|
|
217
|
+
_scripts[path] = { "class": engine_class, "methods": methods, "signals": signals }
|
|
204
218
|
return _scripts[path]
|
|
205
219
|
|
|
206
220
|
|
|
@@ -1,28 +1,25 @@
|
|
|
1
1
|
extends RefCounted
|
|
2
|
-
|
|
3
2
|
## Compiles scripts the way the engine does when it loads them, and answers what it raised.
|
|
4
3
|
##
|
|
5
4
|
## The engine reports a script that does not compile as errors raised from GDScript::reload, each
|
|
6
5
|
## naming the file and line, and they reach a Logger as well as stderr. Measured on 4.7.2: a script
|
|
7
|
-
## whose dependency does not compile reports the dependency's errors at the dependency's path and
|
|
8
|
-
## of its own at line 0, "Compile Error: Failed to compile depended scripts", and is still
|
|
9
|
-
## back as a script that can_instantiate() calls instantiable. Warnings are not among them:
|
|
10
|
-
## sends those only to an editor or a debugger.
|
|
6
|
+
## whose dependency does not compile reports the dependency's errors at the dependency's path and
|
|
7
|
+
## one of its own at line 0, "Compile Error: Failed to compile depended scripts", and is still
|
|
8
|
+
## handed back as a script that can_instantiate() calls instantiable. Warnings are not among them:
|
|
9
|
+
## the engine sends those only to an editor or a debugger.
|
|
11
10
|
##
|
|
12
|
-
## A script that failed stays failed in the engine's script cache, which no ResourceLoader cache
|
|
13
|
-
## reaches, and every script loaded after it that depends on it compiles in silence, reload()
|
|
14
|
-
## So a run ends at the first script that raised anything, and the rest go to a fresh
|
|
11
|
+
## A script that failed stays failed in the engine's script cache, which no ResourceLoader cache
|
|
12
|
+
## mode reaches, and every script loaded after it that depends on it compiles in silence, reload()
|
|
13
|
+
## and all. So a run ends at the first script that raised anything, and the rest go to a fresh
|
|
14
|
+
## engine.
|
|
15
15
|
|
|
16
16
|
const GdhRead = preload("reading.gd")
|
|
17
17
|
const GdhLog = preload("logger.gd")
|
|
18
|
-
|
|
19
18
|
## Where the engine raises a script's compile errors from.
|
|
20
19
|
const RELOAD: String = "GDScript::reload"
|
|
21
|
-
|
|
22
20
|
## What the engine puts on the end of a warning it raised as an error. Kept in step with
|
|
23
21
|
## `RAISED_WARNING` in src/server.ts.
|
|
24
22
|
const RAISED: String = " (Warning treated as error.)"
|
|
25
|
-
|
|
26
23
|
## Where the project's warning levels are, each 0 to ignore, 1 to warn and 2 to raise as an error.
|
|
27
24
|
const WARNING_LEVELS: String = "debug/gdscript/warnings/"
|
|
28
25
|
const WARN: int = 1
|
|
@@ -31,34 +28,6 @@ const ERROR_LEVEL: int = 2
|
|
|
31
28
|
var _log: GdhLog
|
|
32
29
|
|
|
33
30
|
|
|
34
|
-
## Every compile error the engine raises while it is attached, in order.
|
|
35
|
-
class GdhCaught:
|
|
36
|
-
extends Logger
|
|
37
|
-
|
|
38
|
-
var raised: Array[Dictionary] = []
|
|
39
|
-
|
|
40
|
-
func _log_message(_message: String, _error: bool) -> void:
|
|
41
|
-
pass
|
|
42
|
-
|
|
43
|
-
# The engine's own signature for a Logger, eight parameters and not this project's to shape.
|
|
44
|
-
# gdlint:ignore = function-arguments-number
|
|
45
|
-
func _log_error(
|
|
46
|
-
function: String,
|
|
47
|
-
file: String,
|
|
48
|
-
line: int,
|
|
49
|
-
code: String,
|
|
50
|
-
rationale: String,
|
|
51
|
-
_editor_notify: bool,
|
|
52
|
-
_error_type: int,
|
|
53
|
-
_script_backtraces: Array[ScriptBacktrace],
|
|
54
|
-
) -> void:
|
|
55
|
-
if function != RELOAD:
|
|
56
|
-
return
|
|
57
|
-
raised.append(
|
|
58
|
-
{"path": file, "line": line, "message": rationale if not rationale.is_empty() else code}
|
|
59
|
-
)
|
|
60
|
-
|
|
61
|
-
|
|
62
31
|
func _init(p_log: GdhLog) -> void:
|
|
63
32
|
_log = p_log
|
|
64
33
|
|
|
@@ -105,22 +74,24 @@ func check_scripts(params: Dictionary) -> Dictionary:
|
|
|
105
74
|
if not at in others:
|
|
106
75
|
others.append(at)
|
|
107
76
|
continue
|
|
108
|
-
var found: Dictionary = {
|
|
77
|
+
var found: Dictionary = {
|
|
78
|
+
"line": GdhRead.as_int(error["line"]), "message": str(error["message"]),
|
|
79
|
+
}
|
|
109
80
|
if not found in errors:
|
|
110
81
|
errors.append(found)
|
|
111
82
|
if loaded == null and errors.is_empty():
|
|
112
|
-
errors.append({"line": 0, "message": "The engine could not load it as a script."})
|
|
83
|
+
errors.append({ "line": 0, "message": "The engine could not load it as a script." })
|
|
113
84
|
if errors.is_empty() and others.is_empty():
|
|
114
85
|
continue
|
|
115
86
|
if not errors.is_empty():
|
|
116
87
|
failed.append(path)
|
|
117
|
-
var one: Dictionary = {"path": path, "errors": errors}
|
|
88
|
+
var one: Dictionary = { "path": path, "errors": errors }
|
|
118
89
|
if not others.is_empty():
|
|
119
90
|
one["dependencies_with_errors"] = others
|
|
120
91
|
scripts.append(one)
|
|
121
92
|
break
|
|
122
93
|
OS.remove_logger(caught)
|
|
123
|
-
return {"checked": checked, "failed": failed, "scripts": scripts}
|
|
94
|
+
return { "checked": checked, "failed": failed, "scripts": scripts }
|
|
124
95
|
|
|
125
96
|
|
|
126
97
|
## Raises every warning the project sets to warn so that the engine reports it as an error, which is
|
|
@@ -144,9 +115,9 @@ static func raise_warnings() -> void:
|
|
|
144
115
|
|
|
145
116
|
## The warnings of each script in [code]paths[/code], under the levels [method raise_warnings] left:
|
|
146
117
|
## [code]scripts[/code] holds each that has any, with its warnings' lines and the engine's messages
|
|
147
|
-
## as raised. The analyser runs before anything is compiled, so a script whose dependency failed on
|
|
148
|
-
## warning still reports its own, and loading on past a failure loses nothing; only what is raised
|
|
149
|
-
## the script's own path is its, since a dependency is read on its own entry as well.
|
|
118
|
+
## as raised. The analyser runs before anything is compiled, so a script whose dependency failed on
|
|
119
|
+
## a warning still reports its own, and loading on past a failure loses nothing; only what is raised
|
|
120
|
+
## at the script's own path is its, since a dependency is read on its own entry as well.
|
|
150
121
|
func check_warnings(params: Dictionary) -> Dictionary:
|
|
151
122
|
var asked: Array = params.get("paths", [])
|
|
152
123
|
var caught: GdhCaught = GdhCaught.new()
|
|
@@ -163,10 +134,42 @@ func check_warnings(params: Dictionary) -> Dictionary:
|
|
|
163
134
|
var message: String = str(error["message"])
|
|
164
135
|
if str(error["path"]) != path or not message.ends_with(RAISED):
|
|
165
136
|
continue
|
|
166
|
-
var found: Dictionary = {"line": GdhRead.as_int(error["line"]), "message": message}
|
|
137
|
+
var found: Dictionary = { "line": GdhRead.as_int(error["line"]), "message": message }
|
|
167
138
|
if not found in warnings:
|
|
168
139
|
warnings.append(found)
|
|
169
140
|
if not warnings.is_empty():
|
|
170
|
-
scripts.append({"path": path, "warnings": warnings})
|
|
141
|
+
scripts.append({ "path": path, "warnings": warnings })
|
|
171
142
|
OS.remove_logger(caught)
|
|
172
|
-
return {"checked": checked, "scripts": scripts}
|
|
143
|
+
return { "checked": checked, "scripts": scripts }
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
## Every compile error the engine raises while it is attached, in order.
|
|
147
|
+
class GdhCaught:
|
|
148
|
+
extends Logger
|
|
149
|
+
|
|
150
|
+
var raised: Array[Dictionary] = []
|
|
151
|
+
|
|
152
|
+
func _log_message(_message: String, _error: bool) -> void:
|
|
153
|
+
pass
|
|
154
|
+
|
|
155
|
+
# The engine's own signature for a Logger, eight parameters and not this project's to shape.
|
|
156
|
+
# gdstyle:ignore=quality/max-parameters
|
|
157
|
+
func _log_error(
|
|
158
|
+
function: String,
|
|
159
|
+
file: String,
|
|
160
|
+
line: int,
|
|
161
|
+
code: String,
|
|
162
|
+
rationale: String,
|
|
163
|
+
_editor_notify: bool,
|
|
164
|
+
_error_type: int,
|
|
165
|
+
_script_backtraces: Array[ScriptBacktrace],
|
|
166
|
+
) -> void:
|
|
167
|
+
if function != RELOAD:
|
|
168
|
+
return
|
|
169
|
+
raised.append(
|
|
170
|
+
{
|
|
171
|
+
"path": file,
|
|
172
|
+
"line": line,
|
|
173
|
+
"message": rationale if not rationale.is_empty() else code,
|
|
174
|
+
}
|
|
175
|
+
)
|