Browse Source

Merge pull request #71390 from reduz/fix-json-as-resource

Fixes to JSON as resource
Rémi Verschelde 2 years ago
parent
commit
2435eef617
3 changed files with 42 additions and 14 deletions
  1. 25 8
      core/io/json.cpp
  2. 6 3
      core/io/json.h
  3. 11 3
      doc/classes/JSON.xml

+ 25 - 8
core/io/json.cpp

@@ -30,6 +30,7 @@
 
 #include "json.h"
 
+#include "core/config/engine.h"
 #include "core/string/print_string.h"
 
 const char *JSON::tk_name[TK_MAX] = {
@@ -506,6 +507,7 @@ Error JSON::_parse_object(Dictionary &object, const char32_t *p_str, int &index,
 
 void JSON::set_data(const Variant &p_data) {
 	data = p_data;
+	text.clear();
 }
 
 Error JSON::_parse_string(const String &p_json, Variant &r_ret, String &r_err_str, int &r_err_line) {
@@ -539,14 +541,21 @@ Error JSON::_parse_string(const String &p_json, Variant &r_ret, String &r_err_st
 	return err;
 }
 
-Error JSON::parse(const String &p_json_string) {
+Error JSON::parse(const String &p_json_string, bool p_keep_text) {
 	Error err = _parse_string(p_json_string, data, err_str, err_line);
 	if (err == Error::OK) {
 		err_line = 0;
 	}
+	if (p_keep_text) {
+		text = p_json_string;
+	}
 	return err;
 }
 
+String JSON::get_parsed_text() const {
+	return text;
+}
+
 String JSON::stringify(const Variant &p_var, const String &p_indent, bool p_sort_keys, bool p_full_precision) {
 	Ref<JSON> jason;
 	jason.instantiate();
@@ -565,10 +574,11 @@ Variant JSON::parse_string(const String &p_json_string) {
 void JSON::_bind_methods() {
 	ClassDB::bind_static_method("JSON", D_METHOD("stringify", "data", "indent", "sort_keys", "full_precision"), &JSON::stringify, DEFVAL(""), DEFVAL(true), DEFVAL(false));
 	ClassDB::bind_static_method("JSON", D_METHOD("parse_string", "json_string"), &JSON::parse_string);
-	ClassDB::bind_method(D_METHOD("parse", "json_string"), &JSON::parse);
+	ClassDB::bind_method(D_METHOD("parse", "json_text", "keep_text"), &JSON::parse, DEFVAL(false));
 
 	ClassDB::bind_method(D_METHOD("get_data"), &JSON::get_data);
 	ClassDB::bind_method(D_METHOD("set_data", "data"), &JSON::set_data);
+	ClassDB::bind_method(D_METHOD("get_parsed_text"), &JSON::get_parsed_text);
 	ClassDB::bind_method(D_METHOD("get_error_line"), &JSON::get_error_line);
 	ClassDB::bind_method(D_METHOD("get_error_message"), &JSON::get_error_message);
 
@@ -592,13 +602,20 @@ Ref<Resource> ResourceFormatLoaderJSON::load(const String &p_path, const String
 	Ref<JSON> json;
 	json.instantiate();
 
-	Error err = json->parse(FileAccess::get_file_as_string(p_path));
+	Error err = json->parse(FileAccess::get_file_as_string(p_path), Engine::get_singleton()->is_editor_hint());
 	if (err != OK) {
-		if (r_error) {
-			*r_error = err;
+		String err_text = "Error parsing JSON file at '" + p_path + "', on line " + itos(json->get_error_line()) + ": " + json->get_error_message();
+
+		if (Engine::get_singleton()->is_editor_hint()) {
+			// If running on editor, still allow opening the JSON so the code editor can edit it.
+			WARN_PRINT(err_text);
+		} else {
+			if (r_error) {
+				*r_error = err;
+			}
+			ERR_PRINT(err_text);
+			return Ref<Resource>();
 		}
-		ERR_PRINT("Error parsing JSON file at '" + p_path + "', on line " + itos(json->get_error_line()) + ": " + json->get_error_message());
-		return Ref<Resource>();
 	}
 
 	if (r_error) {
@@ -628,7 +645,7 @@ Error ResourceFormatSaverJSON::save(const Ref<Resource> &p_resource, const Strin
 	Ref<JSON> json = p_resource;
 	ERR_FAIL_COND_V(json.is_null(), ERR_INVALID_PARAMETER);
 
-	String source = JSON::stringify(json->get_data(), "\t", false, true);
+	String source = json->get_parsed_text().is_empty() ? JSON::stringify(json->get_data(), "\t", false, true) : json->get_parsed_text();
 
 	Error err;
 	Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err);

+ 6 - 3
core/io/json.h

@@ -36,8 +36,8 @@
 #include "core/io/resource_saver.h"
 #include "core/variant/variant.h"
 
-class JSON : public RefCounted {
-	GDCLASS(JSON, RefCounted);
+class JSON : public Resource {
+	GDCLASS(JSON, Resource);
 
 	enum TokenType {
 		TK_CURLY_BRACKET_OPEN,
@@ -65,6 +65,7 @@ class JSON : public RefCounted {
 		Variant value;
 	};
 
+	String text;
 	Variant data;
 	String err_str;
 	int err_line = 0;
@@ -83,7 +84,9 @@ protected:
 	static void _bind_methods();
 
 public:
-	Error parse(const String &p_json_string);
+	Error parse(const String &p_json_string, bool p_keep_text = false);
+	String get_parsed_text() const;
+
 	static String stringify(const Variant &p_var, const String &p_indent = "", bool p_sort_keys = true, bool p_full_precision = false);
 	static Variant parse_string(const String &p_json_string);
 

+ 11 - 3
doc/classes/JSON.xml

@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8" ?>
-<class name="JSON" inherits="RefCounted" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="JSON" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
 	<brief_description>
 		Helper class for creating and parsing JSON data.
 	</brief_description>
@@ -49,13 +49,21 @@
 				Returns an empty string if the last call to [method parse] was successful, or the error message if it failed.
 			</description>
 		</method>
+		<method name="get_parsed_text" qualifiers="const">
+			<return type="String" />
+			<description>
+				Return the text parsed by [method parse] as long as the function is instructed to keep it.
+			</description>
+		</method>
 		<method name="parse">
 			<return type="int" enum="Error" />
-			<param index="0" name="json_string" type="String" />
+			<param index="0" name="json_text" type="String" />
+			<param index="1" name="keep_text" type="bool" default="false" />
 			<description>
-				Attempts to parse the [param json_string] provided.
+				Attempts to parse the [param json_text] provided.
 				Returns an [enum Error]. If the parse was successful, it returns [constant OK] and the result can be retrieved using [member data]. If unsuccessful, use [method get_error_line] and [method get_error_message] for identifying the source of the failure.
 				Non-static variant of [method parse_string], if you want custom error handling.
+				The optional [param keep_text] argument instructs the parser to keep a copy of the original text. This text can be obtained later by using the [method get_parsed_text] function and is used when saving the resource (instead of generating new text from [member data]).
 			</description>
 		</method>
 		<method name="parse_string" qualifiers="static">