### Initial FEEL String Expression Example Source: https://github.com/camunda/feel-scala/blob/main/docs/versioned_docs/version-1.21/learn/challenge/chapter-4.mdx This is an initial setup for a FEEL string expression. It shows how to start concatenating the 'firstName' variable. Ensure 'firstName' and 'lastName' are defined in the FEEL context. ```feel // concatenate the first and the last name firstName ``` -------------------------------- ### Install Project Dependencies Source: https://github.com/camunda/feel-scala/blob/main/docs/README.md Installs the necessary dependencies for the project using yarn. ```bash yarn install ``` -------------------------------- ### Start Local Development Server Source: https://github.com/camunda/feel-scala/blob/main/docs/README.md Starts a local development server that automatically refreshes the browser on code changes. This is useful for active development. ```bash yarn start ``` -------------------------------- ### Start Documentation Development Server Source: https://github.com/camunda/feel-scala/blob/main/CONTRIBUTING.md Use this command to build and serve the documentation with auto-reloading for development. ```bash npm run start ``` -------------------------------- ### Start the FEEL REPL Source: https://github.com/camunda/feel-scala/blob/main/docs/versioned_docs/version-1.21/playground/repl.md Launches the FEEL REPL environment using Ammonite and the feel-repl.sc script. ```shell amm --predef feel-repl.sc ``` -------------------------------- ### Install Ammonite on Linux Source: https://github.com/camunda/feel-scala/blob/main/docs/versioned_docs/version-1.21/playground/repl.md Installs Ammonite REPL on Linux systems using a shell script. ```shell sudo sh -c '(echo "#!/usr/bin/env sh" && curl -L https://github.com/com-lihaoyi/Ammonite/releases/download/2.4.0/2.13-2.4.0) > /usr/local/bin/amm && chmod +x /usr/local/bin/amm' && amm ``` -------------------------------- ### Install Ammonite on Mac Source: https://github.com/camunda/feel-scala/blob/main/docs/versioned_docs/version-1.21/playground/repl.md Installs Ammonite REPL on Mac systems using Homebrew. ```shell brew install ammonite-repl ``` -------------------------------- ### Greet Zee with FEEL Source: https://github.com/camunda/feel-scala/blob/main/docs/versioned_docs/version-1.21/learn/challenge/challenge.mdx Use this interactive editor to evaluate a simple FEEL expression and greet Zee. This is the starting point of the challenge. ```feel "Hello Zee" ``` -------------------------------- ### Conventional Commit Example Source: https://github.com/camunda/feel-scala/blob/main/CONTRIBUTING.md An example of a commit message following the Conventional Commits format, including a type, scope, and description. ```git feat: add random() function * add new built-in function random() * it returns a random number between 0.0 and 1.0 ``` -------------------------------- ### Python Syntax Highlighting Source: https://github.com/camunda/feel-scala/blob/main/docs/cheat-sheets/markdown-cheat-sheet.md Example of Python code block with syntax highlighting. ```python s = "Python syntax highlighting" print(s) ``` -------------------------------- ### JavaScript Syntax Highlighting Source: https://github.com/camunda/feel-scala/blob/main/docs/cheat-sheets/markdown-cheat-sheet.md Example of JavaScript code block with syntax highlighting. ```javascript var s = 'JavaScript syntax highlighting'; alert(s); ``` -------------------------------- ### Scala: Configure FEEL Engine Source: https://github.com/camunda/feel-scala/blob/main/docs/versioned_docs/version-1.21/developer-guide/bootstrapping.md Configure the FEEL engine during instantiation, for example, to enable external functions. ```scala new FeelEngine(configuration = Configuration(externalFunctionsEnabled = true)) ``` -------------------------------- ### Calculate Arrival Time with Modulo Source: https://github.com/camunda/feel-scala/blob/main/docs/versioned_docs/version-1.21/learn/challenge/chapter-3.mdx Use the modulo function to calculate the arrival time on a 24-hour clock, considering the total hours and a starting hour. This is useful for scenarios where you need to determine the exact time of day an event will conclude. ```feel // use a 24 hour clock hours + startingHour ``` ```feel modulo((hours + startingHour), modulus) ``` -------------------------------- ### Define and Use a React Component in MDX Source: https://github.com/camunda/feel-scala/blob/main/docs/cheat-sheets/mdx-cheat-sheet.md Define a React component using JSX syntax and then use it within your Markdown content. This example shows how to create a reusable component with props for styling. ```jsx export const Highlight = ({children, color}) => ( {children} ) ``` ```mdx Docusaurus green and Facebook blue are my favorite colors. ``` -------------------------------- ### Implement New Built-in Function Source: https://github.com/camunda/feel-scala/blob/main/CONTRIBUTING.md Example of implementing a new built-in function 'reverse' in Scala, including parameter definition and invocation logic. ```scala builtinFunction("reverse", List("value")) { case List(ValString(value)) => ValString(value.reverse) } ``` -------------------------------- ### Calculate Time Elapsed with Temporal Math Source: https://github.com/camunda/feel-scala/blob/main/docs/versioned_docs/version-1.21/learn/challenge/chapter-5.mdx Use temporal math to calculate the time elapsed since a starting date, considering a duration in hours. This is useful for tracking progress or time passed. ```feel // use temporal math to calculate the remaining days date(startingDate) + duration("PT200H") ``` -------------------------------- ### Filter List and Get First Element Source: https://github.com/camunda/feel-scala/blob/main/docs/versioned_docs/version-1.21/learn/samples/list-samples.md Retrieves the first element from a list that matches a specific criterion. Ensure the data structure and attribute names match the expression. ```js (data.attribute.packaging[unit = "Palette"])[1] ``` -------------------------------- ### Implement Custom Value Mapper in Java Source: https://github.com/camunda/feel-scala/blob/main/docs/versioned_docs/version-1.21/developer-guide/value-mapper-spi.md Subclass `JavaCustomValueMapper` for Java-based custom value mapping. Override `toValue` and `unpackValue` to handle transformations. The `priority` method determines the mapper's precedence. This example maps `Custom` to `ValString` and `ValNumber` to `Double`. ```java public class CustomJavaValueMapper extends JavaCustomValueMapper { @Override public Optional toValue(Object x, Function innerValueMapper) { if (x instanceof Custom) { final Custom c = (Custom) x; return Optional.of(new ValString(c.getName())); } else { return Optional.empty(); } } @Override public Optional unpackValue(Val value, Function innerValueMapper) { if (value instanceof ValNumber) { final ValNumber number = (ValNumber) value; return Optional.of(number.value().doubleValue()); // map BigDecimal to Double } else { return Optional.empty(); } } @Override public int priority() { return 1; } } ``` -------------------------------- ### Calculate Remaining Days Until Event Source: https://github.com/camunda/feel-scala/blob/main/docs/versioned_docs/version-1.21/learn/challenge/chapter-5.mdx Calculate the number of days remaining until a target date by subtracting the elapsed time from the total duration between the start and target dates. This is useful for event planning and countdowns. ```feel (date(targetDate) - date(startingDate) - duration("PT200H")) / duration("P1D") ``` -------------------------------- ### Implement Custom Value Mapper in Scala Source: https://github.com/camunda/feel-scala/blob/main/docs/versioned_docs/version-1.21/developer-guide/value-mapper-spi.md Subclass `CustomValueMapper` to transform objects to FEEL `Val` types and vice-versa. Set the `priority` to define precedence. This example maps a `Custom` object to a `ValString` and a `ValNumber` to a `Double`. ```scala class MyValueMapper extends CustomValueMapper { override def toVal(x: Any, innerValueMapper: Any => Val): Option[Val] = x match { case c: Custom => Some(ValString(c.getName)) case _ => None } override def unpackVal(value: Val, innerValueMapper: Val => Any): Option[Any] = value match { case ValNumber(number) => Some(number.doubleValue) // map BigDecimal to Double case _ => None } override val priority: Int = 1 } ``` -------------------------------- ### Build JAR Files with Maven Source: https://github.com/camunda/feel-scala/blob/main/CONTRIBUTING.md Build the project's JAR files using Maven. ```bash mvn install ``` -------------------------------- ### Deploy Website to GitHub Pages Source: https://github.com/camunda/feel-scala/blob/main/docs/README.md Builds the website and pushes the output to the 'gh-pages' branch, specifically for deployment on GitHub Pages. Ensure you replace '' with your actual username. ```bash GIT_USER= USE_SSH=true yarn deploy ``` -------------------------------- ### Java: Configure FEEL Engine Source: https://github.com/camunda/feel-scala/blob/main/docs/versioned_docs/version-1.21/developer-guide/bootstrapping.md Configure the FEEL engine using the builder pattern, for instance, to enable external functions. ```java new FeelEngine.Builder().enableExternalFunctions(true).build() ``` -------------------------------- ### Java: Evaluate FEEL Expressions Source: https://github.com/camunda/feel-scala/blob/main/docs/versioned_docs/version-1.21/developer-guide/bootstrapping.md Use the FeelEngine builder to create an instance and evaluate FEEL expressions with a given context. Handles results or failures. ```java public class MyProgram { public static void main(String[] args) { final FeelEngine engine = new FeelEngine.Builder() .valueMapper(SpiServiceLoader.loadValueMapper()) .functionProvider(SpiServiceLoader.loadFunctionProvider()) .build(); final Map variables = Map.of("x", 21); final Either result = engine.evalExpression(expression, variables); if (result.isRight()) { final Object value = result.right().get(); System.out.println("result is " + value); } else { final FeelEngine.Failure failure = result.left().get(); throw new RuntimeException(failure.message()); } } } ``` -------------------------------- ### Run Tests with Maven Source: https://github.com/camunda/feel-scala/blob/main/CONTRIBUTING.md Execute all project tests using Maven. ```bash mvn test ``` -------------------------------- ### Build Static Website Content Source: https://github.com/camunda/feel-scala/blob/main/docs/README.md Generates the static content for the website, typically placed in the 'build' directory. This output can be hosted on any static content hosting service. ```bash yarn build ``` -------------------------------- ### Evaluate FEEL Expressions Source: https://github.com/camunda/feel-scala/blob/main/docs/versioned_docs/version-1.21/playground/repl.md Demonstrates evaluating FEEL expressions using the 'feel' function in the REPL, with and without context. ```scala feel("1 + 3") // evaluate an expression without any context ``` ```scala val context = Map("x" -> 3) feel("1 + x", context) // evaluate an expression with a map-based context ``` ```scala feel("1 + x", "{ \"x\": 3}") // evaluate an expression with a JSON context ``` ```scala feel("\"date(\"2020-04-06\") + duration(\"P3D\")\"") // evaluate an expression ignoring any quotes in the expression ``` -------------------------------- ### Scala: Evaluate FEEL Expressions Source: https://github.com/camunda/feel-scala/blob/main/docs/versioned_docs/version-1.21/developer-guide/bootstrapping.md Instantiate the FeelEngine and use its API to evaluate FEEL expressions or unary tests with a given context. ```scala object MyProgram { val engine = new FeelEngine def feel(expression: String, context: Map[String, Any]) { val result: Either[Failure, Boolean] = engine.evalUnaryTests(expression, context) // or val result: Either[Failure, Any] = engine.evalExpression(expression, context) // handle result result .right.map(value => println(s"result is: $value")) .left.map(failure => println(s"failure: $failure")) } } ``` -------------------------------- ### Live FEEL Challenge: Select Route Source: https://github.com/camunda/feel-scala/blob/main/docs/versioned_docs/version-1.21/learn/challenge/chapter-6.mdx Use FEEL list operators to select the correct route from a list of options based on the destination. The initial context provides a list of routes, each with a list of stops. ```feel routes ``` -------------------------------- ### Add FEEL Engine Dependency Source: https://github.com/camunda/feel-scala/blob/main/docs/versioned_docs/version-1.21/developer-guide/bootstrapping.md Include the FEEL engine as a dependency in your project's pom.xml file. ```xml org.camunda.feel feel-engine ${VERSION} ``` -------------------------------- ### FEEL Grammar: Intervals Source: https://github.com/camunda/feel-scala/blob/main/src/main/scala/org/camunda/feel/impl/parser/feel-grammar.md Defines the syntax for creating intervals, including open and closed start/end points, used for range comparisons. ```peg interval = ( openIntervalStart / closedIntervalStart ) endpoint ".." endpoint ( openIntervalEnd / closedIntervalEnd ) ``` ```peg openIntervalStart = "(" / "]" ``` ```peg closedIntervalStart = "[" ``` ```peg openIntervalEnd = ")" / "[" ``` ```peg closedIntervalEnd = "]" ``` -------------------------------- ### Implement a Custom FEEL Engine Clock Source: https://github.com/camunda/feel-scala/blob/main/docs/versioned_docs/version-1.21/developer-guide/feel-engine-clock-spi.md Sub-class `FeelEngineClock` and override `getCurrentTime()` to return a custom `ZonedDateTime`. This is useful when your application uses a non-system clock. ```scala class MyClock extends FeelEngineClock { override def getCurrentTime(): ZonedDateTime = { val currentMillis = ... Instant.ofEpochMilli(currentMillis).atZone(ZoneId.systemDefault()) } } ``` -------------------------------- ### JavaScript with Line Highlighting Source: https://github.com/camunda/feel-scala/blob/main/docs/cheat-sheets/markdown-cheat-sheet.md Demonstrates line highlighting within a JavaScript code block using a special syntax. ```js function highlightMe() { console.log('This line can be highlighted!'); } ``` -------------------------------- ### FEEL Grammar: Boxed Expressions (Lists, Functions, Contexts) Source: https://github.com/camunda/feel-scala/blob/main/src/main/scala/org/camunda/feel/impl/parser/feel-grammar.md Defines the syntax for boxed expressions, including lists, function definitions, and contexts (key-value pairs). ```peg boxedExpression = list / functionDefinition / context ``` ```peg list = "[" ( expression ( "," expression )* )? "]" ``` ```peg functionDefinition = "function" "(" ( formalParameter ( "," formalParameter )* )? ")" ( "external" )? expression ``` ```peg formalParameter = parameterName ``` ```peg context = "{" ( contextEntry ( "," contextEntry )* )? "}" ``` ```peg contextEntry = key ":" expression ``` ```peg key = name / stringLiteral ``` -------------------------------- ### Scala: Use FEEL as Script Engine Source: https://github.com/camunda/feel-scala/blob/main/docs/versioned_docs/version-1.21/developer-guide/bootstrapping.md Integrate the FEEL engine with Java's Script Engine API (JSR 223) by obtaining a FeelScriptEngine instance. ```scala object MyProgram { val scriptEngineManager = new ScriptEngineManager def feel(script: String, context: ScriptContext) { val scriptEngine: FeelScriptEngine = scriptEngineManager.getEngineByName("feel") val result: Object = scriptEngine.eval(script, context) // ... } } ``` -------------------------------- ### Structure Calculation with Context Expressions Source: https://github.com/camunda/feel-scala/blob/main/docs/versioned_docs/version-1.21/learn/samples/context-samples.md Employ context expressions to structure complex calculations, such as finding the minimum age from a list of birthdays. Define helper functions within the context. ```js { age: function(birthday) (today() - birthday).years, ages: for birthday in birthdays return age(birthday), minAge: min(ages) }.minAge ``` -------------------------------- ### FEEL Grammar: Type Checking and Path Expressions Source: https://github.com/camunda/feel-scala/blob/main/src/main/scala/org/camunda/feel/impl/parser/feel-grammar.md Defines syntax for checking if an expression is an instance of a specific type and for navigating through nested structures using path expressions. ```peg instanceOf = expression7 "instance" "of" type ``` ```peg type = qualifiedName ``` ```peg pathExpression = expression8 ( "." name )* ( "[" expression "]" ) ``` -------------------------------- ### Register Custom Clock via ServiceLoader Source: https://github.com/camunda/feel-scala/blob/main/docs/versioned_docs/version-1.21/developer-guide/feel-engine-clock-spi.md To register a custom clock using the Java ServiceLoader, create a file named `org.camunda.feel.FeelEngineClock` in the `META-INF/services/` directory. This file should contain the fully qualified name of your custom clock class. ```properties org.camunda.feel.example.MyClock ``` -------------------------------- ### FEEL Grammar: Logical and Comparison Operators Source: https://github.com/camunda/feel-scala/blob/main/src/main/scala/org/camunda/feel/impl/parser/feel-grammar.md Defines the grammar for logical operators (or, and) and various comparison operators including equality, inequality, range, and membership. ```peg disjunction = expression3 ( "or" expression3 )* ``` ```peg conjunction = expression4 ( "and" expression )* ``` ```peg comparison = ( expression5 ( "=" / "!=" / "<" / "<=" / ">" / ">=" ) expression5 ) / ( expression5 "between" expression "and" expression ) / ( expression5 "in" "(" positiveUnaryTests ")" ) / ( expression5 "in" positiveUnaryTest ) ``` -------------------------------- ### Register Custom Function Providers Source: https://github.com/camunda/feel-scala/blob/main/docs/versioned_docs/version-1.21/developer-guide/function-provider-spi.md Register custom function providers by listing their fully qualified names in `META-INF/services/org.camunda.feel.context.CustomFunctionProvider` for loading via Java ServiceLoader. ```properties org.camunda.feel.example.context.CustomScalaFunctionProvider org.camunda.feel.example.context.CustomJavaFunctionProvider ``` -------------------------------- ### Evaluate Unary Tests Source: https://github.com/camunda/feel-scala/blob/main/docs/versioned_docs/version-1.21/playground/repl.md Shows how to evaluate FEEL unary tests with different input types and contexts using the 'unaryTests' function. ```scala unaryTests("> 3", 5) // evaluate a unary-tests with a given input value ``` ```scala val context = Map("x" -> 3) unaryTests("> x", 5, context) // evaluate a unary-tests with a given input value and map-based context ``` ```scala unaryTests("> x", "5", "{ \"x\": 3}") // evaluate a unary-tests with a given JSON input value and JSON context ``` -------------------------------- ### FEEL Grammar: Literals and Values Source: https://github.com/camunda/feel-scala/blob/main/src/main/scala/org/camunda/feel/impl/parser/feel-grammar.md Defines various types of literals and simple values, including null, booleans, dates/times, strings, and numbers. ```peg literal = "null" / simpleLiteral ``` ```peg simpleLiteral = booleanLiteral / dateTimeLiteral / stringLiteral / numericLiteral ``` ```peg booleanLiteral = "true" / "false" ``` ```peg dateTimeLiteral = ( "date" / "time" / "date and time" / "duration" ) "(" stringLiteral ")" ``` ```peg stringLiteral = '"' ( !('"' / verticalSpace) character )* '"' ``` ```peg numericLiteral = ( "-" )? ( ( digits ( "." digits )? ) / ( "." digits ) ) ``` ```peg digits = digit ( digit )* digit = [0-9] ``` ```peg simpleValue = simpleLiteral / qualifiedName ``` -------------------------------- ### FEEL Grammar: Control Flow Expressions Source: https://github.com/camunda/feel-scala/blob/main/src/main/scala/org/camunda/feel/impl/parser/feel-grammar.md Defines FEEL syntax for control flow structures like for loops, if-then-else statements, and quantified expressions (some/every). ```peg forExpression = "for" name "in" expression ( "," name "in" expression )* "return" expression ``` ```peg ifExpression = "if" expression "then" expression "else" expression ``` ```peg quantifiedExpression = ("some" / "every") (name "in" expression)+ "satisfies" expression ``` -------------------------------- ### FEEL Grammar: Function Calls and Filtering Source: https://github.com/camunda/feel-scala/blob/main/src/main/scala/org/camunda/feel/impl/parser/feel-grammar.md Defines the grammar for invoking functions with named or positional parameters and for filtering collections using bracket notation. ```peg filterExpression = expression9 "[" expression "]" ``` ```peg functionInvocation = expression9 parameters ``` ```peg parameters = "(" namedParameters / positionalParameters ")" ``` ```peg namedParameters = parameterName ":" expression ( "," parameterName ":" expression )* ``` ```peg parameterName = name ``` ```peg positionalParameters = ( expression ( "," expression )* )? ``` -------------------------------- ### FEEL Grammar: Names and Qualifiers Source: https://github.com/camunda/feel-scala/blob/main/src/main/scala/org/camunda/feel/impl/parser/feel-grammar.md Defines the structure for names, qualified names, and additional symbols allowed in names, used for variables, functions, and types. ```peg qualifiedName = name ( "." name )* ``` ```peg name = nameStart ( namePart / additionalNameSymbols )* ``` ```peg nameStart = nameStartChar ( namePartChar )* ``` ```peg namePart = ( namePartChar )+ ``` ```peg nameStartChar = "?" / [A-Z] / "_" / [a-z] / [\uC0-\uD6] / [\uD8-\uF6] / [\uF8-\u2FF] / [\u370-\u37D] / [\u37F-\u1FFF] / [\u200C-\u200D] / [\u2070-\u218F] / [\u2C00-\u2FEF] / [\u3001-\uD7FF] / [\uF900-\uFDCF] / [\uFDF0-\uFFFD] / [\u10000-\uEFFFF] ``` ```peg namePartChar = nameStartChar / digit / [\uB7] / [\u0300-\u036F] / [\u203F-\u2040] ``` ```peg additionalNameSymbols = "." / "/" / "-" / "’" / "+" / "*" ``` -------------------------------- ### Create Unix Timestamp Source: https://github.com/camunda/feel-scala/blob/main/docs/versioned_docs/version-1.21/learn/samples/temporal-samples.md Return the current point in time as a Unix timestamp in milliseconds. ```js (now() - date and time("1970-01-01T00:00Z")) / duration("PT1S") * 1000 ``` ```js 1618200039000 ``` -------------------------------- ### Test Built-in Function - Basic Source: https://github.com/camunda/feel-scala/blob/main/CONTRIBUTING.md A basic test case for the 'reverse' built-in function, asserting that it returns a string in reverse order. ```scala "A reverse() function" should "return a string in reverse order" in { reverse("adnumac") should be (ValString("camunda")) } ``` -------------------------------- ### Calculate Duration to Next Tuesday 08:00 Source: https://github.com/camunda/feel-scala/blob/main/docs/versioned_docs/version-1.21/learn/samples/temporal-samples.md Return the duration between now and the next Tuesday at 08:00. ```js (for x in 1..7 return date and time(today(),time("08:00:00Z")) + duration("P"+string(x)+"D") )[day of week(item) = "Tuesday"][1] - now() ``` -------------------------------- ### Implement Custom Scala Function Provider Source: https://github.com/camunda/feel-scala/blob/main/docs/versioned_docs/version-1.21/developer-guide/function-provider-spi.md Extend `CustomFunctionProvider` and implement `getFunction` or `getFunctions` to define custom functions. The `ValFunction` includes parameter definitions and the invocation logic. ```scala class CustomScalaFunctionProvider extends CustomFunctionProvider { def getFunction(name: String): Option[ValFunction] = functions.get(name) def functionNames: Iterable[String] = functions.keys val functions: Map[String, ValFunction] = Map( "incr" -> ValFunction( params = List("x"), invoke = { case List(ValNumber(x)) => ValNumber(x + 1) } ) ) } ``` -------------------------------- ### Format List of Dates Source: https://github.com/camunda/feel-scala/blob/main/docs/versioned_docs/version-1.21/learn/samples/temporal-samples.md Transform a given list of date-time values into a custom 'day-Month-year' format. ```js for d in dates return { date: date(date and time(d)), day: string(date.day), month: substring(month of year(date), 1, 3), year: string(date.year), formatted: day + "-" + month + "-" + year }.formatted ``` ```js ["21-Apr-2021","22-Apr-2021"] ``` -------------------------------- ### FEEL Grammar: Arithmetic Expressions Source: https://github.com/camunda/feel-scala/blob/main/src/main/scala/org/camunda/feel/impl/parser/feel-grammar.md Defines the structure for arithmetic operations, including addition/subtraction, multiplication/division, and exponentiation, with support for unary negation. ```peg simpleExpressions = simpleExpression ( "," simple expression )* simpleExpression = arithmeticExpression / simpleValue ``` ```peg arithmeticExpression = arithmeticExpression2 ( "+" arithmeticExpression2 / "-" arithmeticExpression2 )* ``` ```peg arithmeticExpression2 = arithmeticExpression3 ( "*" arithmeticExpression3 / "/" arithmeticExpression3 )* ``` ```peg arithmeticExpression3 = arithmeticExpression4 ( "**" arithmeticExpression4 )* ``` ```peg arithmeticExpression4 = ("-")? expression6 ``` -------------------------------- ### Evaluate FEEL Expression Source: https://github.com/camunda/feel-scala/blob/main/docs/versioned_docs/version-1.21/playground/playground.mdx Use this snippet to evaluate a FEEL expression with a given context. The expression '3 + x' will be evaluated with 'x' set to 5. ```javascript 3 + x ``` -------------------------------- ### Compare Date with Offset Source: https://github.com/camunda/feel-scala/blob/main/docs/versioned_docs/version-1.21/learn/samples/temporal-samples.md Check if a date is at least 6 months before another date. ```js date1 < date2 + duration("P6M") ``` -------------------------------- ### FEEL Grammar: Core Expressions Source: https://github.com/camunda/feel-scala/blob/main/src/main/scala/org/camunda/feel/impl/parser/feel-grammar.md Defines the basic structure of FEEL expressions, including textual and boxed expressions, and their recursive breakdown into more specific types. ```peg expression = textualExpression expression10 = boxedExpression ``` ```peg textualExpressions = textualExpression ( "," textualExpression )* ``` ```peg textualExpression = functionDefinition / forExpression / ifExpression / quantifiedExpression / expression2 ``` ```peg expression2 = disjunction ``` ```peg expression3 = conjunction ``` ```peg expression4 = comparison / expression5 ``` ```peg expression5 = arithmeticExpression ``` ```peg expression6 = instanceOf / expression7 ``` ```peg expression7 = pathExpression ``` ```peg expression8 = filterExpression / functionInvocation / expression9 ``` ```peg expression9 = literal / name / simplePositiveUnaryTest / ( "(" textualExpression ")" ) / expression10 ``` -------------------------------- ### Implement Custom Java Function Provider Source: https://github.com/camunda/feel-scala/blob/main/docs/versioned_docs/version-1.21/developer-guide/function-provider-spi.md Extend `JavaFunctionProvider` to define custom functions in Java. Use `JavaFunction` for function definition, specifying parameters and the invocation logic. ```java public class CustomJavaFunctionProvider extends JavaFunctionProvider { private static final Map functions = new HashMap<>(); static { final JavaFunction function = new JavaFunction(Arrays.asList("x"), args -> { final ValNumber arg = (ValNumber) args.get(0); int x = arg.value().intValue(); return new ValNumber(BigDecimal.valueOf(x - 1)); }); functions.put("decr", function); } @Override public Optional resolveFunction(String functionName) { return Optional.ofNullable(functions.get(functionName)); } @Override public Collection getFunctionNames() { return functions.keySet(); } } ``` -------------------------------- ### Register Value Mapper via ServiceLoader Source: https://github.com/camunda/feel-scala/blob/main/docs/versioned_docs/version-1.21/developer-guide/value-mapper-spi.md To register a custom value mapper using the Java ServiceLoader mechanism, create a file named `org.camunda.feel.valuemapper.CustomValueMapper` within the `META-INF/services/` directory. This file should contain the fully qualified name of your custom value mapper class. ```properties org.camunda.feel.example.valuemapper.MyValueMapper ``` -------------------------------- ### Calculate Duration to Next Specific Time in Timezone Source: https://github.com/camunda/feel-scala/blob/main/docs/versioned_docs/version-1.21/learn/samples/temporal-samples.md Return the duration between now and the next time it is 09:00 in the Europe/Berlin timezone. ```js { time: time("09:00:00@Europe/Berlin"), date: if (time(now()) < time) then today() else today() + duration("P1D"), duration: date and time(date, time) - now() }.duration ``` -------------------------------- ### Evaluate FEEL Unary Tests Source: https://github.com/camunda/feel-scala/blob/main/docs/versioned_docs/version-1.21/playground/playground.mdx Use this snippet to evaluate FEEL unary tests against an input value and context. The test '< x' will be evaluated with input '3' and 'x' set to 5. ```javascript < x ``` -------------------------------- ### Calculate Total Trip Time with Rest Source: https://github.com/camunda/feel-scala/blob/main/docs/versioned_docs/version-1.21/learn/challenge/chapter-1.mdx Use this snippet to calculate the total time for a trip, incorporating rest periods. It requires variables for distance, speed, rest duration, and rest interval. ```FEEL // change formula considering resting time plus total time round up(distance / speed, 0) ``` ```FEEL round up(restInHrs * (distance / speed) / restInterval + distance / speed, 0) ``` -------------------------------- ### Calculate Next Weekday at Midnight Source: https://github.com/camunda/feel-scala/blob/main/docs/versioned_docs/version-1.21/learn/samples/temporal-samples.md Return the next day that is not a weekend, occurring at midnight. ```js (for x in 1..3 return date and time(today(),time("00:00:00Z")) + duration("P"+string(x)+"D") )[not(day of week(item) in ("Saturday","Sunday"))][1] ``` -------------------------------- ### FEEL Grammar: Unary Tests Source: https://github.com/camunda/feel-scala/blob/main/src/main/scala/org/camunda/feel/impl/parser/feel-grammar.md Defines the structure for unary tests, including negation and positive unary tests, which are used in comparisons and filtering. ```peg unaryTests = "-" / ( "not" "(" positiveUnaryTests ")" ) / positiveUnaryTests ``` ```peg positiveUnaryTests = positiveUnaryTest ( "," positiveUnaryTest )* ``` ```peg positiveUnaryTest = "null" / simplePositiveUnaryTest ``` ```peg simpleUnaryTests = "-" / ( "not" "(" simplePositiveUnaryTests ")" ) / simplePositiveUnaryTests ``` ```peg simplePositiveUnaryTests = simplePositiveUnaryTest ( "," simplePositiveUnaryTest )* ``` ```peg simplePositiveUnaryTest = ( ( "<" / "<=" / ">" / ">=" )? endpoint ) / interval ``` ```peg endpoint = simpleValue ``` -------------------------------- ### Exponentiation for Repeated Multiplication Source: https://github.com/camunda/feel-scala/blob/main/docs/versioned_docs/version-1.21/learn/challenge/chapter-2.mdx Use exponentiation to represent repeated multiplications, such as calculating the number of heads on Lerna's Hydra after a certain number of cuts. This is useful for simplifying expressions involving powers. ```feel // use exponentiation to represent the multiplications 2*2*2*2*2 ``` ```feel base ** exponent ``` -------------------------------- ### Concatenate First and Last Name in FEEL Source: https://github.com/camunda/feel-scala/blob/main/docs/versioned_docs/version-1.21/learn/challenge/chapter-4.mdx Use this expression to combine the 'firstName' and 'lastName' variables with a space in between. This is useful for generating full names from separate components. ```feel firstName + " " + lastName ``` -------------------------------- ### Test Built-in Function - Error Handling Source: https://github.com/camunda/feel-scala/blob/main/CONTRIBUTING.md Test case to verify error handling for the 'reverse' function when the argument is not a string, expecting a specific failure report. ```scala reverse(value = 123) should (reportFailure(FUNCTION_INVOCATION_FAILURE, "Failed to invoke function 'reverse': argument 'value' is of type 'number' but expected 'string'")) ``` -------------------------------- ### Add Nullish Coalescing Operator Parsing Source: https://github.com/camunda/feel-scala/blob/main/CONTRIBUTING.md Extend the FEEL parser in `FeelParser.scala` to recognize and parse the nullish coalescing operator (`??`). This involves defining a new parser rule and integrating it into the existing expression grammar. ```scala private def nullishCoalesching[_: P](value: Exp): P[Exp] = ??? P("??" ~ expLvl4) .map { NullishCoalescing(value, _) } ``` ```scala | nullishCoalesching(value) ``` -------------------------------- ### Test Built-in Function - Null Argument Source: https://github.com/camunda/feel-scala/blob/main/CONTRIBUTING.md Test case for the 'reverse' function when the argument is null, expecting a null result. ```scala reverse(value = null) should be (ValNull) ``` -------------------------------- ### Calculate Age from Birthday Source: https://github.com/camunda/feel-scala/blob/main/docs/versioned_docs/version-1.21/learn/samples/temporal-samples.md Return the current age of a person based on a given birthday. ```js years and months duration(date(birthday), today()).years ``` -------------------------------- ### Test Built-in Function - Named Arguments Source: https://github.com/camunda/feel-scala/blob/main/CONTRIBUTING.md Test case for invoking the 'reverse' function using named arguments. ```scala reverse(value = "adnumac") should be (ValString("camunda")) ``` -------------------------------- ### Group List by Person Source: https://github.com/camunda/feel-scala/blob/main/docs/versioned_docs/version-1.21/learn/samples/list-samples.md Groups a list of invoices by the 'person' attribute. This is useful for aggregating data based on a common key. The input must be a JSON object containing an 'invoices' array. ```js for p in distinct values(invoices.person) return invoices[person = p] ``` ```json {"invoices":[ {"id":1, "person":"A", "amount": 10}, {"id":2, "person":"A", "amount": 20}, {"id":3, "person":"A", "amount": 30}, {"id":4, "person":"A", "amount": 40}, {"id":5, "person":"B", "amount": 15}, {"id":6, "person":"B", "amount": 25} ]} ``` ```json [ [ {"id":1, "person":"A", "amount": 10}, {"id":2, "person":"A", "amount": 20}, {"id":3, "person":"A", "amount": 30}, {"id":4, "person":"A", "amount": 40} ], [ {"id":5, "person":"B", "amount": 15}, {"id":6, "person":"B", "amount": 25} ] ] ``` -------------------------------- ### FEEL Solution: Find Berlin Route Source: https://github.com/camunda/feel-scala/blob/main/docs/versioned_docs/version-1.21/learn/challenge/chapter-6.mdx This FEEL expression filters the routes to find the one that includes 'Berlin' in its stops and then selects the 'route' property of the matching route. It assumes 'Berlin' is a unique destination among the routes. ```feel routes["Berlin" in stops][1].route ``` -------------------------------- ### Define NullishCoalescing Expression Type Source: https://github.com/camunda/feel-scala/blob/main/CONTRIBUTING.md Add a new case class `NullishCoalescing` to `Exp.scala` to represent the nullish coalescing operator in the FEEL abstract syntax tree (AST). ```scala case class NullishCoalescing(value: Exp, alternative: Exp) extends Exp ``` -------------------------------- ### Validate Data with Context Expressions Source: https://github.com/camunda/feel-scala/blob/main/docs/versioned_docs/version-1.21/learn/samples/context-samples.md Use context expressions to define validation rules and aggregate violations. This snippet checks journal entries against specific criteria. ```js { check1: { error: "Document Type invalid for current year posting", violations: collection[documentType = "S2" and glDate > startFiscalYear] }, check2: { error: "Document Type invalid for current year posting", violations: collection[ledgerType = "GP" and foreignAmount != null] }, result: ([check1, check2])[count(violations) > 0] } ``` -------------------------------- ### Adjust List Access in FEEL Evaluation Source: https://github.com/camunda/feel-scala/blob/main/CONTRIBUTING.md Modify the list access behavior in `FeelInterpreter.scala` to use zero-based indexing. This change affects how elements are retrieved from lists within FEEL expressions. ```scala private def filterList(list: List[Val], index: Number) ``` -------------------------------- ### Plain Text Code Block Source: https://github.com/camunda/feel-scala/blob/main/docs/cheat-sheets/markdown-cheat-sheet.md A code block without specified language, useful for plain text or mixed content. ```plaintext No language indicated, so no syntax highlighting. But let's throw in a tag. ``` -------------------------------- ### Add Test Case for Nullish Coalescing Operator Source: https://github.com/camunda/feel-scala/blob/main/CONTRIBUTING.md Write new test cases in `InterpreterBooleanExpressionTest.scala` to verify the correct behavior of the nullish coalescing operator. Ensure tests cover scenarios where the value is null and not null. ```scala "A nullish coalescing operator" should "return the value if the given value is not null" in { ??? } ``` ```scala it should "return the alternative if the given value is null" in { ??? } ``` -------------------------------- ### Implement Nullish Coalescing Operator Evaluation Source: https://github.com/camunda/feel-scala/blob/main/CONTRIBUTING.md Handle the evaluation of the nullish coalescing operator in `FeelInterpreter.scala`. This involves adding a new case to the `eval` method to correctly return either the original value or the alternative. ```scala case NullishCoalescing(value, alternative) => ??? // Implement the behavior and return eval(value) or eval(alternative) ``` -------------------------------- ### Test Built-in Function - Error Result Source: https://github.com/camunda/feel-scala/blob/main/CONTRIBUTING.md Test case to verify that the 'reverse' function correctly reports an error when an internal error occurs during invocation. ```scala reverse(value = "error") should (reportFailure(FUNCTION_INVOCATION_FAILURE, "Failed to invoke function 'reverse': something went wrong")) ``` -------------------------------- ### Check if Current Day is Weekend Source: https://github.com/camunda/feel-scala/blob/main/docs/versioned_docs/version-1.21/learn/samples/temporal-samples.md Check if the current day is on a weekend (Saturday or Sunday). ```js day of week(today()) in ("Saturday","Sunday") ``` -------------------------------- ### Merge Two Lists by ID Source: https://github.com/camunda/feel-scala/blob/main/docs/versioned_docs/version-1.21/learn/samples/list-samples.md Merges two lists of objects, each containing an 'id' field. It combines elements with the same 'id', prioritizing values from the second list ('y') in case of conflicts. The input must be a JSON object with 'x' and 'y' properties, each containing a 'files' array. ```js { ids: union(x.files.id,y.files.id), getById: function (files,fileId) if (count(files[id=fileId]) > 0) then files[id=fileId][1] else {}, merge: for id in ids return put all(getById(x.files, id), getById(y.files, id)) }.merge ``` ```json { "x": {"files": [ {"id":1, "content":"a"}, {"id":2, "content":"b"} ]}, "y": {"files": [ {"id":1, "content":"a2"}, {"id":3, "content":"c"} ]} } ``` ```json [ {"id":1, "content":"a2"}, {"id":2, "content":"b"}, {"id":3, "content":"c"} ] ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.