Json Utility Plugin requires a "Make Pretty String" function

As the Title Describes,

The Json Plugin needs this.

The Plugin itself:
Super handy, easy to use, will use it to store The UserSettings of my Plugin, into the project Directory.

The generated Json File:
Is a One-Line Code.
And it makes it super hard to, maybe, add new Settings via external IDE.

So… a “Make Pretty String” would be helpful, to make a One Liner look Structured and indented:

Beside that: Absolute amazing Thing, to have Json functionality as native Plugin :+1:

cause it bothered me… I refactored the Make Pretty Code from Vishal.

Here it is:

bool UCLASSNAME::PrettyfyJson(const FString FilePath, FText& Message)
{
	FString FileData;		
	if (!FFileHelper::LoadFileToString(FileData, *FilePath))
	{
		Message = FText::FromString("Failed to open File");
		return false;
	}
    
	int32 Tokens = -1;		
	FString OutData;
	for (const TCHAR Ch : FileData)
	{
		if (Ch == '{')
		{
			Tokens++;
			// open braces tabs
			int32 Tabs = Tokens;
			if (Tokens > 0)
				OutData += "\n";
			OutData += FString::ChrN(Tabs, '\t') + "{\n";

			//json key:value tabs
			Tabs = Tokens + 1;			
			OutData += FString::ChrN(Tabs, '\t');
		}
		else if (Ch == ':')
		{
			OutData += " : ";
		}
		else if (Ch == ',')
		{
			OutData += ",\n" + FString::ChrN(Tokens + 1, '\t');
		}
		else if (Ch == '}')
		{
			OutData += "\n" + FString::ChrN(Tokens, '\t') + "}\n";
			Tokens--;
			OutData += FString::ChrN(Tokens + 1, '\t');
		}
		else if(Ch == '[')
		{
			Tokens++;
			// open braces tabs
			int32 Tabs = Tokens;
			if (Tokens > 0)
				OutData += "\n";
			OutData += FString::ChrN(Tabs, '\t') + "[\n";

			//json key:value tabs
			Tabs = Tokens + 1;			
			OutData += FString::ChrN(Tabs, '\t');
		}
		else if (Ch == ']')
			{
				OutData += "\n" + FString::ChrN(Tokens, '\t') + "]\n";
				Tokens--;
				OutData += FString::ChrN(Tokens + 1, '\t');
			}
		else
		{
			if (Ch == '\n' || Ch == '\t')
				continue;
			else
				OutData += Ch;
		}
	}
    
	if (!FFileHelper::SaveStringToFile(OutData, *FilePath))
	{
		Message = FText::FromString("Failed to save File");
		return false;
	}

	Message = FText::FromString("Succeeded Beautification!");
	return true;	
}

Not perfect, but working and more readable.

The JSON utility library already features a “pretty” writer, you just need to implement your own write blueprint function.

You can use this one:

KFJsonUtils.hpp

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "KFJsonUtils.generated.h"

/**
 * 
 */
UCLASS()
class KFPS_API UKFJsonUtils : public UBlueprintFunctionLibrary
{
	GENERATED_BODY()

public:
	/** Creates a file from the provided JsonObject. */
	UFUNCTION(BlueprintCallable, Category="Json", meta = (DisplayName = "KF Save Json to File"))
	static UPARAM(DisplayName="Success") bool KFJsonToFile(const FJsonObjectWrapper& JsonObject, const FFilePath& File, bool bIsPrettyPrint = true);

	/** Creates a Json string from the provided JsonObject. */
	UFUNCTION(BlueprintCallable, Category="Json", meta = (DisplayName = "Get Json String"))
	static UPARAM(DisplayName="Success") bool KFJsonToString(const FJsonObjectWrapper& JsonObject, UPARAM(DisplayName="String") FString& OutJsonString, bool bIsPrettyPrint);

private:
	static bool JsonObjectToStringPretty(const FJsonObjectWrapper& JsonObject, FString& Str);
	static bool JsonObjectToStringCondensed(const FJsonObjectWrapper& JsonObject, FString& Str);
};

KFJsonUtils.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "KFJsonUtils.h"

#include "JsonObjectWrapper.h"

bool UKFJsonUtils::KFJsonToFile(const FJsonObjectWrapper& JsonObject, const FFilePath& File, bool bIsPrettyPrint)
{
	if (!FPaths::DirectoryExists(FPaths::GetPath(File.FilePath)))
	{
		FFrame::KismetExecutionMessage(*FString::Printf(TEXT("Directory not found: %s"), *FPaths::GetPath(File.FilePath)), ELogVerbosity::Error);
		return false;
	}

	if (File.FilePath.IsEmpty())
	{
		FFrame::KismetExecutionMessage(*FString::Printf(TEXT("FileName cannot be empty")), ELogVerbosity::Error);
		return false;
	}

	if (FString JsonString; KFJsonToString(JsonObject, JsonString, bIsPrettyPrint))
	{
		const bool& bResult = FFileHelper::SaveStringToFile(JsonString, *File.FilePath);
		if (!bResult)
		{
			FFrame::KismetExecutionMessage(*FString::Printf(TEXT("Failed to save JSON to file. %s"), *JsonString), ELogVerbosity::Error);
		}

		return bResult;
	}

	return false;
}

bool UKFJsonUtils::KFJsonToString(const FJsonObjectWrapper& JsonObject, FString& OutJsonString, bool bIsPrettyPrint)
{
	if(bIsPrettyPrint)
	{
		if (!JsonObjectToStringPretty(JsonObject, OutJsonString))
		{
			FFrame::KismetExecutionMessage(TEXT("Failed to convert JSON Object to string"), ELogVerbosity::Error);
			return false;
		}
	}
	else
	{
		if (!JsonObjectToStringCondensed(JsonObject, OutJsonString))
		{
			FFrame::KismetExecutionMessage(TEXT("Failed to convert JSON Object to string"), ELogVerbosity::Error);
			return false;
		}
	}

	return true;
}

bool UKFJsonUtils::JsonObjectToStringPretty(const FJsonObjectWrapper& JsonObject, FString& Str)
{
	TSharedRef<TJsonWriter<>> JsonWriter = TJsonWriterFactory<>::Create(&Str, 0);
	TSharedRef<FJsonObject> ptr = MakeShared<FJsonObject>(*JsonObject.JsonObject.Get());
	return FJsonSerializer::Serialize(ptr, JsonWriter, true);
}

bool UKFJsonUtils::JsonObjectToStringCondensed(const FJsonObjectWrapper& JsonObject, FString& Str)
{
	TSharedRef<TJsonWriter<TCHAR, TCondensedJsonPrintPolicy<TCHAR>>> JsonWriter = TJsonWriterFactory<TCHAR, TCondensedJsonPrintPolicy<TCHAR>>::Create(&Str, 0);
	TSharedRef<FJsonObject> ptr = MakeShared<FJsonObject>(*JsonObject.JsonObject.Get());
	return FJsonSerializer::Serialize(ptr, JsonWriter, true);
}