diff --git a/source/base/StarAssets.cpp b/source/base/StarAssets.cpp index 422ea22..0b21f5e 100644 --- a/source/base/StarAssets.cpp +++ b/source/base/StarAssets.cpp @@ -678,6 +678,38 @@ ByteArray Assets::read(String const& path) const { throw AssetException(strf("No such asset '{}'", path)); } +Json Assets::checkPatchArray(String const& path, AssetSourcePtr const& source, Json const result, JsonArray const patchData, Maybe const external) const { + auto externalRef = external.value(); + auto newResult = result; + for (auto const patch : patchData) { + switch(patch.type()){ + case Json::Type::Array: // if the patch is an array, go down recursively until we get objects + try { + newResult = checkPatchArray(path, source, newResult, patch.toArray(), externalRef); + } catch (JsonPatchTestFail const& e) { + Logger::debug("Patch test failure from file {} in source: '{}' at '{}'. Caused by: {}", path, source->metadata().value("name", ""), m_assetSourcePaths.getLeft(source), e.what()); + } catch (JsonPatchException const& e) { + Logger::error("Could not apply patch from file {} in source: '{}' at '{}'. Caused by: {}", path, source->metadata().value("name", ""), m_assetSourcePaths.getLeft(source), e.what()); + } + break; + case Json::Type::Object: // if its an object, check for operations, or for if an external file is needed for patches to reference + newResult = JsonPatching::applyOperation(newResult, patch, externalRef); + break; + case Json::Type::String: + try { + externalRef = json(patch.toString()); + } catch (...) { + throw JsonPatchTestFail(strf("Unable to load reference asset: {}", patch.toString())); + } + break; + default: + throw JsonPatchException(strf("Patch data is wrong type: {}", Json::typeName(patch.type()))); + break; + } + } + return newResult; +} + Json Assets::readJson(String const& path) const { ByteArray streamData = read(path); try { @@ -688,30 +720,13 @@ Json Assets::readJson(String const& path) const { if (patchJson.isType(Json::Type::Array)) { auto patchData = patchJson.toArray(); try { - if (patchData.size()) { - if (patchData.at(0).type() == Json::Type::Array) { - for (auto const& patch : patchData) { - try { - result = jsonPatch(result, patch.toArray()); - } catch (JsonPatchTestFail const& e) { - Logger::debug("Patch test failure from file {} in source: {}. Caused by: {}", pair.first, m_assetSourcePaths.getLeft(pair.second), e.what()); - } - } - } else if (patchData.at(0).type() == Json::Type::Object) { - try { - result = jsonPatch(result, patchData); - } catch (JsonPatchTestFail const& e) { - Logger::debug("Patch test failure from file {} in source: {}. Caused by: {}", pair.first, m_assetSourcePaths.getLeft(pair.second), e.what()); - } - } else { - throw JsonPatchException(strf("Patch data is wrong type: {}", Json::typeName(patchData.at(0).type()))); - } - } + result = checkPatchArray(pair.first, pair.second, result, patchData, {}); + } catch (JsonPatchTestFail const& e) { + Logger::debug("Patch test failure from file {} in source: '{}' at '{}'. Caused by: {}", pair.first, pair.second->metadata().value("name", ""), m_assetSourcePaths.getLeft(pair.second), e.what()); } catch (JsonPatchException const& e) { - Logger::error("Could not apply patch from file {} in source: {}. Caused by: {}", pair.first, m_assetSourcePaths.getLeft(pair.second), e.what()); + Logger::error("Could not apply patch from file {} in source: '{}' at '{}'. Caused by: {}", pair.first, pair.second->metadata().value("name", ""), m_assetSourcePaths.getLeft(pair.second), e.what()); } - } - else if (patchJson.isType(Json::Type::Object)) { //Kae: Do a good ol' json merge instead if the .patch file is a Json object + } else if (patchJson.isType(Json::Type::Object)) { //Kae: Do a good ol' json merge instead if the .patch file is a Json object auto patchData = patchJson.toObject(); result = jsonMerge(result, patchData); } @@ -722,6 +737,7 @@ Json Assets::readJson(String const& path) const { } } + bool Assets::doLoad(AssetId const& id) const { try { // loadAsset automatically manages the queue and freshens the asset diff --git a/source/base/StarAssets.hpp b/source/base/StarAssets.hpp index 0024207..37e9a6c 100644 --- a/source/base/StarAssets.hpp +++ b/source/base/StarAssets.hpp @@ -269,6 +269,7 @@ private: ByteArray read(String const& basePath) const; Json readJson(String const& basePath) const; + Json checkPatchArray(String const& path, AssetSourcePtr const& source, Json const result, JsonArray const patchData, Maybe const external) const; // Load / post process an asset and log any exception. Returns true if the // work was performed (whether successful or not), false if the work is diff --git a/source/core/StarJsonPatch.cpp b/source/core/StarJsonPatch.cpp index d8116eb..14505e5 100644 --- a/source/core/StarJsonPatch.cpp +++ b/source/core/StarJsonPatch.cpp @@ -44,7 +44,7 @@ namespace JsonPatching { {"merge", std::bind(applyMergeOperation, _1, _2)}, }; - Json applyOperation(Json const& base, Json const& op) { + Json applyOperation(Json const& base, Json const& op, Maybe const& external) { try { auto operation = op.getString("op"); return JsonPatching::functionMap.get(operation)(base, op); diff --git a/source/core/StarJsonPatch.hpp b/source/core/StarJsonPatch.hpp index 44bf482..9832543 100644 --- a/source/core/StarJsonPatch.hpp +++ b/source/core/StarJsonPatch.hpp @@ -13,7 +13,7 @@ Json jsonPatch(Json const& base, JsonArray const& patch); namespace JsonPatching { // Applies the given single operation - Json applyOperation(Json const& base, Json const& op); + Json applyOperation(Json const& base, Json const& op, Maybe const& external = {}); // Tests for "value" at "path" // Returns base or throws JsonPatchException