diff --git a/bom/kie-yard-bom/.gitignore b/bom/kie-yard-bom/.gitignore
new file mode 100644
index 00000000000..606d865999a
--- /dev/null
+++ b/bom/kie-yard-bom/.gitignore
@@ -0,0 +1,10 @@
+/target
+/local
+
+# Eclipse, Netbeans and IntelliJ files
+/.gitignore
+!.gitignore
+/nbproject
+/*.ipr
+/*.iws
+/*.iml
diff --git a/bom/kie-yard-bom/pom.xml b/bom/kie-yard-bom/pom.xml
new file mode 100644
index 00000000000..15c0d4959d9
--- /dev/null
+++ b/bom/kie-yard-bom/pom.xml
@@ -0,0 +1,113 @@
+
+
+
+ 4.0.0
+
+ org.kie
+ kie-core-bom
+ 999-SNAPSHOT
+ ../kie-core-bom/pom.xml
+
+
+ kie-yard-bom
+ pom
+
+ Kie YaRD BOM (Bill Of Materials)
+
+ Import this BOM in your dependencyManagement if you want to depend on multiple Kie YaRD artifacts.
+
+
+ https://www.drools.org
+
+
+ scm:git:https://github.com/apache/incubator-kie-drools.git
+ scm:git:git@github.com:apache/incubator-kie-drools.git
+ https://github.com/apache/incubator-kie-drools
+
+
+ GitHub Issues
+ https://github.com/apache/incubator-kie-issues/issues
+
+
+
+ All developers are listed on the team website
+ http://www.drools.org/community/team.html
+
+
+
+
+ All contributors are listed on the team website
+ http://www.drools.org/community/team.html
+
+
+
+
+ Development mailing list
+ dev@kie.apache.org
+ dev-subscribe@kie.apache.org
+ dev-unsubscribe@kie.apache.org
+ https://lists.apache.org/list.html?dev@kie.apache.org
+
+
+ setup
+ https://groups.google.com/forum/#!forum/drools-setup
+ https://groups.google.com/forum/#!forum/drools-setup
+
+
+ usage
+ https://groups.google.com/forum/#!forum/drools-usage
+ https://groups.google.com/forum/#!forum/drools-usage
+
+
+
+
+
+
+
+
+
+ org.drools
+ drools-bom
+ pom
+ ${project.version}
+ import
+
+
+
+
+
+ org.kie
+ kie-yard-api
+ ${project.version}
+
+
+ org.kie
+ kie-yard-api
+ ${project.version}
+ sources
+
+
+ org.kie
+ kie-yard-core
+ ${project.version}
+
+
+ org.kie
+ kie-yard-core
+ ${project.version}
+ sources
+
+
+
+
+
+
diff --git a/bom/pom.xml b/bom/pom.xml
index 411a4269a1d..b4ad741e621 100644
--- a/bom/pom.xml
+++ b/bom/pom.xml
@@ -19,6 +19,7 @@
kie-efesto-bom
kie-dmn-bom
kie-pmml-bom
+ kie-yard-bom
\ No newline at end of file
diff --git a/build-parent/pom.xml b/build-parent/pom.xml
index f91ddc9fbea..39575453af6 100644
--- a/build-parent/pom.xml
+++ b/build-parent/pom.xml
@@ -216,6 +216,9 @@
3.3.0
3.4.0
3.6.2
+
+ 0.4
+ 1.1.0
@@ -1142,6 +1145,21 @@
jboss-logging
${version.org.jboss.logging}
+
+ org.kie.j2cl.tools.yaml.mapper
+ common
+ ${version.yaml.mapper}
+
+
+ org.kie.j2cl.tools.yaml.mapper
+ processor
+ ${version.yaml.mapper}
+
+
+ ch.obermuhlner
+ jshell-scriptengine
+ ${version.jshell}
+
diff --git a/kie-yard/kie-yard-api/pom.xml b/kie-yard/kie-yard-api/pom.xml
new file mode 100644
index 00000000000..15911e2572c
--- /dev/null
+++ b/kie-yard/kie-yard-api/pom.xml
@@ -0,0 +1,61 @@
+
+
+
+ 4.0.0
+
+ org.kie
+ kie-yard
+ 999-SNAPSHOT
+
+
+ kie-yard-api
+
+
+ org.kie.yard.api
+
+
+
+
+
+ org.drools
+ drools-bom
+ ${project.version}
+ pom
+ import
+
+
+
+
+
+
+ org.kie.j2cl.tools.yaml.mapper
+ common
+
+
+
+ org.kie.j2cl.tools.yaml.mapper
+ processor
+ provided
+
+
+
\ No newline at end of file
diff --git a/kie-yard/kie-yard-api/src/main/java/org/kie/yard/api/model/DecisionLogic.java b/kie-yard/kie-yard-api/src/main/java/org/kie/yard/api/model/DecisionLogic.java
new file mode 100644
index 00000000000..8f1c8ffc164
--- /dev/null
+++ b/kie-yard/kie-yard-api/src/main/java/org/kie/yard/api/model/DecisionLogic.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.yard.api.model;
+
+import org.kie.j2cl.tools.yaml.mapper.api.annotation.YamlSubtype;
+import org.kie.j2cl.tools.yaml.mapper.api.annotation.YamlTypeInfo;
+
+@YamlTypeInfo(
+ key = "type",
+ value = {
+ @YamlSubtype(alias = "DecisionTable", type = DecisionTable.class),
+ @YamlSubtype(alias = "LiteralExpression", type = LiteralExpression.class)
+ })
+public interface DecisionLogic {
+
+}
diff --git a/kie-yard/kie-yard-api/src/main/java/org/kie/yard/api/model/DecisionTable.java b/kie-yard/kie-yard-api/src/main/java/org/kie/yard/api/model/DecisionTable.java
new file mode 100644
index 00000000000..57678c66bdf
--- /dev/null
+++ b/kie-yard/kie-yard-api/src/main/java/org/kie/yard/api/model/DecisionTable.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.yard.api.model;
+
+import java.util.List;
+
+import org.kie.j2cl.tools.yaml.mapper.api.annotation.YAMLMapper;
+import org.kie.j2cl.tools.yaml.mapper.api.annotation.YamlTypeDeserializer;
+import org.kie.j2cl.tools.yaml.mapper.api.annotation.YamlTypeSerializer;
+
+@YAMLMapper
+public class DecisionTable implements DecisionLogic {
+
+ private List inputs;
+ private String hitPolicy = "ANY";
+ @Deprecated
+ private List outputComponents;
+ @YamlTypeSerializer(RuleDefSerializer.class)
+ @YamlTypeDeserializer(RuleDefSerializer.class)
+ private List rules;
+
+ public void setInputs(List inputs) {
+ this.inputs = inputs;
+ }
+
+ public void setOutputComponents(List outputComponents) {
+ this.outputComponents = outputComponents;
+ }
+
+ public List getInputs() {
+ return inputs;
+ }
+
+ @Deprecated
+ public List getOutputComponents() {
+ return outputComponents;
+ }
+
+ public String getHitPolicy() {
+ return hitPolicy;
+ }
+
+ public void setHitPolicy(String hitPolicy) {
+ this.hitPolicy = hitPolicy;
+ }
+
+ public List getRules() {
+ return rules;
+ }
+
+ public void setRules(List rules) {
+ this.rules = rules;
+ }
+}
diff --git a/kie-yard/kie-yard-api/src/main/java/org/kie/yard/api/model/Element.java b/kie-yard/kie-yard-api/src/main/java/org/kie/yard/api/model/Element.java
new file mode 100644
index 00000000000..77fe1c3208e
--- /dev/null
+++ b/kie-yard/kie-yard-api/src/main/java/org/kie/yard/api/model/Element.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.yard.api.model;
+
+import java.util.List;
+
+import org.kie.j2cl.tools.yaml.mapper.api.annotation.YAMLMapper;
+
+@YAMLMapper
+public class Element {
+
+ private String name;
+ private String type;
+ private List requirements;
+ private DecisionLogic logic;
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public void setRequirements(List requirements) {
+ this.requirements = requirements;
+ }
+
+ public void setLogic(DecisionLogic logic) {
+ this.logic = logic;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public List getRequirements() {
+ return requirements;
+ }
+
+ public DecisionLogic getLogic() {
+ return logic;
+ }
+}
diff --git a/kie-yard/kie-yard-api/src/main/java/org/kie/yard/api/model/InlineRule.java b/kie-yard/kie-yard-api/src/main/java/org/kie/yard/api/model/InlineRule.java
new file mode 100644
index 00000000000..79c921e15ee
--- /dev/null
+++ b/kie-yard/kie-yard-api/src/main/java/org/kie/yard/api/model/InlineRule.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.yard.api.model;
+
+import java.util.List;
+
+public class InlineRule implements Rule {
+
+ private final int rowNumber;
+ public List def;
+
+ public InlineRule(int rowNumber, List data) {
+ this.rowNumber = rowNumber;
+ this.def = data;
+ }
+
+ @Override
+ public int getRowNumber() {
+ return rowNumber;
+ }
+
+ public List getDef() {
+ return def;
+ }
+
+ public void setDef(List def) {
+ this.def = def;
+ }
+}
diff --git a/kie-yard/kie-yard-api/src/main/java/org/kie/yard/api/model/Input.java b/kie-yard/kie-yard-api/src/main/java/org/kie/yard/api/model/Input.java
new file mode 100644
index 00000000000..a025c298695
--- /dev/null
+++ b/kie-yard/kie-yard-api/src/main/java/org/kie/yard/api/model/Input.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.yard.api.model;
+
+import org.kie.j2cl.tools.yaml.mapper.api.annotation.YAMLMapper;
+
+@YAMLMapper
+public class Input {
+
+ private String name;
+ private String type;
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getType() {
+ return type;
+ }
+}
\ No newline at end of file
diff --git a/kie-yard/kie-yard-api/src/main/java/org/kie/yard/api/model/LiteralExpression.java b/kie-yard/kie-yard-api/src/main/java/org/kie/yard/api/model/LiteralExpression.java
new file mode 100644
index 00000000000..18e884baef8
--- /dev/null
+++ b/kie-yard/kie-yard-api/src/main/java/org/kie/yard/api/model/LiteralExpression.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.yard.api.model;
+
+import org.kie.j2cl.tools.yaml.mapper.api.annotation.YAMLMapper;
+
+@YAMLMapper
+public class LiteralExpression implements DecisionLogic {
+
+ private String expression;
+
+ public void setExpression(String expression) {
+ this.expression = expression;
+ }
+
+ public String getExpression() {
+ return expression;
+ }
+}
\ No newline at end of file
diff --git a/kie-yard/kie-yard-api/src/main/java/org/kie/yard/api/model/Operators.java b/kie-yard/kie-yard-api/src/main/java/org/kie/yard/api/model/Operators.java
new file mode 100644
index 00000000000..bae70914259
--- /dev/null
+++ b/kie-yard/kie-yard-api/src/main/java/org/kie/yard/api/model/Operators.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.yard.api.model;
+
+import java.util.Objects;
+
+/**
+ * Interface instead of enum due to possible custom operators.
+ */
+public interface Operators {
+
+ String NOT_EQUALS = "!=";
+ String EQUALS = "=";
+ String GREATER_OR_EQUAL = ">=";
+ String GREATER_THAN = ">";
+ String LESS_OR_EQUAL = "<=";
+ String LESS_THAN = "<";
+
+ String[] ALL = {EQUALS, LESS_OR_EQUAL, LESS_THAN, GREATER_OR_EQUAL, GREATER_THAN, NOT_EQUALS};
+
+ static int compare(final String operator,
+ final String other) {
+ return getWeight(operator) - getWeight(other);
+ }
+
+ static int getWeight(final String operator) {
+ for (int i = 0; i < ALL.length; i++) {
+ if (Objects.equals(operator, ALL[i])) {
+ return i;
+ }
+ }
+ return 0;
+ }
+}
diff --git a/kie-yard/kie-yard-api/src/main/java/org/kie/yard/api/model/Rule.java b/kie-yard/kie-yard-api/src/main/java/org/kie/yard/api/model/Rule.java
new file mode 100644
index 00000000000..874f2650b03
--- /dev/null
+++ b/kie-yard/kie-yard-api/src/main/java/org/kie/yard/api/model/Rule.java
@@ -0,0 +1,24 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.yard.api.model;
+
+public interface Rule {
+
+ int getRowNumber();
+}
diff --git a/kie-yard/kie-yard-api/src/main/java/org/kie/yard/api/model/RuleDefSerializer.java b/kie-yard/kie-yard-api/src/main/java/org/kie/yard/api/model/RuleDefSerializer.java
new file mode 100644
index 00000000000..cedd50668e1
--- /dev/null
+++ b/kie-yard/kie-yard-api/src/main/java/org/kie/yard/api/model/RuleDefSerializer.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.yard.api.model;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.kie.j2cl.tools.yaml.mapper.api.YAMLDeserializer;
+import org.kie.j2cl.tools.yaml.mapper.api.YAMLSerializer;
+import org.kie.j2cl.tools.yaml.mapper.api.exception.YAMLDeserializationException;
+import org.kie.j2cl.tools.yaml.mapper.api.internal.deser.YAMLDeserializationContext;
+import org.kie.j2cl.tools.yaml.mapper.api.internal.ser.YAMLSerializationContext;
+import org.kie.j2cl.tools.yaml.mapper.api.node.YamlMapping;
+import org.kie.j2cl.tools.yaml.mapper.api.node.YamlNode;
+import org.kie.j2cl.tools.yaml.mapper.api.node.YamlSequence;
+
+public class RuleDefSerializer
+ implements YAMLSerializer,
+ YAMLDeserializer {
+
+ private int rowNumber = 1;
+
+ @Override
+ public Object deserialize(YamlMapping yamlMapping,
+ String s,
+ YAMLDeserializationContext yamlDeserializationContext) throws YAMLDeserializationException {
+ return deserialize(yamlMapping.getNode(s), yamlDeserializationContext);
+ }
+
+ @Override
+ public Object deserialize(YamlNode yamlNode,
+ YAMLDeserializationContext yamlDeserializationContext) {
+ if (yamlNode instanceof YamlSequence) {
+ final List items = getItems(yamlNode);
+ return new InlineRule(rowNumber++, items);
+ } else if (yamlNode instanceof YamlMapping) {
+ final WhenThenRule whenThenRule = new WhenThenRule(rowNumber++);
+ final YamlNode when = ((YamlMapping) yamlNode).getNode("when");
+ final YamlNode then = ((YamlMapping) yamlNode).getNode("then");
+ whenThenRule.setWhen(getItems(when));
+ whenThenRule.setThen(then.asScalar().value());
+ return whenThenRule;
+ }
+ return new IllegalArgumentException("Unknown rule format.");
+ }
+
+ private List getItems(final YamlNode yamlNode) {
+ final List result = new ArrayList<>();
+ if (yamlNode instanceof YamlSequence) {
+ ((YamlSequence) yamlNode).iterator().forEachRemaining(x -> {
+ final Comparable value = (Comparable) x.asScalar().value();
+ result.add(value);
+ });
+ }
+ return result;
+ }
+
+ @Override
+ public void serialize(YamlMapping yamlMapping,
+ String s,
+ Object objects,
+ YAMLSerializationContext yamlSerializationContext) {
+ // Not needed, we never serialize.
+ }
+
+ @Override
+ public void serialize(YamlSequence yamlSequence,
+ Object objects,
+ YAMLSerializationContext yamlSerializationContext) {
+ // Not needed, we never serialize.
+ }
+}
diff --git a/kie-yard/kie-yard-api/src/main/java/org/kie/yard/api/model/WhenThenRule.java b/kie-yard/kie-yard-api/src/main/java/org/kie/yard/api/model/WhenThenRule.java
new file mode 100644
index 00000000000..b552f714585
--- /dev/null
+++ b/kie-yard/kie-yard-api/src/main/java/org/kie/yard/api/model/WhenThenRule.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.yard.api.model;
+
+import java.util.List;
+
+public class WhenThenRule implements Rule {
+
+ private final int rowNumber;
+ private List when;
+ private Object then;
+
+ public WhenThenRule(int rowNumber) {
+ this.rowNumber = rowNumber;
+ }
+
+ @Override
+ public int getRowNumber() {
+ return rowNumber;
+ }
+
+ public List getWhen() {
+ return when;
+ }
+
+ public Object getThen() {
+ return then;
+ }
+
+ public void setWhen(List when) {
+ this.when = when;
+ }
+
+ public void setThen(Object then) {
+ this.then = then;
+ }
+}
diff --git a/kie-yard/kie-yard-api/src/main/java/org/kie/yard/api/model/WhenThenRuleThenSerializer.java b/kie-yard/kie-yard-api/src/main/java/org/kie/yard/api/model/WhenThenRuleThenSerializer.java
new file mode 100644
index 00000000000..63d2dcd5f5b
--- /dev/null
+++ b/kie-yard/kie-yard-api/src/main/java/org/kie/yard/api/model/WhenThenRuleThenSerializer.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.yard.api.model;
+
+import java.util.Locale;
+
+import org.kie.j2cl.tools.yaml.mapper.api.YAMLDeserializer;
+import org.kie.j2cl.tools.yaml.mapper.api.YAMLSerializer;
+import org.kie.j2cl.tools.yaml.mapper.api.exception.YAMLDeserializationException;
+import org.kie.j2cl.tools.yaml.mapper.api.internal.deser.YAMLDeserializationContext;
+import org.kie.j2cl.tools.yaml.mapper.api.internal.ser.YAMLSerializationContext;
+import org.kie.j2cl.tools.yaml.mapper.api.node.YamlMapping;
+import org.kie.j2cl.tools.yaml.mapper.api.node.YamlNode;
+import org.kie.j2cl.tools.yaml.mapper.api.node.YamlSequence;
+
+public class WhenThenRuleThenSerializer
+ implements YAMLSerializer,
+ YAMLDeserializer {
+
+ @Override
+ public Object deserialize(YamlMapping yamlMapping, String key, YAMLDeserializationContext yamlDeserializationContext) throws YAMLDeserializationException {
+ return deserialize(yamlMapping.getNode(key), yamlDeserializationContext);
+ }
+
+ @Override
+ public Object deserialize(YamlNode yamlNode, YAMLDeserializationContext yamlDeserializationContext) {
+ if (yamlNode == null || yamlNode.isEmpty()) {
+ return null;
+ }
+ return yamlNode.asScalar().value().toLowerCase(Locale.ROOT);
+ }
+
+ @Override
+ public void serialize(YamlMapping yamlMapping, String s, Object o, YAMLSerializationContext yamlSerializationContext) {
+ // Not needed, we never serialize.
+ }
+
+ @Override
+ public void serialize(YamlSequence yamlSequence, Object o, YAMLSerializationContext yamlSerializationContext) {
+ // Not needed, we never serialize.
+ }
+}
diff --git a/kie-yard/kie-yard-api/src/main/java/org/kie/yard/api/model/YaRD.java b/kie-yard/kie-yard-api/src/main/java/org/kie/yard/api/model/YaRD.java
new file mode 100644
index 00000000000..a0a40ba7d9c
--- /dev/null
+++ b/kie-yard/kie-yard-api/src/main/java/org/kie/yard/api/model/YaRD.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.yard.api.model;
+
+import java.util.List;
+
+import org.kie.j2cl.tools.yaml.mapper.api.annotation.YAMLMapper;
+
+@YAMLMapper
+public class YaRD {
+
+ private String specVersion = "alpha";
+ private String kind = "YaRD";
+ private String name;
+ private String expressionLang;
+ private List inputs;
+ private List elements;
+
+ public void setInputs(List inputs) {
+ this.inputs = inputs;
+ }
+
+ public void setElements(List elements) {
+ this.elements = elements;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getExpressionLang() {
+ return expressionLang;
+ }
+
+ public void setExpressionLang(String expressionLang) {
+ this.expressionLang = expressionLang;
+ }
+
+ public String getKind() {
+ return kind;
+ }
+
+ public void setKind(String kind) {
+ this.kind = kind;
+ }
+
+ public String getSpecVersion() {
+ return specVersion;
+ }
+
+ public void setSpecVersion(String specVersion) {
+ this.specVersion = specVersion;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public List getInputs() {
+ return inputs;
+ }
+
+ public List getElements() {
+ return elements;
+ }
+}
diff --git a/kie-yard/kie-yard-api/src/main/resources/YaRD-schema.json b/kie-yard/kie-yard-api/src/main/resources/YaRD-schema.json
new file mode 100644
index 00000000000..95d19677960
--- /dev/null
+++ b/kie-yard/kie-yard-api/src/main/resources/YaRD-schema.json
@@ -0,0 +1,191 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "definitions": {
+ "DecisionTable-1": {
+ "type": "object",
+ "properties": {
+ "inputs": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "hitPolicy": {
+ "type": "string",
+ "default": "ANY"
+ },
+ "rules": {
+ "type": "array",
+ "items": {
+ "anyOf": [
+ {
+ "$ref": "#/definitions/InlineRule"
+ },
+ {
+ "$ref": "#/definitions/WhenThenRule"
+ }
+ ]
+ }
+ },
+ "outputComponents": {
+ "description": "deprecated",
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ },
+ "required": [
+ "inputs",
+ "rules"
+ ]
+ },
+ "DecisionTable-2": {
+ "allOf": [
+ {
+ "$ref": "#/definitions/DecisionTable-1"
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "DecisionTable"
+ }
+ },
+ "required": [
+ "type"
+ ]
+ }
+ ]
+ },
+ "Element": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "type": {
+ "type": "string"
+ },
+ "requirements": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "logic": {
+ "anyOf": [
+ {
+ "$ref": "#/definitions/DecisionTable-2"
+ },
+ {
+ "$ref": "#/definitions/LiteralExpression-2"
+ }
+ ]
+ }
+ },
+ "required": [
+ "name",
+ "type",
+ "logic"
+ ]
+ },
+ "InlineRule": {
+ "type": "array",
+ "items": {}
+ },
+ "Input": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "type": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "name",
+ "type"
+ ]
+ },
+ "LiteralExpression-1": {
+ "type": "object",
+ "properties": {
+ "expression": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "expression"
+ ]
+ },
+ "LiteralExpression-2": {
+ "allOf": [
+ {
+ "$ref": "#/definitions/LiteralExpression-1"
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "const": "LiteralExpression"
+ }
+ },
+ "required": [
+ "type"
+ ]
+ }
+ ]
+ },
+ "WhenThenRule": {
+ "type": "object",
+ "properties": {
+ "when": {
+ "type": "array",
+ "items": {}
+ },
+ "then": {}
+ },
+ "required": [
+ "when",
+ "then"
+ ]
+ }
+ },
+ "type": "object",
+ "properties": {
+ "specVersion": {
+ "type": "string",
+ "default": "alpha"
+ },
+ "kind": {
+ "type": "string",
+ "default": "YaRD"
+ },
+ "name": {
+ "type": "string",
+ "description": "when not provided explicitly, implementation will attempt to deduce the name from the runtime context; if a name cannot be deduced it is an error."
+ },
+ "expressionLang": {
+ "type": "string",
+ "description": "An implementation is free to assume a default expressionLang if not explicitly set. For the purpose of a User sharing a YaRD definition, is best to valorise this field explicit."
+ },
+ "inputs": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/Input"
+ }
+ },
+ "elements": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/Element"
+ }
+ }
+ },
+ "required": [
+ "inputs",
+ "elements"
+ ]
+}
\ No newline at end of file
diff --git a/kie-yard/kie-yard-core/pom.xml b/kie-yard/kie-yard-core/pom.xml
new file mode 100644
index 00000000000..4d6981620e3
--- /dev/null
+++ b/kie-yard/kie-yard-core/pom.xml
@@ -0,0 +1,76 @@
+
+
+ 4.0.0
+
+ org.kie
+ kie-yard
+ 999-SNAPSHOT
+
+
+ kie-yard-core
+
+
+ org.kie.yard.core
+
+
+
+
+
+ org.drools
+ drools-bom
+ ${project.version}
+ pom
+ import
+
+
+
+
+
+
+ org.kie
+ kie-yard-api
+
+
+ org.drools
+ drools-ruleunits-dsl
+
+
+ org.kie.j2cl.tools.yaml.mapper
+ common
+
+
+
+ ch.obermuhlner
+ jshell-scriptengine
+
+
+ org.mvel
+ mvel2
+
+
+ com.fasterxml.jackson.dataformat
+ jackson-dataformat-yaml
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ test
+
+
+ org.assertj
+ assertj-core
+ test
+
+
+ org.mockito
+ mockito-core
+ test
+
+
+ ch.qos.logback
+ logback-classic
+ test
+
+
+
\ No newline at end of file
diff --git a/kie-yard/kie-yard-core/src/main/java/org/kie/yard/core/DTableUnitBuilder.java b/kie-yard/kie-yard-core/src/main/java/org/kie/yard/core/DTableUnitBuilder.java
new file mode 100644
index 00000000000..592d7e7a260
--- /dev/null
+++ b/kie-yard/kie-yard-core/src/main/java/org/kie/yard/core/DTableUnitBuilder.java
@@ -0,0 +1,198 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.yard.core;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.json.JsonMapper;
+import org.drools.model.Index;
+import org.drools.ruleunits.api.SingletonStore;
+import org.drools.ruleunits.dsl.SyntheticRuleUnit;
+import org.drools.ruleunits.dsl.SyntheticRuleUnitBuilder;
+import org.kie.yard.api.model.InlineRule;
+import org.kie.yard.api.model.Rule;
+import org.kie.yard.api.model.WhenThenRule;
+
+public class DTableUnitBuilder {
+
+ private final YaRDDefinitions definitions;
+ private final String name;
+ private final OnExecute executionAction;
+ private final List rules;
+ private final List inputs;
+ private final JsonMapper jsonMapper = JsonMapper.builder().build();
+
+ public DTableUnitBuilder(
+ final YaRDDefinitions definitions,
+ final String name,
+ final org.kie.yard.api.model.DecisionTable dtableDefinition) {
+ this.inputs = dtableDefinition.getInputs();
+ if (inputs.isEmpty()) {
+ throw new IllegalStateException("Empty decision table?");
+ }
+ this.definitions = definitions;
+ this.name = name;
+ this.rules = dtableDefinition.getRules();
+ this.executionAction = getExecutionAction(dtableDefinition.getHitPolicy());
+ }
+
+ public SyntheticRuleUnit build() {
+
+ final SyntheticRuleUnitBuilder unit = SyntheticRuleUnitBuilder.build(name);
+ for (Map.Entry> e : definitions.inputs().entrySet()) {
+ unit.registerDataSource(e.getKey(), e.getValue(), Object.class);
+ }
+ final StoreHandle result = StoreHandle.empty(Object.class);
+ unit.registerGlobal(name, result);
+ definitions.outputs().put(name, result);
+ return unit.defineRules(rulesFactory -> {
+ for (Rule ruleDefinition : rules) {
+ var rule = rulesFactory.rule();
+ for (int idx = 0; idx < inputs.size(); idx++) {
+ final RuleCell ruleCell = parseGenericRuleCell(ruleDefinition, idx);
+ if (ruleCell.value != null) {
+ final SingletonStore dataSource = definitions.inputs().get(inputs.get(idx));
+
+ rule.on(dataSource).filter(ruleCell.idxtype, ruleCell.value);
+ }
+ }
+ rule.execute(result, storeHandle -> executionAction.onExecute(ruleDefinition, storeHandle));
+ }
+ });
+ }
+
+ private OnExecute getExecutionAction(String hitPolicy) {
+ if (hitPolicy == null || Objects.equals("ANY", hitPolicy)) {
+ return (ruleDefinition, storeHandle) -> {
+ final RuleCell rc = parseGenericRuleThen(ruleDefinition);
+ Object value = resolveValue(rc.value);
+ storeHandle.set(value);
+ };
+ } else if (Objects.equals("FIRST", hitPolicy)) {
+ return (ruleDefinition, storeHandle) -> {
+ if (!storeHandle.isValuePresent()) {
+ final RuleCell rc = parseGenericRuleThen(ruleDefinition);
+ storeHandle.set(resolveValue(rc.value));
+ }
+ };
+ } else if (Objects.equals("COLLECT", hitPolicy)) {
+ return (ruleDefinition, storeHandle) -> {
+ if (!storeHandle.isValuePresent()) {
+ storeHandle.set(new ArrayList<>());
+ }
+ final RuleCell rc = parseGenericRuleThen(ruleDefinition);
+
+ if (storeHandle.get() instanceof List list) {
+ list.add(resolveValue(rc.value));
+ }
+ String remove = "";
+ };
+ } else {
+ throw new UnsupportedOperationException("Not implemented ");
+ }
+ }
+
+ private Object resolveValue(Object value) {
+ try {
+ if (value instanceof String text) {
+ return jsonMapper.readValue(text, Map.class);
+ }
+ } catch (JsonProcessingException ignored) {
+ }
+ return value;
+ }
+
+ private RuleCell parseGenericRuleThen(Rule rule) {
+ if (rule instanceof InlineRule inlineRule) {
+ return parseRuleCell(inlineRule.getDef().get(inlineRule.getDef().size() - 1));
+ } else if (rule instanceof WhenThenRule whenThenRule) {
+ return parseRuleCell((whenThenRule).getThen());
+ } else {
+ throw new IllegalStateException("Unknown or unmanaged rule instance type?");
+ }
+ }
+
+ private RuleCell parseGenericRuleCell(Rule rule, int i) {
+ if (rule instanceof InlineRule inlineRule) {
+ return parseRuleCell((inlineRule).getDef().get(i));
+ } else if (rule instanceof WhenThenRule whenThenRule) {
+ return parseRuleCell((whenThenRule).getWhen().get(i));
+ } else {
+ throw new IllegalStateException("Unknown or unmanaged rule instance type?");
+ }
+ }
+
+ private RuleCell parseRuleCell(Object object) {
+ if (object instanceof Boolean) {
+ return new RuleCell(Index.ConstraintType.EQUAL, object);
+ } else if (object instanceof Number) {
+ return new RuleCell(Index.ConstraintType.EQUAL, object);
+ } else if (object instanceof String valueString) {
+ if (valueString.startsWith("<=")) { // pay attention to ordering when not using a parser like in this case.
+ return new RuleCell(Index.ConstraintType.LESS_OR_EQUAL, parseConstrainedCellString(valueString.substring(2)));
+ } else if (valueString.startsWith(">=")) {
+ return new RuleCell(Index.ConstraintType.GREATER_OR_EQUAL, parseConstrainedCellString(valueString.substring(2)));
+ } else if (valueString.startsWith("<")) {
+ return new RuleCell(Index.ConstraintType.LESS_THAN, parseConstrainedCellString(valueString.substring(1)));
+ } else if (valueString.startsWith(">")) {
+ return new RuleCell(Index.ConstraintType.GREATER_THAN, parseConstrainedCellString(valueString.substring(1)));
+ } else {
+ return new RuleCell(Index.ConstraintType.EQUAL, parseConstrainedCellString(valueString));
+ }
+ } else {
+ throw new IllegalStateException("Unmanaged case, please report!");
+ }
+ }
+
+ private Object parseConstrainedCellString(String substring) {
+ if (Objects.equals("true", substring.trim().toLowerCase())) {
+ return true;
+ }
+ if (Objects.equals("false", substring.trim().toLowerCase())) {
+ return false;
+ }
+ try {
+ return Integer.parseInt(substring.trim());
+ } catch (Exception e) {
+
+ }
+ try {
+ return Long.parseLong(substring.trim());
+ } catch (Exception e) {
+
+ }
+ if (Objects.equals("-", substring.trim())) {
+ return null;
+ }
+ return substring;
+ }
+
+ private interface OnExecute {
+
+ void onExecute(Rule ruleDefinition, StoreHandle storeHandle);
+ }
+
+ public static record RuleCell(Index.ConstraintType idxtype, Object value) {
+
+ }
+}
diff --git a/kie-yard/kie-yard-core/src/main/java/org/kie/yard/core/Firable.java b/kie-yard/kie-yard-core/src/main/java/org/kie/yard/core/Firable.java
new file mode 100644
index 00000000000..7a3548b9f18
--- /dev/null
+++ b/kie-yard/kie-yard-core/src/main/java/org/kie/yard/core/Firable.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.yard.core;
+
+import java.util.Map;
+
+public interface Firable {
+
+ int fire(Map context, YaRDDefinitions units);
+}
\ No newline at end of file
diff --git a/kie-yard/kie-yard-core/src/main/java/org/kie/yard/core/JShellLiteralExpressionInterpreter.java b/kie-yard/kie-yard-core/src/main/java/org/kie/yard/core/JShellLiteralExpressionInterpreter.java
new file mode 100644
index 00000000000..eca81a063df
--- /dev/null
+++ b/kie-yard/kie-yard-core/src/main/java/org/kie/yard/core/JShellLiteralExpressionInterpreter.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.yard.core;
+
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.script.Bindings;
+import javax.script.Compilable;
+import javax.script.CompiledScript;
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineManager;
+import javax.script.ScriptException;
+
+public class JShellLiteralExpressionInterpreter implements Firable {
+
+ private final String name;
+ private final QuotedExprParsed quoted;
+ private final ScriptEngine engine;
+ private final CompiledScript compiledScript;
+
+ public JShellLiteralExpressionInterpreter(final String nameString,
+ final QuotedExprParsed quotedExprParsed) {
+ this.name = nameString;
+ this.quoted = quotedExprParsed;
+ try {
+ final ScriptEngineManager manager = new ScriptEngineManager();
+ engine = manager.getEngineByName("jshell");
+ final Compilable compiler = (Compilable) engine;
+ compiledScript = compiler.compile(quoted.getRewrittenExpression());
+ } catch (Exception e) {
+ throw new IllegalArgumentException("parse error", e);
+ }
+ }
+
+ @Override
+ public int fire(final Map context,
+ final YaRDDefinitions units) {
+ final Bindings bindings = engine.createBindings();
+ // deliberately escape all symbols; a normal symbol will
+ // never be in the detected-by-unquoting set, so this
+ // set can't be used to selectively put in scope
+ for (Entry inKV : context.entrySet()) {
+ bindings.put(QuotedExprParsed.escapeIdentifier(inKV.getKey()), inKV.getValue());
+ }
+ for (Entry> outKV : units.outputs().entrySet()) {
+ if (!outKV.getValue().isValuePresent()) {
+ continue;
+ }
+ bindings.put(QuotedExprParsed.escapeIdentifier(outKV.getKey()), outKV.getValue().get());
+ }
+ try {
+ var result = compiledScript.eval(bindings);
+ units.outputs().get(name).set(result);
+ return 1;
+ } catch (ScriptException e) {
+ throw new RuntimeException("interpretation failed at runtime", e);
+ }
+ }
+}
diff --git a/kie-yard/kie-yard-core/src/main/java/org/kie/yard/core/LiteralExpressionBuilder.java b/kie-yard/kie-yard-core/src/main/java/org/kie/yard/core/LiteralExpressionBuilder.java
new file mode 100644
index 00000000000..f81eefbe1ff
--- /dev/null
+++ b/kie-yard/kie-yard-core/src/main/java/org/kie/yard/core/LiteralExpressionBuilder.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.yard.core;
+
+import org.kie.yard.api.model.LiteralExpression;
+
+import java.util.Objects;
+
+public class LiteralExpressionBuilder {
+
+ private final String expressionLang;
+ private final YaRDDefinitions definitions;
+ private final String name;
+ private final LiteralExpression decisionLogic;
+
+ public LiteralExpressionBuilder(final String expressionLang,
+ final YaRDDefinitions definitions,
+ final String name,
+ final LiteralExpression decisionLogic) {
+ this.expressionLang = expressionLang;
+ this.definitions = definitions;
+ this.name = name;
+ this.decisionLogic = decisionLogic;
+ }
+
+ public Firable build() {
+ final String expr = decisionLogic.getExpression();
+ definitions.outputs().put(name, StoreHandle.empty(Object.class));
+ if(Objects.equals(expressionLang, "jshell")){
+ return new JShellLiteralExpressionInterpreter(name, QuotedExprParsed.from(expr));
+ }
+ else {
+ return new MVELLiteralExpressionInterpreter(name,QuotedExprParsed.from(expr));
+ }
+ }
+}
diff --git a/kie-yard/kie-yard-core/src/main/java/org/kie/yard/core/MVELLiteralExpressionInterpreter.java b/kie-yard/kie-yard-core/src/main/java/org/kie/yard/core/MVELLiteralExpressionInterpreter.java
new file mode 100644
index 00000000000..3e9971fe1fb
--- /dev/null
+++ b/kie-yard/kie-yard-core/src/main/java/org/kie/yard/core/MVELLiteralExpressionInterpreter.java
@@ -0,0 +1,55 @@
+package org.kie.yard.core;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.json.JsonMapper;
+import org.mvel2.MVEL;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class MVELLiteralExpressionInterpreter implements Firable {
+ private final String name;
+ private final QuotedExprParsed expr;
+
+ private final JsonMapper jsonMapper = JsonMapper.builder().build();
+
+ public MVELLiteralExpressionInterpreter(final String name,
+ final QuotedExprParsed expr) {
+ this.name = name;
+ this.expr = expr;
+ }
+
+ @Override
+ public int fire(final Map context,
+ final YaRDDefinitions units) {
+ final Map internalContext = new HashMap<>();
+ internalContext.putAll(context);
+
+ for (Map.Entry> outKV : units.outputs().entrySet()) {
+ if (!outKV.getValue().isValuePresent()) {
+ continue;
+ }
+ internalContext.put(QuotedExprParsed.escapeIdentifier(outKV.getKey()), outKV.getValue().get());
+ }
+
+ try {
+ String rewrittenExpression = expr.getRewrittenExpression();
+ final Object result = MVEL.eval(rewrittenExpression, internalContext);
+ units.outputs().get(name).set(resolveValue(result));
+ return 1;
+ } catch (Exception e) {
+ throw new RuntimeException("interpretation failed at runtime", e);
+ // TODO why throw and not return 0?
+ }
+ }
+
+ private Object resolveValue(Object value) {
+ try {
+ if (value instanceof String text) {
+ return jsonMapper.readValue(text, Map.class);
+ }
+ } catch (JsonProcessingException ignored) {
+ }
+ return value;
+ }
+}
diff --git a/kie-yard/kie-yard-core/src/main/java/org/kie/yard/core/QuotedExprParsed.java b/kie-yard/kie-yard-core/src/main/java/org/kie/yard/core/QuotedExprParsed.java
new file mode 100644
index 00000000000..451a114c72e
--- /dev/null
+++ b/kie-yard/kie-yard-core/src/main/java/org/kie/yard/core/QuotedExprParsed.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.yard.core;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.PrimitiveIterator.OfInt;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import javax.lang.model.SourceVersion;
+
+public class QuotedExprParsed {
+
+ private static final int ESCAPE_CHAR = "`".codePointAt(0);
+
+ private final Set usedSymbols;
+ private final String rewrittenExpression;
+
+ private QuotedExprParsed(List usedSymbols, String rewrittenExpression) {
+ this.usedSymbols = usedSymbols.stream().collect(Collectors.toUnmodifiableSet());
+ this.rewrittenExpression = rewrittenExpression;
+ }
+
+ public String getRewrittenExpression() {
+ return rewrittenExpression;
+ }
+
+ public Collection getUsedSymbols() {
+ return usedSymbols;
+ }
+
+ public static QuotedExprParsed from(String expr) {
+ StringBuilder rewittenExpr = new StringBuilder();
+ StringBuilder quotedBuffer = new StringBuilder();
+ List usedSymbols = new ArrayList<>();
+ OfInt it = expr.codePoints().iterator();
+ State state = State.UNQUOTED;
+ while (it.hasNext()) {
+ int c = it.nextInt();
+ if (c == ESCAPE_CHAR) {
+ switch (state) {
+ case UNQUOTED:
+ state = State.QUOTED;
+ break;
+ case QUOTED:
+ state = State.UNQUOTED;
+ var originalSymbol = quotedBuffer.toString();
+ usedSymbols.add(originalSymbol);
+ var escaped = escapeIdentifier(originalSymbol);
+ rewittenExpr.append(escaped);
+ quotedBuffer = new StringBuilder();
+ break;
+ default:
+ throw new IllegalStateException();
+ }
+ } else {
+ switch (state) {
+ case UNQUOTED:
+ rewittenExpr.appendCodePoint(c);
+ break;
+ case QUOTED:
+ quotedBuffer.appendCodePoint(c);
+ break;
+ default:
+ throw new IllegalStateException();
+ }
+ }
+ }
+ return new QuotedExprParsed(usedSymbols, rewittenExpr.toString());
+ }
+
+ private static enum State {
+ UNQUOTED,
+ QUOTED
+ }
+
+ public static String escapeIdentifier(String partOfIdentifier) {
+ String id = partOfIdentifier;
+ if (!Character.isJavaIdentifierStart(id.charAt(0))) {
+ id = "_" + id;
+ }
+ id = id.replaceAll("_", "__");
+ if (SourceVersion.isKeyword(id)) {
+ id = "_" + id;
+ }
+ StringBuilder result = new StringBuilder();
+ char[] cs = id.toCharArray();
+ for (char c : cs) {
+ if (Character.isJavaIdentifierPart(c)) {
+ result.append(c);
+ } else {
+ result.append("_" + Integer.valueOf(c));
+ }
+ }
+ return result.toString();
+ }
+}
diff --git a/kie-yard/kie-yard-core/src/main/java/org/kie/yard/core/StoreHandle.java b/kie-yard/kie-yard-core/src/main/java/org/kie/yard/core/StoreHandle.java
new file mode 100644
index 00000000000..9e6aa85f45b
--- /dev/null
+++ b/kie-yard/kie-yard-core/src/main/java/org/kie/yard/core/StoreHandle.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.yard.core;
+
+import org.drools.ruleunits.api.DataHandle;
+import org.drools.ruleunits.api.DataSource;
+import org.drools.ruleunits.api.SingletonStore;
+
+public class StoreHandle {
+
+ private SingletonStore wrapped;
+ private DataHandle datahandle;
+
+ private StoreHandle(T value) {
+ wrapped = DataSource.createSingleton();
+ datahandle = wrapped.set(value);
+ }
+
+ private StoreHandle() {
+ wrapped = DataSource.createSingleton();
+ datahandle = null;
+ }
+
+ public static StoreHandle of(T value) {
+ return new StoreHandle<>(value);
+ }
+
+ public static StoreHandle empty(Class type) {
+ return new StoreHandle<>();
+ }
+
+ public DataHandle set(T value) {
+ datahandle = wrapped.set(value);
+ return datahandle;
+ }
+
+ public void clear() {
+ datahandle = null;
+ wrapped.clear();
+ }
+
+ public boolean isValuePresent() {
+ return !(datahandle == null);
+ }
+
+ public T get() {
+ if (datahandle == null) {
+ throw new IllegalStateException("was never set");
+ }
+ @SuppressWarnings("unchecked")
+ T result = (T) datahandle.getObject();
+ return result;
+ }
+}
diff --git a/kie-yard/kie-yard-core/src/main/java/org/kie/yard/core/SyntheticRuleUnitWrapper.java b/kie-yard/kie-yard-core/src/main/java/org/kie/yard/core/SyntheticRuleUnitWrapper.java
new file mode 100644
index 00000000000..46e5ace943a
--- /dev/null
+++ b/kie-yard/kie-yard-core/src/main/java/org/kie/yard/core/SyntheticRuleUnitWrapper.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.yard.core;
+
+import java.util.Map;
+
+import org.drools.ruleunits.api.RuleUnitInstance;
+import org.drools.ruleunits.api.RuleUnitProvider;
+import org.drools.ruleunits.dsl.SyntheticRuleUnit;
+
+public class SyntheticRuleUnitWrapper implements Firable {
+
+ private final SyntheticRuleUnit wrapped;
+
+ public SyntheticRuleUnitWrapper(SyntheticRuleUnit wrapped) {
+ this.wrapped = wrapped;
+ }
+
+ @Override
+ public int fire(Map context, YaRDDefinitions units) {
+ RuleUnitInstance unitInstance = RuleUnitProvider.get().createRuleUnitInstance(wrapped);
+ return unitInstance.fire();
+ }
+}
diff --git a/kie-yard/kie-yard-core/src/main/java/org/kie/yard/core/YaRDDefinitions.java b/kie-yard/kie-yard-core/src/main/java/org/kie/yard/core/YaRDDefinitions.java
new file mode 100644
index 00000000000..730953b041f
--- /dev/null
+++ b/kie-yard/kie-yard-core/src/main/java/org/kie/yard/core/YaRDDefinitions.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.yard.core;
+
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.drools.ruleunits.api.SingletonStore;
+
+public record YaRDDefinitions(
+ Map> inputs,
+ List units,
+ Map> outputs) {
+
+ public Map evaluate(Map context) {
+ Map results = new LinkedHashMap<>(context);
+ for (String inputKey : inputs.keySet()) {
+ if (!context.containsKey(inputKey)) {
+ throw new IllegalArgumentException("Missing input key in context: " + inputKey);
+ }
+ Object inputValue = context.get(inputKey);
+ inputs.get(inputKey).set(inputValue);
+ }
+ for (Firable unit : units) {
+ unit.fire(context, this);
+ }
+ for (Entry> outputSets : outputs.entrySet()) {
+ results.put(outputSets.getKey(), outputSets.getValue().get());
+ }
+ reset();
+ return results;
+ }
+
+ private void reset() {
+ inputs.forEach((k, v) -> v.clear());
+ outputs.forEach((k, v) -> v.clear());
+ }
+}
diff --git a/kie-yard/kie-yard-core/src/main/java/org/kie/yard/core/YaRDParser.java b/kie-yard/kie-yard-core/src/main/java/org/kie/yard/core/YaRDParser.java
new file mode 100644
index 00000000000..e1bc1e53507
--- /dev/null
+++ b/kie-yard/kie-yard-core/src/main/java/org/kie/yard/core/YaRDParser.java
@@ -0,0 +1,137 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.yard.core;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Objects;
+
+import org.drools.ruleunits.api.DataSource;
+import org.kie.yard.api.model.DecisionLogic;
+import org.kie.yard.api.model.Element;
+import org.kie.yard.api.model.Input;
+import org.kie.yard.api.model.YaRD;
+import org.kie.yard.api.model.YaRD_YamlMapperImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class YaRDParser {
+
+ private static final Logger LOG = LoggerFactory.getLogger(YaRDParser.class);
+ private final YaRDDefinitions definitions = new YaRDDefinitions(new HashMap<>(), new ArrayList<>(), new HashMap<>());
+ private final YaRD model;
+ private final String yaml;
+
+ public YaRDParser(Reader reader) throws Exception {
+ yaml = read(reader);
+ model = getModel(yaml);
+ parse(yaml);
+ }
+
+ public YaRDParser(String yaml) throws IOException {
+ this.yaml = yaml;
+ model = getModel(yaml);
+ parse(yaml);
+ }
+
+ public YaRD getModel() {
+ return model;
+ }
+
+ public String getYaml() {
+ return yaml;
+ }
+
+ public YaRDDefinitions getDefinitions() {
+ return definitions;
+ }
+
+ private String read(Reader reader) throws Exception {
+ final StringBuilder fileData = new StringBuilder(1000);
+ char[] buf = new char[1024];
+ int numRead;
+ while ((numRead = reader.read(buf)) != -1) {
+ String readData = String.valueOf(buf,
+ 0,
+ numRead);
+ fileData.append(readData);
+ buf = new char[1024];
+ }
+ reader.close();
+ return fileData.toString();
+ }
+
+ private YaRD getModel(String yaml) throws IOException {
+ return new YaRD_YamlMapperImpl().read(yaml);
+ }
+
+ private YaRDDefinitions parse(String yaml) throws IOException {
+ final YaRD sd = new YaRD_YamlMapperImpl().read(yaml);
+ appendInputs(sd.getInputs());
+ appendUnits(sd.getElements());
+ return definitions;
+ }
+
+ private void appendUnits(List list) {
+ final List existingNames = new ArrayList<>();
+ for (Element hi : list) {
+ final String nameString = hi.getName();
+ if (existingNames.contains(nameString)) {
+ throw new IllegalArgumentException("Two element definitions with the same name are not allowed.");
+ } else {
+ existingNames.add(nameString);
+ }
+ LOG.debug("parsing {}", nameString);
+ final Firable decisionLogic = createDecisionLogic(nameString, hi.getLogic());
+ definitions.units().add(decisionLogic);
+ }
+ }
+
+ private Firable createDecisionLogic(String nameString, DecisionLogic decisionLogic) {
+ if (decisionLogic instanceof org.kie.yard.api.model.DecisionTable decisionTable) {
+ return new SyntheticRuleUnitWrapper(new DTableUnitBuilder(definitions, nameString, decisionTable).build());
+ } else if (decisionLogic instanceof org.kie.yard.api.model.LiteralExpression literalExpression) {
+ return new LiteralExpressionBuilder(model.getExpressionLang(), definitions, nameString, literalExpression).build();
+ } else {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+ }
+
+ private void appendInputs(List list) {
+ for (Input hi : list) {
+ String nameString = hi.getName();
+ @SuppressWarnings("unused")
+ Class> typeRef = processType(hi.getType());
+ definitions.inputs().put(nameString, DataSource.createSingleton());
+ }
+ }
+
+ private Class> processType(String string) {
+ switch (string) {
+ case "string":
+ case "number":
+ case "boolean":
+ default:
+ return Object.class;
+ }
+ }
+}
diff --git a/kie-yard/kie-yard-core/src/main/java/org/kie/yard/core/YaRDRunner.java b/kie-yard/kie-yard-core/src/main/java/org/kie/yard/core/YaRDRunner.java
new file mode 100644
index 00000000000..8f616bf382f
--- /dev/null
+++ b/kie-yard/kie-yard-core/src/main/java/org/kie/yard/core/YaRDRunner.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.yard.core;
+
+import java.io.IOException;
+import java.util.Map;
+
+import com.fasterxml.jackson.databind.json.JsonMapper;
+
+public class YaRDRunner {
+
+ private final YaRDDefinitions definitions;
+ private final JsonMapper jsonMapper = JsonMapper.builder().build();
+ private final String name;
+
+ public YaRDRunner(final String yaml) throws IOException {
+ final YaRDParser parser = new YaRDParser(yaml);
+ name = parser.getModel().getName();
+ definitions = parser.getDefinitions();
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Map evaluate(final Map map) {
+ return definitions.evaluate(map);
+ }
+
+ public String evaluate(String jsonInputCxt) throws Exception {
+ final Map inputContext = readJSON(jsonInputCxt);
+ return jsonMapper.writerWithDefaultPrettyPrinter().writeValueAsString(evaluate(inputContext));
+ }
+
+ @SuppressWarnings("unchecked")
+ private Map readJSON(final String json) {
+ try {
+ return jsonMapper.readValue(json, Map.class);
+ } catch (Exception e) {
+ throw new IllegalArgumentException("Failed to read JSON " + json, e);
+ }
+ }
+}
diff --git a/kie-yard/kie-yard-core/src/test/java/org/kie/yard/core/DomesticPackagePricesTest.java b/kie-yard/kie-yard-core/src/test/java/org/kie/yard/core/DomesticPackagePricesTest.java
new file mode 100644
index 00000000000..a7a94255c7a
--- /dev/null
+++ b/kie-yard/kie-yard-core/src/test/java/org/kie/yard/core/DomesticPackagePricesTest.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.yard.core;
+
+import java.util.Map;
+
+import com.fasterxml.jackson.databind.json.JsonMapper;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class DomesticPackagePricesTest
+ extends TestBase {
+
+ private static final String FILE_NAME = "/domestic-package-prices.yml";
+
+ @Test
+ public void testMPackage() throws Exception {
+ final String CTX = """
+ {
+ "Height":10,
+ "Width":10,
+ "Length": 10,
+ "Weight":10
+ }
+ """;
+ Map outputJSONasMap = evaluate(CTX, FILE_NAME);
+ assertEquals(6.9, ((Map) outputJSONasMap.get("Package")).get("Cost"));
+ assertEquals("M", ((Map) outputJSONasMap.get("Package")).get("Size"));
+ }
+
+ @Test
+ public void testLPackage() throws Exception {
+ final String CTX = """
+ {
+ "Height":12,
+ "Width":10,
+ "Length": 10,
+ "Weight":10
+ }
+ """;
+ Map outputJSONasMap = evaluate(CTX, FILE_NAME);
+ assertEquals(8.9, ((Map) outputJSONasMap.get("Package")).get("Cost"));
+ assertEquals("L", ((Map) outputJSONasMap.get("Package")).get("Size"));
+ }
+}
diff --git a/kie-yard/kie-yard-core/src/test/java/org/kie/yard/core/DublicateElementNameTest.java b/kie-yard/kie-yard-core/src/test/java/org/kie/yard/core/DublicateElementNameTest.java
new file mode 100644
index 00000000000..3f1228f4275
--- /dev/null
+++ b/kie-yard/kie-yard-core/src/test/java/org/kie/yard/core/DublicateElementNameTest.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.yard.core;
+
+import org.junit.jupiter.api.Test;
+
+import java.util.Map;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+public class DublicateElementNameTest
+ extends TestBase {
+
+ private static final String FILE_NAME = "/two-elements-with-duplicate-name.yml";
+
+ @Test
+ public void testNoDublicateNames() throws Exception {
+ final String CTX = """
+ {
+ "Age": 10
+ }
+ """;
+ assertThrows(IllegalArgumentException.class, () ->
+ evaluate(CTX, FILE_NAME)
+ );
+ }
+}
diff --git a/kie-yard/kie-yard-core/src/test/java/org/kie/yard/core/ExtraCostsTest.java b/kie-yard/kie-yard-core/src/test/java/org/kie/yard/core/ExtraCostsTest.java
new file mode 100644
index 00000000000..82b32982549
--- /dev/null
+++ b/kie-yard/kie-yard-core/src/test/java/org/kie/yard/core/ExtraCostsTest.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.yard.core;
+
+import java.util.Map;
+
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class ExtraCostsTest
+ extends TestBase {
+
+ private static final String FILE_NAME = "/extra-costs.yml";
+
+ @Test
+ public void testMPackage() throws Exception {
+ final String CTX = """
+ {
+ "Fragile":true,
+ "Package Tracking":true,
+ "Insurance":true,
+ "Package Type":"M"
+ }
+ """;
+ Map outputJSONasMap = evaluate(CTX, FILE_NAME);
+ assertThat(outputJSONasMap).hasFieldOrPropertyWithValue("Total cost of premiums", 40);
+ }
+}
diff --git a/kie-yard/kie-yard-core/src/test/java/org/kie/yard/core/InsuranceBasePriceTest.java b/kie-yard/kie-yard-core/src/test/java/org/kie/yard/core/InsuranceBasePriceTest.java
new file mode 100644
index 00000000000..86cc261fae0
--- /dev/null
+++ b/kie-yard/kie-yard-core/src/test/java/org/kie/yard/core/InsuranceBasePriceTest.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.yard.core;
+
+import java.util.Map;
+
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class InsuranceBasePriceTest
+ extends TestBase {
+
+ private static final String FILE_NAME = "/insurance-base-price.yml";
+
+ @Test
+ public void testScenario1() throws Exception {
+ final String CTX = """
+ {
+ "Age": 47,
+ "Previous incidents?": false
+ }
+ """;
+ Map outputJSONasMap = evaluate(CTX, FILE_NAME);
+ assertThat(outputJSONasMap).hasFieldOrPropertyWithValue("Base price", 500);
+ assertThat(outputJSONasMap).hasFieldOrPropertyWithValue("Downpayment", 50);
+ }
+
+ @Test
+ public void testScenario2() throws Exception {
+ final String CTX = """
+ {
+ "Age": 19,
+ "Previous incidents?": true
+ }
+ """;
+ Map outputJSONasMap = evaluate(CTX, FILE_NAME);
+ assertThat(outputJSONasMap).hasFieldOrPropertyWithValue("Base price", 1000);
+ assertThat(outputJSONasMap).hasFieldOrPropertyWithValue("Downpayment", 70);
+ }
+}
diff --git a/kie-yard/kie-yard-core/src/test/java/org/kie/yard/core/MVELJSONTest.java b/kie-yard/kie-yard-core/src/test/java/org/kie/yard/core/MVELJSONTest.java
new file mode 100644
index 00000000000..f69723e310c
--- /dev/null
+++ b/kie-yard/kie-yard-core/src/test/java/org/kie/yard/core/MVELJSONTest.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.yard.core;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class MVELJSONTest
+ extends TestBase {
+
+ private static final String FILE_NAME = "/mvel-json-dot-access.yml";
+
+ @Test
+ public void testMVELManagesJSONMaps() throws Exception {
+ final String CTX = """
+ {
+ "Work Address":true
+ }
+ """;
+ final Map output = evaluate(CTX, FILE_NAME);
+
+ final Map mailingAddress = (Map) output.get("Mailing Address");
+ assertEquals("Work Street", mailingAddress.get("Street"));
+ assertEquals(23, mailingAddress.get("Number"));
+
+ final List deliveryItemNames = (List) output.get("Delivery Item Names");
+ assertEquals(3, deliveryItemNames.size());
+ assertTrue(deliveryItemNames.contains("Work Shoes"));
+ assertTrue(deliveryItemNames.contains("Work Hat"));
+ assertTrue(deliveryItemNames.contains("Work Shirt"));
+
+ final Map JSONTest= (Map) output.get("JSON Test");
+ assertEquals("Best Company LTD", JSONTest.get("Company"));
+
+ final Map mapTest = (Map) output.get("Map Test");
+ assertEquals("Hello", mapTest.get("Map"));
+ }
+}
diff --git a/kie-yard/kie-yard-core/src/test/java/org/kie/yard/core/MVELLiteralExpressionInterpreterTest.java b/kie-yard/kie-yard-core/src/test/java/org/kie/yard/core/MVELLiteralExpressionInterpreterTest.java
new file mode 100644
index 00000000000..63227755699
--- /dev/null
+++ b/kie-yard/kie-yard-core/src/test/java/org/kie/yard/core/MVELLiteralExpressionInterpreterTest.java
@@ -0,0 +1,81 @@
+package org.kie.yard.core;
+
+import org.junit.jupiter.api.Test;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+public class MVELLiteralExpressionInterpreterTest {
+
+
+ private MVELLiteralExpressionInterpreter sum;
+ private YaRDDefinitions yardDefinitions;
+
+ void setUp(final String expression) {
+ sum = new MVELLiteralExpressionInterpreter("sum", QuotedExprParsed.from(expression));
+
+ final Map> outputs = new HashMap<>();
+ outputs.put("C", StoreHandle.of(5));
+ outputs.put("sum", StoreHandle.empty(Object.class));
+ yardDefinitions = new YaRDDefinitions(Collections.emptyMap(), Collections.EMPTY_LIST, outputs);
+
+ }
+
+ @Test
+ public void testSum() {
+
+ setUp("1+1");
+
+ final int fire = sum.fire(Collections.emptyMap(), yardDefinitions);
+
+ assertEquals(1, fire);
+ assertEquals(2, yardDefinitions.outputs().get("sum").get());
+ }
+
+ @Test
+ public void testOutputVar() {
+
+ setUp("Math.max(C, 1)");
+
+ final int fire = sum.fire(Collections.emptyMap(), yardDefinitions);
+
+ assertEquals(1, fire);
+ assertEquals(5, yardDefinitions.outputs().get("sum").get());
+ }
+
+ @Test
+ public void testContext() {
+
+ setUp("A+B");
+
+ final Map context = new HashMap<>();
+ context.put("A", 1);
+ context.put("B", 2);
+ final int fire = sum.fire(context, yardDefinitions);
+
+ assertEquals(1, fire);
+ assertEquals(3, yardDefinitions.outputs().get("sum").get());
+ }
+
+ @Test
+ public void testMaps() {
+
+ setUp("person.address.street + ' ' + person.address.number");
+
+ final Map context = new HashMap<>();
+ final Map person = new HashMap<>();
+ final Map address = new HashMap<>();
+ address.put("street", "My Street");
+ address.put("number", 12);
+ person.put("address", address);
+ context.put("person", person);
+ final int fire = sum.fire(context, yardDefinitions);
+
+ assertEquals(1, fire);
+ assertEquals("My Street 12", yardDefinitions.outputs().get("sum").get());
+ }
+}
\ No newline at end of file
diff --git a/kie-yard/kie-yard-core/src/test/java/org/kie/yard/core/TestBase.java b/kie-yard/kie-yard-core/src/test/java/org/kie/yard/core/TestBase.java
new file mode 100644
index 00000000000..e18ac182ba6
--- /dev/null
+++ b/kie-yard/kie-yard-core/src/test/java/org/kie/yard/core/TestBase.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.yard.core;
+
+import java.io.IOException;
+import java.util.Map;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.json.JsonMapper;
+import org.drools.util.IoUtils;
+
+public class TestBase {
+
+ private JsonMapper jsonMapper = JsonMapper.builder().build();
+
+ protected Map evaluate(String jsonInputCxt, String file) throws Exception {
+ final String yamlDecision = read(file);
+ final String OUTPUT_JSON = new YaRDRunner(yamlDecision).evaluate(jsonInputCxt);
+ return readJSON(OUTPUT_JSON);
+ }
+
+ private String read(String file) throws IOException {
+ return new String(IoUtils.readBytesFromInputStream(this.getClass().getResourceAsStream(file), true));
+ }
+
+ @SuppressWarnings("unchecked")
+ private Map readJSON(final String CONTEXT) throws JsonProcessingException {
+ return jsonMapper.readValue(CONTEXT, Map.class);
+ }
+}
diff --git a/kie-yard/kie-yard-core/src/test/resources/domestic-package-prices.yml b/kie-yard/kie-yard-core/src/test/resources/domestic-package-prices.yml
new file mode 100644
index 00000000000..7f5257613b3
--- /dev/null
+++ b/kie-yard/kie-yard-core/src/test/resources/domestic-package-prices.yml
@@ -0,0 +1,29 @@
+specVersion: alpha
+kind: YaRD
+name: "Traffic Violation"
+inputs:
+ - name: "Length"
+ type: integer
+ - name: "Width"
+ type: number
+ - name: "Height"
+ type: number
+ - name: "Weight"
+ type: number
+elements:
+ - name: Package
+ type: Decision
+ logic:
+ type: DecisionTable
+ # First matching result will be picked
+ hitPolicy: FIRST
+ inputs: [ "Height", "Width", "Length", "Weight" ]
+ rules:
+ - when: [ '<= 3', '<= 25','<= 35', '<= 2' ]
+ then: '{ "Size": "S", "Cost": 5.90 }'
+ - when: [ '<= 11','<= 32','<= 42', '<=25' ]
+ then: '{ "Size": "M", "Cost": 6.90 }'
+ - when: [ '<= 19', '<= 36', '<= 60', '<= 25' ]
+ then: '{ "Size": "L", "Cost": 8.90 }'
+ - when: [ '<= 37', '<= 36', '<= 60', '<= 25' ]
+ then: '{ "Size": "XL", "Cost": 10.90}'
\ No newline at end of file
diff --git a/kie-yard/kie-yard-core/src/test/resources/extra-costs.yml b/kie-yard/kie-yard-core/src/test/resources/extra-costs.yml
new file mode 100644
index 00000000000..6c16d351a3a
--- /dev/null
+++ b/kie-yard/kie-yard-core/src/test/resources/extra-costs.yml
@@ -0,0 +1,47 @@
+specVersion: alpha
+kind: YaRD
+name: "Traffic Violation"
+expressionLang: jshell
+inputs:
+ - name: Fragile
+ type: boolean
+ - name: Package Tracking
+ type: boolean
+ - name: Insurance
+ type: boolean
+ - name: Package Type
+ type: string
+elements:
+ - name: Selected premiums
+ type: Decision
+ logic:
+ type: DecisionTable
+ # Collect all costs
+ hitPolicy: COLLECT
+ inputs: [ Package Type, Fragile, Package Tracking, Insurance ]
+ rules:
+ # Insurance for all packages, based on size and if the content is fragile
+ - when: [ 'S', true, "-", true ]
+ then: '{ "Name": "Fragile insurance cost", "Price": 10}'
+ - when: [ 'M', true, "-", true ]
+ then: '{ "Name": "Fragile insurance cost", "Price": 20}'
+ - when: [ 'L', true, "-", true ]
+ then: '{ "Name": "Fragile insurance cost", "Price": 30}'
+ - when: [ 'XL', true, "-", true ]
+ then: '{ "Name": "Fragile insurance cost", "Price": 40}'
+ - when: [ "-", false, "-", true ]
+ then: '{ "Name": "Regular insurance cost", "Price": 5}'
+ # Tracking cost is same for all sizes
+ - when: [ "-", "-", true, "-" ]
+ then: '{ "Name": "Tracking cost", "Price": 5}'
+ # Fragile package extra care cost
+ - when: [ "-", true, "-", "-" ]
+ then: '{ "Name": "Fragile package shipping cost", "Price": 15}'
+ - name: "Total cost of premiums"
+ type: Decision
+ logic:
+ type: LiteralExpression
+ expression: |
+ ((java.util.List>)`Selected premiums`).stream().map(m -> m.get("Price")).mapToInt(Integer::valueOf).sum();
+# Feels filthy compared to FEEL below
+# expression: 'sum( for item in Selected premiums return item.Price )'
diff --git a/kie-yard/kie-yard-core/src/test/resources/insurance-base-price.yml b/kie-yard/kie-yard-core/src/test/resources/insurance-base-price.yml
new file mode 100644
index 00000000000..263fd92883d
--- /dev/null
+++ b/kie-yard/kie-yard-core/src/test/resources/insurance-base-price.yml
@@ -0,0 +1,29 @@
+specVersion: alpha
+kind: YaRD
+name: 'BasePrice'
+inputs:
+ - name: 'Age'
+ type: number
+ - name: 'Previous incidents?'
+ type: boolean
+elements:
+ - name: 'Base price'
+ type: Decision
+ logic:
+ type: DecisionTable
+ inputs: [ 'Age', 'Previous incidents?' ]
+ rules:
+ - when: [ '<21', false ]
+ then: 800
+ - when: [ '<21', true ]
+ then: 1000
+ - when: [ '>=21', false ]
+ then: 500
+ - when: [ '>=21', true ]
+ then: 600
+ - name: 'Downpayment'
+ type: Decision
+ logic:
+ type: LiteralExpression
+ expression: |
+ Math.max(`Base price` * 0.07, 50)
diff --git a/kie-yard/kie-yard-core/src/test/resources/mvel-json-dot-access.yml b/kie-yard/kie-yard-core/src/test/resources/mvel-json-dot-access.yml
new file mode 100644
index 00000000000..3bd073033dc
--- /dev/null
+++ b/kie-yard/kie-yard-core/src/test/resources/mvel-json-dot-access.yml
@@ -0,0 +1,57 @@
+specVersion: alpha
+kind: YaRD
+name: "Testing MVEL"
+inputs:
+ - name: Work Address
+ type: boolean
+elements:
+ - name: JSON Test
+ type: Decision
+ logic:
+ type: LiteralExpression
+ expression: |
+ '{ "Company": "Best Company LTD" }'
+ - name: Map Test
+ type: Decision
+ logic:
+ type: LiteralExpression
+ expression: |
+ [ "Map": "Hello" ]
+ - name: Delivery Items
+ type: Decision
+ logic:
+ type: DecisionTable
+ hitPolicy: COLLECT
+ inputs: [ 'Work Address']
+ rules:
+ - when: [ true ]
+ then: '{ "Item": { "Name": "Work Shoes" } }'
+ - when: [ true ]
+ then: '{ "Item": { "Name": "Work Hat" } }'
+ - when: [ true ]
+ then: '{ "Item": { "Name": "Work Shirt" } }'
+ - when: [ false ]
+ then: '{ "Item": { "Name": "Holiday Hat" } }'
+ - name: Customer
+ type: Decision
+ logic:
+ type: DecisionTable
+ hitPolicy: ANY
+ inputs: [ 'Work Address']
+ rules:
+ - when: [ true ]
+ then: '{ "Address": { "Street": "Work Street", "Number": 23 } }'
+ - when: [ false ]
+ then: '{ "Address": { "Street": "Free Time Path", "Number": 123 } }'
+ - name: Mailing Address
+ type: Decision
+ logic:
+ type: LiteralExpression
+ expression: |
+ Customer.Address
+ - name: Delivery Item Names
+ type: Decision
+ logic:
+ type: LiteralExpression
+ expression: |
+ ( Item.Name in `Delivery Items` )
diff --git a/kie-yard/kie-yard-core/src/test/resources/scorecards/README-health-card.yml b/kie-yard/kie-yard-core/src/test/resources/scorecards/README-health-card.yml
new file mode 100644
index 00000000000..8f79686f2d6
--- /dev/null
+++ b/kie-yard/kie-yard-core/src/test/resources/scorecards/README-health-card.yml
@@ -0,0 +1,47 @@
+specVersion: alpha
+kind: YaRD
+name: "Git Repository Completeness"
+expressionLang: jshell
+inputs:
+ - name: "README"
+ type: string
+ - name: "Web Page Link"
+ type: string
+ - name: "Documentation Link"
+ type: string
+elements:
+ - name: Has README.md file
+ type: Decision
+ logic:
+ type: LiteralExpression
+ expression: |
+ `README` != null
+ - name: README has link to web page
+ type: Decision
+ logic:
+ type: LiteralExpression
+ expression: |
+ `README`.contains( `Web Page Link` )
+ - name: README has a link to documentation
+ type: Decision
+ logic:
+ type: LiteralExpression
+ expression: |
+ `README`.contains( `Documentation Link` )
+ - name: README has a title for 'How to contribute'
+ type: Decision
+ logic:
+ type: LiteralExpression
+ expression: |
+ `README`.contains( "#How to contribute" )
+ - name: Score
+ type: Decision
+ logic:
+ type: DecisionTable
+ hitPolicy: COLLECT COUNT
+ inputs: [ "true == {0}" ]
+ rules:
+ - [ "Has README.md file" ]
+ - [ "README has link to web page" ]
+ - [ "README has a link to documentation" ]
+ - [ "README has a title for 'How to contribute'" ]
diff --git a/kie-yard/kie-yard-core/src/test/resources/scorecards/README.md b/kie-yard/kie-yard-core/src/test/resources/scorecards/README.md
new file mode 100644
index 00000000000..0bfe8deb30c
--- /dev/null
+++ b/kie-yard/kie-yard-core/src/test/resources/scorecards/README.md
@@ -0,0 +1,8 @@
+Not used by any tests at this point. Used as drafts for upcoming features.
+
+Each YaRD yml file is a scorecard and has to return a value "Score".
+Depending on the draft:
+
+* The Score is either a % between 0 and 100.
+* The Score is calculated from previous expressions, each expression has to return true or it is considered a failure
+
diff --git a/kie-yard/kie-yard-core/src/test/resources/scorecards/branch-responsibilities.yml b/kie-yard/kie-yard-core/src/test/resources/scorecards/branch-responsibilities.yml
new file mode 100644
index 00000000000..f0e9ee96f49
--- /dev/null
+++ b/kie-yard/kie-yard-core/src/test/resources/scorecards/branch-responsibilities.yml
@@ -0,0 +1,38 @@
+specVersion: alpha
+kind: YaRD
+name: "Branch responsibilities"
+expressionLang: jshell
+inputs:
+ - name: "Main POM"
+ type: 'http://myapi.org/jsonSchema.json#POM'
+ - name: "Latest Tag POM"
+ type: 'http://myapi.org/jsonSchema.json#POM'
+elements:
+ - name: Main is set on SNAPSHOT
+ type: Decision
+ logic:
+ type: LiteralExpression
+ expression: |
+ `Main POM`.version.endsWith("-SNAPSHOT")
+ - name: Main version is higher than latest Tag
+ type: Decision
+ logic:
+ type: LiteralExpression
+ expression: |
+ `Main POM`.version > `Latest Tag POM`.version
+ - name: Tag is not on SNAPSHOT
+ type: Decision
+ logic:
+ type: LiteralExpression
+ expression: |
+ !`Latest Tag POM`.version.endWith("-SNAPSHOT")
+ - name: Score
+ type: Decision
+ logic:
+ type: DecisionTable
+ hitPolicy: COLLECT COUNT
+ inputs: [ "true == {0}" ] # this is not in the current spec, neither is inserting the values below
+ rules:
+ - [ 'Main is set on SNAPSHOT' ]
+ - [ 'Main version is higher than latest Tag' ]
+ - [ 'Tag is not on SNAPSHOT' ]
\ No newline at end of file
diff --git a/kie-yard/kie-yard-core/src/test/resources/scorecards/drafts/branch-blocked-card.yml b/kie-yard/kie-yard-core/src/test/resources/scorecards/drafts/branch-blocked-card.yml
new file mode 100644
index 00000000000..0b4a085bf85
--- /dev/null
+++ b/kie-yard/kie-yard-core/src/test/resources/scorecards/drafts/branch-blocked-card.yml
@@ -0,0 +1,21 @@
+specVersion: alpha
+kind: YaRD
+name: "Main broken"
+expressionLang: jshell
+inputs:
+ - name: "Creator"
+ type: string
+ - name: "Created"
+ type: datetime
+ - name: "Closed"
+ type: datetime
+ - name: "Severity"
+# How long was branch broken
+# Was the correct protocol followed, what ever that is
+elements:
+ - name: Time Taken to Ack
+ type: Decision
+ logic:
+ type: LiteralExpression
+ expression: |
+ `Reported` -`Acked`
diff --git a/kie-yard/kie-yard-core/src/test/resources/scorecards/drafts/closed-prs-card.yml b/kie-yard/kie-yard-core/src/test/resources/scorecards/drafts/closed-prs-card.yml
new file mode 100644
index 00000000000..578330c2adb
--- /dev/null
+++ b/kie-yard/kie-yard-core/src/test/resources/scorecards/drafts/closed-prs-card.yml
@@ -0,0 +1,23 @@
+specVersion: alpha
+kind: YaRD
+name: "Closed PRs"
+expressionLang: jshell
+inputs:
+ - name: "Creator"
+ type: string
+ - name: "Created"
+ type: datetime
+ - name: "Closed"
+ type: datetime
+ - name: "Severity"
+# Another one for closed PRs?
+# Gap check
+# Reviewers acked
+# Code smells and so on were in check
+elements:
+ - name: Time Taken to Ack
+ type: Decision
+ logic:
+ type: LiteralExpression
+ expression: |
+ `Reported` -`Acked`
diff --git a/kie-yard/kie-yard-core/src/test/resources/scorecards/drafts/open-prs-card.yml b/kie-yard/kie-yard-core/src/test/resources/scorecards/drafts/open-prs-card.yml
new file mode 100644
index 00000000000..b0eed257ea5
--- /dev/null
+++ b/kie-yard/kie-yard-core/src/test/resources/scorecards/drafts/open-prs-card.yml
@@ -0,0 +1,21 @@
+specVersion: alpha
+kind: YaRD
+name: "Open PRs"
+expressionLang: jshell
+inputs:
+ - name: "Creator"
+ type: string
+ - name: "Created"
+ type: datetime
+ - name: "Closed"
+ type: datetime
+ - name: "Severity"
+# Check they have 2 reviewers set, open - close gap is scored based on length
+# Tests are ran, code smells minimal
+elements:
+ - name: Time Taken to Ack
+ type: Decision
+ logic:
+ type: LiteralExpression
+ expression: |
+ `Reported` -`Acked`
diff --git a/kie-yard/kie-yard-core/src/test/resources/scorecards/drafts/weekly-branch-health-card.yml b/kie-yard/kie-yard-core/src/test/resources/scorecards/drafts/weekly-branch-health-card.yml
new file mode 100644
index 00000000000..5bee4356941
--- /dev/null
+++ b/kie-yard/kie-yard-core/src/test/resources/scorecards/drafts/weekly-branch-health-card.yml
@@ -0,0 +1,22 @@
+specVersion: alpha
+kind: YaRD
+name: "Main broken"
+expressionLang: jshell
+inputs:
+ - name: "Creator"
+ type: string
+ - name: "Created"
+ type: datetime
+ - name: "Closed"
+ type: datetime
+ - name: "Severity"
+# Times the nightlies failed
+# Amount of test failures
+# Build failures
+elements:
+ - name: Time Taken to Ack
+ type: Decision
+ logic:
+ type: LiteralExpression
+ expression: |
+ `Reported` -`Acked`
diff --git a/kie-yard/kie-yard-core/src/test/resources/scorecards/git-repository-health-card.yml b/kie-yard/kie-yard-core/src/test/resources/scorecards/git-repository-health-card.yml
new file mode 100644
index 00000000000..af056f36905
--- /dev/null
+++ b/kie-yard/kie-yard-core/src/test/resources/scorecards/git-repository-health-card.yml
@@ -0,0 +1,56 @@
+specVersion: alpha
+kind: YaRD
+name: "Git Repository Completeness"
+expressionLang: jshell
+inputs:
+ - name: "Repository Data"
+ type: 'http://myapi.org/jsonSchema.json#GitRepositoryData'
+elements:
+ - name: Has Owners
+ type: Decision
+ logic:
+ type: LiteralExpression
+ expression: |
+ `Git Data`.owners.size > 0
+ - name: Has Description
+ type: Decision
+ logic:
+ type: LiteralExpression
+ expression: |
+ !`Git Data`.description.trim.isEmpty()
+ - name: Code of Conduct is Set
+ type: Decision
+ logic:
+ type: LiteralExpression
+ expression: |
+ `Git Data`.codeOfConduct != null
+ && !`Git Data`.codeOfConduct.trim.isEmpty()
+ - name: Security Information is Set
+ type: Decision
+ logic:
+ type: LiteralExpression
+ expression: |
+ `Git Data`.securityInformation != null
+ && !`Git Data`.securityInformation.trim.isEmpty()
+ - name: Weighted Score
+ type: Decision
+ logic:
+ type: DecisionTable
+ hitPolicy: COLLECT
+ inputs: [ "true == {0}" ]
+ outputComponents: [ "Line Score" ]
+ rules:
+ - when: [ 'Has Owners' ]
+ then: 4
+ - when: [ 'Has Description' ]
+ then: 1
+ - when: [ 'Code of Conduct is Set' ]
+ then: 4
+ - when: [ 'Security Information is Set' ]
+ then: 2
+ - name: Score
+ type: Decision
+ logic:
+ type: LiteralExpression
+ expression: |
+ `Weighted Score`.stream.mapToInt(Integer::intValue).sum();
\ No newline at end of file
diff --git a/kie-yard/kie-yard-core/src/test/resources/scorecards/resource-limits-card.yml b/kie-yard/kie-yard-core/src/test/resources/scorecards/resource-limits-card.yml
new file mode 100644
index 00000000000..984f4fcf319
--- /dev/null
+++ b/kie-yard/kie-yard-core/src/test/resources/scorecards/resource-limits-card.yml
@@ -0,0 +1,40 @@
+specVersion: alpha
+kind: YaRD
+name: "Resource Limits"
+expressionLang: jshell
+inputs:
+ - name: "CPU Count"
+ type: number
+ - name: "Memory Use"
+ type: number
+ - name: "Run Started"
+ type: datetime
+ - name: "Run Ended"
+ type: datetime
+elements:
+ - name: Run Time
+ type: Decision
+ logic:
+ type: LiteralExpression
+ # With JShell this does not work, but this can be done with a Java oneliner
+ expression: |
+ `Run Started` -`Run Ended`
+ - name: Fitting profiles
+ type: Decision
+ logic:
+ type: DecisionTable
+ hitPolicy: COLLECT
+ inputs: [ "Run Time", "Memory Use", "CPU Count" ]
+ # This assumes there are set profiles that include the above parameters
+ # How well we meet them is visualized in the score
+ rules:
+ - when: [ '<=30m', '<=20', '<=1' ] # Low profile
+ then: 4
+ - when: [ '<=3h00m', '<=40', '<=1' ] # Medium
+ then: 3
+ - when: [ '<=4h00m', '<=50', '<=1' ] # High
+ then: 2
+ - when: [ '<=2h30m', '<=60', '<=1' ] # Ultra
+ then: 1
+ - when: [ '-', '-', '-' ] # Unacceptable
+ then: 0
diff --git a/kie-yard/kie-yard-core/src/test/resources/ticket-score-cards.yml b/kie-yard/kie-yard-core/src/test/resources/ticket-score-cards.yml
new file mode 100644
index 00000000000..2dd17e66597
--- /dev/null
+++ b/kie-yard/kie-yard-core/src/test/resources/ticket-score-cards.yml
@@ -0,0 +1,45 @@
+specVersion: alpha
+kind: YaRD
+name: "Traffic Violation"
+inputs:
+ - name: "Tickets"
+ type: List
+elements:
+ - name: Incident was ack'd within 3 minutes
+ type: Decision
+ logic:
+ type: LiteralExpression
+ expression: |
+ `Tickets`.stream().allMatch(t -> TimeUnit.MINUTES.convert(t.reported.getTime() - t.acked.getTime(), TimeUnit.MILLISECONDS) <= 3 );
+ - name: Incident was resolved within 5 minutes
+ type: Decision
+ logic:
+ type: LiteralExpression
+ expression: |
+ `Tickets`.stream().allMatch(t -> TimeUnit.MINUTES.convert(t.reported.getTime() - t.resolved.getTime(), TimeUnit.MILLISECONDS) <= 5 );
+ - name: Bronze Level
+ type: Decision
+ logic:
+ type: DecisionTable
+ hitPolicy: COLLECT COUNT
+ inputs: [ "Incident was ack'd within 3 minutes", "Incident was resolved within 5 minutes" ]
+ rules:
+ - [ true, '-' ]
+ - [ '-', true ]
+ - name: Bronze Complete
+ type: Decision
+ logic:
+ type: LiteralExpression
+ expression: `Bronze Level` == 2
+ - name: Level
+ type: Decision
+ logic:
+ type: DecisionTable
+ hitPolicy: ANY
+ inputs: [ "Bronze Complete", "Silver Complete", "Gold Complete" ]
+ outputComponents: [ "Level" ]
+ # To reach the next level, previous one has to be fully completed
+ rules:
+ - [ true, true, true, 'Gold' ]
+ - [ true, true, false, 'Silver' ]
+ - [ true, false, false, 'Bronze' ]
diff --git a/kie-yard/kie-yard-core/src/test/resources/two-elements-with-duplicate-name.yml b/kie-yard/kie-yard-core/src/test/resources/two-elements-with-duplicate-name.yml
new file mode 100644
index 00000000000..7f954a64bb5
--- /dev/null
+++ b/kie-yard/kie-yard-core/src/test/resources/two-elements-with-duplicate-name.yml
@@ -0,0 +1,19 @@
+specVersion: alpha
+kind: YaRD
+name: 'BasePrice'
+inputs:
+ - name: Age
+ type: number
+elements:
+ - name: Ten
+ type: Decision
+ logic:
+ type: LiteralExpression
+ expression: |
+ 10
+ - name: Ten
+ type: Decision
+ logic:
+ type: LiteralExpression
+ expression: |
+ 5 + 5
diff --git a/kie-yard/pom.xml b/kie-yard/pom.xml
new file mode 100644
index 00000000000..185b4a36d00
--- /dev/null
+++ b/kie-yard/pom.xml
@@ -0,0 +1,59 @@
+
+
+
+
+ 4.0.0
+
+
+ org.kie
+ drools-build-parent
+ 999-SNAPSHOT
+ ../build-parent/pom.xml
+
+
+ kie-yard
+ pom
+
+ KIE :: Yet Another Rule Definition
+
+ A simple way to describe declarative Decisions and Rules in YAML.
+
+
+
+ kie-yard-api
+ kie-yard-core
+
+
+
+
+
+ org.kie
+ kie-yard-bom
+ ${project.version}
+ pom
+ import
+
+
+
+
+
diff --git a/pom.xml b/pom.xml
index 7dcdf4c004e..fa6b5bd7b7f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -206,6 +206,7 @@
efesto
kie-drl
kie-dmn
+ kie-yard
kie-pmml-trusty
kie-maven-plugin
kie-archetypes