mirror of
https://github.com/octoleo/plantuml.git
synced 2024-12-18 08:34:16 +00:00
feat: add new JSON builtin function (%json_merge
)
This commit is contained in:
parent
dcfe17b73c
commit
3dba008497
@ -112,6 +112,7 @@ import net.sourceforge.plantuml.tim.stdlib.IsDark;
|
||||
import net.sourceforge.plantuml.tim.stdlib.IsLight;
|
||||
import net.sourceforge.plantuml.tim.stdlib.JsonAdd;
|
||||
import net.sourceforge.plantuml.tim.stdlib.JsonKeyExists;
|
||||
import net.sourceforge.plantuml.tim.stdlib.JsonMerge;
|
||||
import net.sourceforge.plantuml.tim.stdlib.JsonRemove;
|
||||
import net.sourceforge.plantuml.tim.stdlib.JsonSet;
|
||||
import net.sourceforge.plantuml.tim.stdlib.Lighten;
|
||||
@ -224,6 +225,7 @@ public class TContext {
|
||||
functionsSet.addFunction(new JsonAdd());
|
||||
functionsSet.addFunction(new JsonRemove());
|
||||
functionsSet.addFunction(new JsonSet());
|
||||
functionsSet.addFunction(new JsonMerge());
|
||||
// %standard_exists_function
|
||||
// %str_replace
|
||||
// !exit
|
||||
|
92
src/net/sourceforge/plantuml/tim/stdlib/JsonMerge.java
Normal file
92
src/net/sourceforge/plantuml/tim/stdlib/JsonMerge.java
Normal file
@ -0,0 +1,92 @@
|
||||
/* ========================================================================
|
||||
* PlantUML : a free UML diagram generator
|
||||
* ========================================================================
|
||||
*
|
||||
* (C) Copyright 2009-2024, Arnaud Roques
|
||||
*
|
||||
* Project Info: https://plantuml.com
|
||||
*
|
||||
* If you like this project or if you find it useful, you can support us at:
|
||||
*
|
||||
* https://plantuml.com/patreon (only 1$ per month!)
|
||||
* https://plantuml.com/paypal
|
||||
*
|
||||
* This file is part of PlantUML.
|
||||
*
|
||||
* PlantUML is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* PlantUML distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
* USA.
|
||||
*
|
||||
*
|
||||
* Original Author: Arnaud Roques
|
||||
* Contribution: The-Lum
|
||||
*
|
||||
*/
|
||||
package net.sourceforge.plantuml.tim.stdlib;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import net.sourceforge.plantuml.json.JsonArray;
|
||||
import net.sourceforge.plantuml.json.JsonObject;
|
||||
import net.sourceforge.plantuml.json.JsonValue;
|
||||
import net.sourceforge.plantuml.text.StringLocated;
|
||||
import net.sourceforge.plantuml.tim.EaterException;
|
||||
import net.sourceforge.plantuml.tim.TContext;
|
||||
import net.sourceforge.plantuml.tim.TFunctionSignature;
|
||||
import net.sourceforge.plantuml.tim.TMemory;
|
||||
import net.sourceforge.plantuml.tim.expression.TValue;
|
||||
|
||||
public class JsonMerge extends SimpleReturnFunction {
|
||||
|
||||
public TFunctionSignature getSignature() {
|
||||
return new TFunctionSignature("%json_merge", 2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canCover(int nbArg, Set<String> namedArgument) {
|
||||
return nbArg == 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TValue executeReturnFunction(TContext context, TMemory memory, StringLocated location, List<TValue> values,
|
||||
Map<String, TValue> named) throws EaterException {
|
||||
final TValue data0 = values.get(0);
|
||||
if (!data0.isJson())
|
||||
throw new EaterException("Not JSON data", location);
|
||||
final TValue data1 = values.get(1);
|
||||
if (!data1.isJson())
|
||||
throw new EaterException("Not JSON data", location);
|
||||
|
||||
final JsonValue json0 = data0.toJson();
|
||||
final JsonValue json1 = data1.toJson();
|
||||
|
||||
if ((!json0.isArray() && !json0.isObject() && !json1.isArray() && !json1.isObject())
|
||||
|| ((json0.isArray() && json1.isObject()) || (json0.isObject() && json1.isArray())))
|
||||
return data0;
|
||||
|
||||
if (json0.isArray() && json1.isArray()) {
|
||||
for (JsonValue j1 : json1.asArray()) {
|
||||
json0.asArray().add(j1);
|
||||
}
|
||||
return TValue.fromJson(json0);
|
||||
}
|
||||
if (json0.isObject() && json1.isObject()) {
|
||||
json0.asObject().merge(json1.asObject());
|
||||
return TValue.fromJson(json0);
|
||||
}
|
||||
throw new EaterException("Bad JSON type", location);
|
||||
}
|
||||
}
|
93
test/net/sourceforge/plantuml/tim/stdlib/JsonMergeTest.java
Normal file
93
test/net/sourceforge/plantuml/tim/stdlib/JsonMergeTest.java
Normal file
@ -0,0 +1,93 @@
|
||||
package net.sourceforge.plantuml.tim.stdlib;
|
||||
|
||||
import static net.sourceforge.plantuml.tim.TimTestUtils.assertTimExpectedOutputFromInput;
|
||||
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores;
|
||||
import org.junit.jupiter.api.IndicativeSentencesGeneration;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.converter.ConvertWith;
|
||||
import org.junit.jupiter.params.provider.CsvSource;
|
||||
|
||||
import net.sourceforge.plantuml.json.JsonValue;
|
||||
import net.sourceforge.plantuml.tim.EaterException;
|
||||
import net.sourceforge.plantuml.tim.TFunction;
|
||||
import test.utils.JunitUtils.StringJsonConverter;
|
||||
|
||||
/**
|
||||
* Tests the builtin function.
|
||||
*/
|
||||
@IndicativeSentencesGeneration(separator = ": ", generator = ReplaceUnderscores.class)
|
||||
|
||||
class JsonMergeTest {
|
||||
TFunction cut = new JsonMerge();
|
||||
final String cutName = "json_merge";
|
||||
final String paramTestName = "[{index}] " + cutName + "({0}, {1}) = {2}";
|
||||
|
||||
@ParameterizedTest(name = paramTestName)
|
||||
@CsvSource(value = {
|
||||
" [], [1], [1]",
|
||||
" [0], [\"a\"], '[0,\"a\"]' ",
|
||||
" [0], [{\"a\": 123}], '[0,{\"a\":123}]' ",
|
||||
" [0], [1], '[0,1]' ",
|
||||
" '[{\"a\":[1, 2]}]', [1], '[{\"a\":[1,2]},1]' ",
|
||||
|
||||
})
|
||||
void Test_with_Array_Json(@ConvertWith(StringJsonConverter.class) JsonValue input1, @ConvertWith(StringJsonConverter.class) JsonValue input2, String expected) throws EaterException {
|
||||
assertTimExpectedOutputFromInput(cut, input1, input2, expected);
|
||||
}
|
||||
|
||||
@ParameterizedTest(name = "[{index}] " + cutName + "({0}, {1}, {2}) = {3}")
|
||||
@CsvSource(value = {
|
||||
" {}, {\"a\":1}, {\"a\":1}",
|
||||
" {}, '{\"a\":[1,2,3]}', '{\"a\":[1,2,3]}'",
|
||||
" {}, '{\"a\":{\"b\":123}}', '{\"a\":{\"b\":123}}'",
|
||||
" {}, '{\"a\":{\"b\":\"abc\"}}', '{\"a\":{\"b\":\"abc\"}}'",
|
||||
" {\"z\":0}, '{\"a\":1}', '{\"z\":0,\"a\":1}'",
|
||||
" {\"z\":0}, '{\"a\":[1,2,3]}', '{\"z\":0,\"a\":[1,2,3]}'",
|
||||
" {\"z\":0}, '{\"a\":{\"b\":123}}', '{\"z\":0,\"a\":{\"b\":123}}'",
|
||||
" {\"z\":0}, '{\"a\":{\"b\":\"abc\"}}', '{\"z\":0,\"a\":{\"b\":\"abc\"}}'",
|
||||
" '{\"a\": 1, \"b\": \"two\"}', {\"c\":3}, '{\"a\":1,\"b\":\"two\",\"c\":3}'",
|
||||
" '{\"a\": 1, \"b\": \"two\"}', '{\"d\":{\"da\": 1, \"db\": \"two\"}}', '{\"a\":1,\"b\":\"two\",\"d\":{\"da\":1,\"db\":\"two\"}}'",
|
||||
" {\"z\":0}, '{\"z\":1}', '{\"z\":1}'",
|
||||
" {\"z\":0}, '{\"z\":[1,2,3]}', '{\"z\":[1,2,3]}'",
|
||||
" {\"z\":0}, '{\"z\":{\"b\":123}}', '{\"z\":{\"b\":123}}'",
|
||||
" {\"z\":0}, '{\"z\":{\"b\":\"abc\"}}', '{\"z\":{\"b\":\"abc\"}}'",
|
||||
" '{\"a\": 1, \"b\": \"two\"}', {\"b\":3}, '{\"a\":1,\"b\":3}'",
|
||||
|
||||
})
|
||||
void Test_with_Object_Json(@ConvertWith(StringJsonConverter.class) JsonValue input1, @ConvertWith(StringJsonConverter.class) JsonValue input2, String expected) throws EaterException {
|
||||
assertTimExpectedOutputFromInput(cut, input1, input2, expected);
|
||||
}
|
||||
|
||||
@Nested
|
||||
class Not_Nominal_Test {
|
||||
@ParameterizedTest(name = paramTestName)
|
||||
@CsvSource(value = {
|
||||
" [], {\"a\":1}, []",
|
||||
" [0], {\"a\":1}, '[0]' ",
|
||||
" [0], {\"a\":1}, '[0]' ",
|
||||
" [0], {\"a\":1}, '[0]' ",
|
||||
" '[{\"a\":[1, 2]}]', {\"a\":1}, '[{\"a\":[1,2]}]' ",
|
||||
|
||||
})
|
||||
void Test_with_Array_Object_Json(@ConvertWith(StringJsonConverter.class) JsonValue input1, @ConvertWith(StringJsonConverter.class) JsonValue input2, String expected) throws EaterException {
|
||||
assertTimExpectedOutputFromInput(cut, input1, input2, expected);
|
||||
}
|
||||
|
||||
@ParameterizedTest(name = paramTestName)
|
||||
@CsvSource(value = {
|
||||
" {}, [], {} ",
|
||||
" {\"a\":1}, [], {\"a\":1} ",
|
||||
" '{\"a\":[1,2,3]}', [0], '{\"a\":[1,2,3]}' ",
|
||||
" '{\"z\":0,\"a\":1}', [0], '{\"z\":0,\"a\":1}' ",
|
||||
" '{\"z\":0,\"a\":1}', '[{\"a\":[1, 2]}]', '{\"z\":0,\"a\":1}' ",
|
||||
|
||||
})
|
||||
void Test_with_Object_Array_Json(@ConvertWith(StringJsonConverter.class) JsonValue input1, @ConvertWith(StringJsonConverter.class) JsonValue input2, String expected) throws EaterException {
|
||||
assertTimExpectedOutputFromInput(cut, input1, input2, expected);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user